Commit aedcae64 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/davem/BK/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 8309fa38 71f55998
...@@ -109,6 +109,9 @@ It's a good idea to avoid using lots of macros and use inlined functions ...@@ -109,6 +109,9 @@ It's a good idea to avoid using lots of macros and use inlined functions
instead, as gcc does a good job with inlining, while excessive use of instead, as gcc does a good job with inlining, while excessive use of
macros can cause compilation problems on some platforms. macros can cause compilation problems on some platforms.
Also check the TODO list at the web site listed below to see what people
might already be working on.
BUGS BUGS
......
...@@ -413,6 +413,15 @@ L: dev-etrax@axis.com ...@@ -413,6 +413,15 @@ L: dev-etrax@axis.com
W: http://developer.axis.com W: http://developer.axis.com
S: Maintained S: Maintained
CRYPTO API
P: James Morris
M: jmorris@intercode.com.au
P: David S. Miller
M: davem@redhat.com
W http://samba.org/~jamesm/crypto/
L: linux-kernel@vger.kernel.org
S: Maintained
CYBERPRO FB DRIVER CYBERPRO FB DRIVER
P: Russell King P: Russell King
M: rmk@arm.linux.org.uk M: rmk@arm.linux.org.uk
......
...@@ -74,19 +74,39 @@ static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) ...@@ -74,19 +74,39 @@ static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
return -EINVAL; return -EINVAL;
} }
static void crypto_init_ops(struct crypto_tfm *tfm) static int crypto_init_ops(struct crypto_tfm *tfm)
{ {
switch (crypto_tfm_alg_type(tfm)) { switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER: case CRYPTO_ALG_TYPE_CIPHER:
crypto_init_cipher_ops(tfm); return crypto_init_cipher_ops(tfm);
case CRYPTO_ALG_TYPE_DIGEST:
return crypto_init_digest_ops(tfm);
case CRYPTO_ALG_TYPE_COMP:
return crypto_init_compress_ops(tfm);
default:
break;
}
BUG();
return -EINVAL;
}
static void crypto_exit_ops(struct crypto_tfm *tfm)
{
switch (crypto_tfm_alg_type(tfm)) {
case CRYPTO_ALG_TYPE_CIPHER:
crypto_exit_cipher_ops(tfm);
break; break;
case CRYPTO_ALG_TYPE_DIGEST: case CRYPTO_ALG_TYPE_DIGEST:
crypto_init_digest_ops(tfm); crypto_exit_digest_ops(tfm);
break; break;
case CRYPTO_ALG_TYPE_COMP: case CRYPTO_ALG_TYPE_COMP:
crypto_init_compress_ops(tfm); crypto_exit_compress_ops(tfm);
break; break;
default: default:
...@@ -110,6 +130,8 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ...@@ -110,6 +130,8 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
memset(tfm, 0, sizeof(*tfm)); memset(tfm, 0, sizeof(*tfm));
memset(tfm, 0, sizeof(*tfm));
if (alg->cra_ctxsize) { if (alg->cra_ctxsize) {
tfm->crt_ctx = kmalloc(alg->cra_ctxsize, GFP_KERNEL); tfm->crt_ctx = kmalloc(alg->cra_ctxsize, GFP_KERNEL);
if (tfm->crt_ctx == NULL) if (tfm->crt_ctx == NULL)
...@@ -128,8 +150,11 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ...@@ -128,8 +150,11 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
if (crypto_init_flags(tfm, flags)) if (crypto_init_flags(tfm, flags))
goto out_free_work_block; goto out_free_work_block;
crypto_init_ops(tfm); if (crypto_init_ops(tfm)) {
crypto_exit_ops(tfm);
goto out_free_ctx;
}
goto out; goto out;
out_free_work_block: out_free_work_block:
......
...@@ -234,27 +234,19 @@ static int nocrypt(struct crypto_tfm *tfm, ...@@ -234,27 +234,19 @@ static int nocrypt(struct crypto_tfm *tfm,
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags)
{ {
struct crypto_alg *alg = tfm->__crt_alg;
u32 mode = flags & CRYPTO_TFM_MODE_MASK; u32 mode = flags & CRYPTO_TFM_MODE_MASK;
tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB;
if (alg->cra_cipher.cia_ivsize && mode != CRYPTO_TFM_MODE_ECB) {
tfm->crt_cipher.cit_iv =
kmalloc(alg->cra_cipher.cia_ivsize, GFP_KERNEL);
if (tfm->crt_cipher.cit_iv == NULL)
return -ENOMEM;
} else
tfm->crt_cipher.cit_iv = NULL;
if (flags & CRYPTO_TFM_REQ_WEAK_KEY) if (flags & CRYPTO_TFM_REQ_WEAK_KEY)
tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY; tfm->crt_flags = CRYPTO_TFM_REQ_WEAK_KEY;
return 0; return 0;
} }
void crypto_init_cipher_ops(struct crypto_tfm *tfm) int crypto_init_cipher_ops(struct crypto_tfm *tfm)
{ {
int ret = 0;
struct crypto_alg *alg = tfm->__crt_alg;
struct cipher_tfm *ops = &tfm->crt_cipher; struct cipher_tfm *ops = &tfm->crt_cipher;
ops->cit_setkey = setkey; ops->cit_setkey = setkey;
...@@ -283,4 +275,20 @@ void crypto_init_cipher_ops(struct crypto_tfm *tfm) ...@@ -283,4 +275,20 @@ void crypto_init_cipher_ops(struct crypto_tfm *tfm)
default: default:
BUG(); BUG();
} }
if (alg->cra_cipher.cia_ivsize &&
ops->cit_mode != CRYPTO_TFM_MODE_ECB) {
ops->cit_iv = kmalloc(alg->cra_cipher.cia_ivsize, GFP_KERNEL);
if (ops->cit_iv == NULL)
ret = -ENOMEM;
}
return ret;
}
void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
{
if (tfm->crt_cipher.cit_iv)
kfree(tfm->crt_cipher.cit_iv);
} }
...@@ -33,10 +33,14 @@ int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) ...@@ -33,10 +33,14 @@ int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags)
return crypto_cipher_flags(flags) ? -EINVAL : 0; return crypto_cipher_flags(flags) ? -EINVAL : 0;
} }
void crypto_init_compress_ops(struct crypto_tfm *tfm) int crypto_init_compress_ops(struct crypto_tfm *tfm)
{ {
struct compress_tfm *ops = &tfm->crt_compress; struct compress_tfm *ops = &tfm->crt_compress;
ops->cot_compress = crypto_compress; ops->cot_compress = crypto_compress;
ops->cot_decompress = crypto_decompress; ops->cot_decompress = crypto_decompress;
return 0;
} }
void crypto_exit_compress_ops(struct crypto_tfm *tfm)
{ }
...@@ -63,12 +63,19 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) ...@@ -63,12 +63,19 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
return crypto_cipher_flags(flags) ? -EINVAL : 0; return crypto_cipher_flags(flags) ? -EINVAL : 0;
} }
void crypto_init_digest_ops(struct crypto_tfm *tfm) int crypto_init_digest_ops(struct crypto_tfm *tfm)
{ {
struct digest_tfm *ops = &tfm->crt_digest; struct digest_tfm *ops = &tfm->crt_digest;
ops->dit_init = init; ops->dit_init = init;
ops->dit_update = update; ops->dit_update = update;
ops->dit_final = final; ops->dit_final = final;
ops->dit_digest = digest; ops->dit_digest = digest;
return crypto_alloc_hmac_block(tfm);
}
void crypto_exit_digest_ops(struct crypto_tfm *tfm)
{
crypto_free_hmac_block(tfm);
} }
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/slab.h>
#include <asm/scatterlist.h> #include <asm/scatterlist.h>
#include "internal.h" #include "internal.h"
...@@ -31,18 +32,39 @@ static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen) ...@@ -31,18 +32,39 @@ static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
} }
int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
{
int ret = 0;
BUG_ON(!crypto_tfm_alg_blocksize(tfm));
tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
GFP_KERNEL);
if (tfm->crt_digest.dit_hmac_block == NULL)
ret = -ENOMEM;
return ret;
}
void crypto_free_hmac_block(struct crypto_tfm *tfm)
{
if (tfm->crt_digest.dit_hmac_block)
kfree(tfm->crt_digest.dit_hmac_block);
}
void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen) void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
{ {
unsigned int i; unsigned int i;
struct scatterlist tmp; struct scatterlist tmp;
char *ipad = tfm->crt_work_block; char *ipad = tfm->crt_digest.dit_hmac_block;
if (*keylen > crypto_tfm_alg_blocksize(tfm)) { if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen); hash_key(tfm, key, *keylen);
*keylen = crypto_tfm_alg_digestsize(tfm); *keylen = crypto_tfm_alg_digestsize(tfm);
} }
memset(ipad, 0, crypto_tfm_alg_blocksize(tfm) + 1); memset(ipad, 0, crypto_tfm_alg_blocksize(tfm));
memcpy(ipad, key, *keylen); memcpy(ipad, key, *keylen);
for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
...@@ -67,8 +89,8 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ...@@ -67,8 +89,8 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
{ {
unsigned int i; unsigned int i;
struct scatterlist tmp; struct scatterlist tmp;
char *opad = tfm->crt_work_block; char *opad = tfm->crt_digest.dit_hmac_block;
if (*keylen > crypto_tfm_alg_blocksize(tfm)) { if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen); hash_key(tfm, key, *keylen);
*keylen = crypto_tfm_alg_digestsize(tfm); *keylen = crypto_tfm_alg_digestsize(tfm);
...@@ -76,7 +98,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ...@@ -76,7 +98,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
crypto_digest_final(tfm, out); crypto_digest_final(tfm, out);
memset(opad, 0, crypto_tfm_alg_blocksize(tfm) + 1); memset(opad, 0, crypto_tfm_alg_blocksize(tfm));
memcpy(opad, key, *keylen); memcpy(opad, key, *keylen);
for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
......
...@@ -52,13 +52,30 @@ static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) ...@@ -52,13 +52,30 @@ static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
} }
#endif #endif
#ifdef CONFIG_CRYPTO_HMAC
int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
void crypto_free_hmac_block(struct crypto_tfm *tfm);
#else
static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
{
return 0;
}
static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
{ }
#endif
int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
void crypto_init_digest_ops(struct crypto_tfm *tfm); int crypto_init_digest_ops(struct crypto_tfm *tfm);
void crypto_init_cipher_ops(struct crypto_tfm *tfm); int crypto_init_cipher_ops(struct crypto_tfm *tfm);
void crypto_init_compress_ops(struct crypto_tfm *tfm); int crypto_init_compress_ops(struct crypto_tfm *tfm);
void crypto_exit_digest_ops(struct crypto_tfm *tfm);
void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
void crypto_exit_compress_ops(struct crypto_tfm *tfm);
#endif /* _CRYPTO_INTERNAL_H */ #endif /* _CRYPTO_INTERNAL_H */
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
# Token Ring driver configuration # Token Ring driver configuration
# #
menu "Token Ring devices" menu "Token Ring devices (depends on LLC=y)"
depends on NETDEVICES depends on NETDEVICES
# So far, we only have PCI, ISA, and MCA token ring devices # So far, we only have PCI, ISA, and MCA token ring devices
config TR config TR
bool "Token Ring driver support" bool "Token Ring driver support"
depends on PCI || ISA || MCA depends on (PCI || ISA || MCA) && LLC=y
help help
Token Ring is IBM's way of communication on a local network; the Token Ring is IBM's way of communication on a local network; the
rest of the world uses Ethernet. To participate on a Token Ring rest of the world uses Ethernet. To participate on a Token Ring
......
...@@ -144,6 +144,9 @@ struct digest_tfm { ...@@ -144,6 +144,9 @@ struct digest_tfm {
void (*dit_final)(struct crypto_tfm *tfm, u8 *out); void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg, void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg, u8 *out); unsigned int nsg, u8 *out);
#ifdef CONFIG_CRYPTO_HMAC
void *dit_hmac_block;
#endif
}; };
struct compress_tfm { struct compress_tfm {
...@@ -196,12 +199,7 @@ static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) ...@@ -196,12 +199,7 @@ static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm)
static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm) static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm)
{ {
struct crypto_alg *alg = tfm->__crt_alg; return module_name(tfm->__crt_alg->cra_module);
if (alg->cra_module)
return alg->cra_module->name;
else
return NULL;
} }
static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm)
......
...@@ -110,8 +110,8 @@ extern int init_netlink(void); ...@@ -110,8 +110,8 @@ extern int init_netlink(void);
extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)); extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock); extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
extern void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid, extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
__u32 group, int allocation); __u32 group, int allocation);
extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code); extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
extern int netlink_register_notifier(struct notifier_block *nb); extern int netlink_register_notifier(struct notifier_block *nb);
extern int netlink_unregister_notifier(struct notifier_block *nb); extern int netlink_unregister_notifier(struct notifier_block *nb);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* *
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -72,6 +73,7 @@ typedef enum { ...@@ -72,6 +73,7 @@ typedef enum {
SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ SCTP_CMD_STRIKE, /* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_UPDATE, /* Update the heartbeat timers. */
SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */ SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */ SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */
SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */ SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */
...@@ -83,6 +85,7 @@ typedef enum { ...@@ -83,6 +85,7 @@ typedef enum {
SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ SCTP_CMD_UPDATE_ASSOC, /* Update association information. */
SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* The base lksctp header. * The base lksctp header.
* *
* 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 * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Xingang Guo <xingang.guo@intel.com> * Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -52,10 +52,10 @@ ...@@ -52,10 +52,10 @@
* structs * structs
* prototypes * prototypes
* macros, externs, and inlines * macros, externs, and inlines
* *
* Move test_frame specific items out of the kernel headers * Move test_frame specific items out of the kernel headers
* and into the test frame headers. This is not perfect in any sense * and into the test frame headers. This is not perfect in any sense
* and will continue to evolve. * and will continue to evolve.
*/ */
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
#endif #endif
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -105,19 +105,19 @@ ...@@ -105,19 +105,19 @@
#endif #endif
/* Certain internal static functions need to be exported when /* Certain internal static functions need to be exported when
* compiled into the test frame. * compiled into the test frame.
*/ */
#ifndef SCTP_STATIC #ifndef SCTP_STATIC
#define SCTP_STATIC static #define SCTP_STATIC static
#endif #endif
/* /*
* Function declarations. * Function declarations.
*/ */
/* /*
* sctp_protocol.c * sctp_protocol.c
*/ */
extern sctp_protocol_t sctp_proto; extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
...@@ -142,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); ...@@ -142,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg);
extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); extern int sctp_primitive_ABORT(sctp_association_t *, void *arg);
extern int sctp_primitive_SEND(sctp_association_t *, void *arg); extern int sctp_primitive_SEND(sctp_association_t *, void *arg);
extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/* /*
* sctp_crc32c.c * sctp_crc32c.c
...@@ -418,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) ...@@ -418,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return retval; return retval;
} }
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
* there is room for a param header too.
*/
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
/* Round an int up to the next multiple of 4. */ /* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3) #define WORD_ROUND(s) (((s)+3)&~3)
...@@ -460,6 +473,26 @@ static inline sctp_protocol_t *sctp_get_protocol(void) ...@@ -460,6 +473,26 @@ static inline sctp_protocol_t *sctp_get_protocol(void)
return &sctp_proto; return &sctp_proto;
} }
/* Convert from an IP version number to an Address Family symbol. */
static inline int ipver2af(__u8 ipver)
{
int family;
switch (ipver) {
case 4:
family = AF_INET;
break;
case 6:
family = AF_INET6;
break;
default:
family = 0;
break;
};
return family;
}
/* Warning: The following hash functions assume a power of two 'size'. */ /* Warning: The following hash functions assume a power of two 'size'. */
/* This is the hash function for the SCTP port hash table. */ /* This is the hash function for the SCTP port hash table. */
static inline int sctp_phashfn(__u16 lport) static inline int sctp_phashfn(__u16 lport)
......
...@@ -156,6 +156,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort; ...@@ -156,6 +156,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_closed;
sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_error_shutdown;
sctp_state_fn_t sctp_sf_ignore_primitive; sctp_state_fn_t sctp_sf_ignore_primitive;
sctp_state_fn_t sctp_sf_do_prm_requestheartbeat;
/* Prototypes for other event state functions. */ /* Prototypes for other event state functions. */
sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
...@@ -205,9 +206,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, ...@@ -205,9 +206,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *,
sctp_chunk_t *, sctp_chunk_t *,
const int priority); const int priority);
__u32 sctp_generate_verification_tag(void); __u32 sctp_generate_verification_tag(void);
sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *,
const int priority, int *addrs_len);
void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
/* Prototypes for chunk-building functions. */ /* Prototypes for chunk-building functions. */
...@@ -333,10 +331,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *); ...@@ -333,10 +331,10 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *);
__u32 sctp_generate_tsn(const sctp_endpoint_t *); __u32 sctp_generate_tsn(const sctp_endpoint_t *);
/* 4th level prototypes */ /* 4th level prototypes */
void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *, void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *,
__u16 port); __u16 port);
int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *);
int sockaddr2sctp_addr(const sockaddr_storage_t *, sctp_addr_param_t *); int sockaddr2sctp_addr(const union sctp_addr *, sctp_addr_param_t *);
/* Extern declarations for major data structures. */ /* Extern declarations for major data structures. */
sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
......
...@@ -2,35 +2,35 @@ ...@@ -2,35 +2,35 @@
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of 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 * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email addresses: * email addresses:
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* Randall Stewart <randall@sctp.chicago.il.us> * Randall Stewart <randall@sctp.chicago.il.us>
* Ken Morneau <kmorneau@cisco.com> * Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com> * Qiaobing Xie <qxie1@email.mot.com>
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -95,11 +95,11 @@ struct sockaddr_storage { ...@@ -95,11 +95,11 @@ struct sockaddr_storage {
/* A convenience structure for handling sockaddr structures. /* A convenience structure for handling sockaddr structures.
* We should wean ourselves off this. * We should wean ourselves off this.
*/ */
typedef union { union sctp_addr {
struct sockaddr_in v4; struct sockaddr_in v4;
struct sockaddr_in6 v6; struct sockaddr_in6 v6;
struct sockaddr sa; struct sockaddr sa;
} sockaddr_storage_t; };
/* Forward declarations for data structures. */ /* Forward declarations for data structures. */
...@@ -246,29 +246,47 @@ typedef struct sctp_func { ...@@ -246,29 +246,47 @@ typedef struct sctp_func {
int optname, int optname,
char *optval, char *optval,
int *optlen); int *optlen);
struct dst_entry *(*get_dst) (sockaddr_storage_t *daddr, struct dst_entry *(*get_dst) (union sctp_addr *daddr,
sockaddr_storage_t *saddr); union sctp_addr *saddr);
int (*cmp_saddr) (struct dst_entry *dst, void (*copy_addrlist) (struct list_head *,
sockaddr_storage_t *saddr); struct net_device *);
__u16 net_header_len; void (*dst_saddr) (union sctp_addr *saddr,
struct dst_entry *dst);
int (*cmp_addr) (const union sctp_addr *addr1,
const union sctp_addr *addr2);
void (*addr_copy) (union sctp_addr *dst,
union sctp_addr *src);
void (*from_skb) (union sctp_addr *,
struct sk_buff *skb,
int saddr);
int (*addr_valid) (union sctp_addr *);
sctp_scope_t (*scope) (union sctp_addr *);
void (*inaddr_any) (union sctp_addr *, unsigned short);
int (*is_any) (const union sctp_addr *);
__u16 net_header_len;
int sockaddr_len; int sockaddr_len;
sa_family_t sa_family; sa_family_t sa_family;
struct list_head list; struct list_head list;
} sctp_func_t; } sctp_func_t;
sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); sctp_func_t *sctp_get_af_specific(sa_family_t);
/* Protocol family functions. */ /* Protocol family functions. */
typedef struct sctp_pf { typedef struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *); void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
void (*skb_msgname)(struct sk_buff *, char *, int *); void (*skb_msgname)(struct sk_buff *, char *, int *);
int (*af_supported)(sa_family_t);
int (*cmp_addr) (const union sctp_addr *,
const union sctp_addr *,
struct sctp_opt *);
struct sctp_func *af;
} sctp_pf_t; } sctp_pf_t;
/* SCTP Socket type: UDP or TCP style. */ /* SCTP Socket type: UDP or TCP style. */
typedef enum { typedef enum {
SCTP_SOCKET_UDP = 0, SCTP_SOCKET_UDP = 0,
SCTP_SOCKET_UDP_HIGH_BANDWIDTH, SCTP_SOCKET_UDP_HIGH_BANDWIDTH,
SCTP_SOCKET_TCP SCTP_SOCKET_TCP
} sctp_socket_type_t; } sctp_socket_type_t;
/* Per socket SCTP information. */ /* Per socket SCTP information. */
...@@ -339,7 +357,7 @@ typedef struct sctp_cookie { ...@@ -339,7 +357,7 @@ typedef struct sctp_cookie {
__u32 initial_tsn; __u32 initial_tsn;
/* This holds the originating address of the INIT packet. */ /* This holds the originating address of the INIT packet. */
sockaddr_storage_t peer_addr; union sctp_addr peer_addr;
/* This is a shim for my peer's INIT packet, followed by /* This is a shim for my peer's INIT packet, followed by
* a copy of the raw address list of the association. * a copy of the raw address list of the association.
...@@ -359,20 +377,6 @@ typedef struct sctp_signed_cookie { ...@@ -359,20 +377,6 @@ typedef struct sctp_signed_cookie {
} sctp_signed_cookie_t; } sctp_signed_cookie_t;
/* This convenience type allows us to avoid casting when walking
* through a parameter list.
*/
typedef union {
__u8 *v;
sctp_paramhdr_t *p;
sctp_cookie_preserve_param_t *bht;
sctp_hostname_param_t *dns;
sctp_cookie_param_t *cookie;
sctp_supported_addrs_param_t *sat;
sctp_ipv4addr_param_t *v4;
sctp_ipv6addr_param_t *v6;
} sctpParam_t;
/* This is another convenience type to allocate memory for address /* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around * params for the maximum size and pass such structures around
...@@ -383,6 +387,21 @@ typedef union { ...@@ -383,6 +387,21 @@ typedef union {
sctp_ipv6addr_param_t v6; sctp_ipv6addr_param_t v6;
} sctp_addr_param_t; } sctp_addr_param_t;
/* A convenience type to allow walking through the various
* parameters and avoid casting all over the place.
*/
union sctp_params {
void *v;
sctp_paramhdr_t *p;
sctp_cookie_preserve_param_t *life;
sctp_hostname_param_t *dns;
sctp_cookie_param_t *cookie;
sctp_supported_addrs_param_t *sat;
sctp_ipv4addr_param_t *v4;
sctp_ipv6addr_param_t *v6;
sctp_addr_param_t *addr;
};
/* RFC 2960. Section 3.3.5 Heartbeat. /* RFC 2960. Section 3.3.5 Heartbeat.
* Heartbeat Information: variable length * Heartbeat Information: variable length
* The Sender-specific Heartbeat Info field should normally include * The Sender-specific Heartbeat Info field should normally include
...@@ -392,7 +411,7 @@ typedef union { ...@@ -392,7 +411,7 @@ typedef union {
*/ */
typedef struct sctp_sender_hb_info { typedef struct sctp_sender_hb_info {
sctp_paramhdr_t param_hdr; sctp_paramhdr_t param_hdr;
sockaddr_storage_t daddr; union sctp_addr daddr;
unsigned long sent_at; unsigned long sent_at;
} sctp_sender_hb_info_t __attribute__((packed)); } sctp_sender_hb_info_t __attribute__((packed));
...@@ -433,7 +452,7 @@ struct SCTP_chunk { ...@@ -433,7 +452,7 @@ struct SCTP_chunk {
*/ */
/* We point this at the FIRST TLV parameter to chunk_hdr. */ /* We point this at the FIRST TLV parameter to chunk_hdr. */
sctpParam_t param_hdr; union sctp_params param_hdr;
union { union {
__u8 *v; __u8 *v;
sctp_datahdr_t *data_hdr; sctp_datahdr_t *data_hdr;
...@@ -474,13 +493,13 @@ struct SCTP_chunk { ...@@ -474,13 +493,13 @@ struct SCTP_chunk {
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */ __u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */ __u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */ __u8 tsn_missing_report; /* Data chunk missing counter. */
/* What is the origin IP address for this chunk? */ /* What is the origin IP address for this chunk? */
sockaddr_storage_t source; union sctp_addr source;
/* Destination address for this chunk. */ /* Destination address for this chunk. */
sockaddr_storage_t dest; union sctp_addr dest;
/* For an inbound chunk, this tells us where it came from. /* For an inbound chunk, this tells us where it came from.
* For an outbound chunk, it tells us where we'd like it to * For an outbound chunk, it tells us where we'd like it to
...@@ -497,8 +516,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); ...@@ -497,8 +516,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data);
sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *,
struct sock *); struct sock *);
void sctp_init_addrs(sctp_chunk_t *chunk); void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *);
const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); const union sctp_addr *sctp_source(const sctp_chunk_t *chunk);
/* This is a structure for holding either an IPv6 or an IPv4 address. */ /* This is a structure for holding either an IPv6 or an IPv4 address. */
/* sin_family -- AF_INET or AF_INET6 /* sin_family -- AF_INET or AF_INET6
...@@ -507,7 +526,7 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); ...@@ -507,7 +526,7 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk);
*/ */
struct sockaddr_storage_list { struct sockaddr_storage_list {
struct list_head list; struct list_head list;
sockaddr_storage_t a; union sctp_addr a;
}; };
typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
...@@ -573,7 +592,7 @@ void sctp_packet_free(sctp_packet_t *); ...@@ -573,7 +592,7 @@ void sctp_packet_free(sctp_packet_t *);
/* This represents a remote transport address. /* This represents a remote transport address.
* For local transport addresses, we just use sockaddr_storage_t. * For local transport addresses, we just use union sctp_addr.
* *
* RFC2960 Section 1.4 Key Terms * RFC2960 Section 1.4 Key Terms
* *
...@@ -601,7 +620,7 @@ struct SCTP_transport { ...@@ -601,7 +620,7 @@ struct SCTP_transport {
int dead; int dead;
/* This is the peer's IP address and port. */ /* This is the peer's IP address and port. */
sockaddr_storage_t ipaddr; union sctp_addr ipaddr;
/* These are the functions we call to handle LLP stuff. */ /* These are the functions we call to handle LLP stuff. */
sctp_func_t *af_specific; sctp_func_t *af_specific;
...@@ -684,13 +703,15 @@ struct SCTP_transport { ...@@ -684,13 +703,15 @@ struct SCTP_transport {
*/ */
unsigned long last_time_ecne_reduced; unsigned long last_time_ecne_reduced;
/* state : The current state of this destination, /* active : The current active state of this destination,
* : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. * : i.e. DOWN, UP, etc.
*/ */
struct { int active;
int active;
int hb_allowed; /* hb_allowed : The current heartbeat state of this destination,
} state; * : i.e. ALLOW-HB, NO-HEARTBEAT, etc.
*/
int hb_allowed;
/* These are the error stats for this destination. */ /* These are the error stats for this destination. */
...@@ -739,11 +760,12 @@ struct SCTP_transport { ...@@ -739,11 +760,12 @@ struct SCTP_transport {
int malloced; /* Is this structure kfree()able? */ int malloced; /* Is this structure kfree()able? */
}; };
extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); extern sctp_transport_t *sctp_transport_new(const union sctp_addr *, int);
extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, extern sctp_transport_t *sctp_transport_init(sctp_transport_t *,
const sockaddr_storage_t *, int); const union sctp_addr *, int);
extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *);
extern void sctp_transport_route(sctp_transport_t *, sockaddr_storage_t *); extern void sctp_transport_route(sctp_transport_t *, union sctp_addr *,
struct sctp_opt *);
extern void sctp_transport_free(sctp_transport_t *); extern void sctp_transport_free(sctp_transport_t *);
extern void sctp_transport_destroy(sctp_transport_t *); extern void sctp_transport_destroy(sctp_transport_t *);
extern void sctp_transport_reset_timers(sctp_transport_t *); extern void sctp_transport_reset_timers(sctp_transport_t *);
...@@ -890,30 +912,31 @@ void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); ...@@ -890,30 +912,31 @@ void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port);
void sctp_bind_addr_free(sctp_bind_addr_t *); void sctp_bind_addr_free(sctp_bind_addr_t *);
int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
sctp_scope_t scope, int priority,int flags); sctp_scope_t scope, int priority,int flags);
int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *,
int priority); int priority);
int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *);
int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *,
sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, struct sctp_opt *);
int *addrs_len, union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
int priority); int *addrs_len,
int priority);
int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp,
__u8 *raw_addr_list, __u8 *raw_addr_list,
int addrs_len, int addrs_len,
unsigned short port, unsigned short port,
int priority); int priority);
sctp_scope_t sctp_scope(const sockaddr_storage_t *); sctp_scope_t sctp_scope(const union sctp_addr *);
int sctp_in_scope(const sockaddr_storage_t *addr, const sctp_scope_t scope); int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
int sctp_is_any(const sockaddr_storage_t *addr); int sctp_is_any(const union sctp_addr *addr);
int sctp_addr_is_valid(const sockaddr_storage_t *addr); int sctp_addr_is_valid(const union sctp_addr *addr);
/* What type of sctp_endpoint_common? */ /* What type of sctp_endpoint_common? */
typedef enum { typedef enum {
SCTP_EP_TYPE_SOCKET, SCTP_EP_TYPE_SOCKET,
SCTP_EP_TYPE_ASSOCIATION, SCTP_EP_TYPE_ASSOCIATION,
} sctp_endpoint_type_t; } sctp_endpoint_type_t;
/* /*
* A common base class to bridge the implmentation view of a * A common base class to bridge the implmentation view of a
...@@ -1048,35 +1071,25 @@ void sctp_endpoint_put(sctp_endpoint_t *); ...@@ -1048,35 +1071,25 @@ void sctp_endpoint_put(sctp_endpoint_t *);
void sctp_endpoint_hold(sctp_endpoint_t *); void sctp_endpoint_hold(sctp_endpoint_t *);
void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc);
sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **); sctp_transport_t **);
int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *);
sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
const sockaddr_storage_t *); const union sctp_addr *);
int sctp_has_association(const sockaddr_storage_t *laddr, int sctp_has_association(const union sctp_addr *laddr,
const sockaddr_storage_t *paddr); const union sctp_addr *paddr);
int sctp_verify_init(const sctp_association_t *asoc, int sctp_verify_init(const sctp_association_t *asoc,
sctp_cid_t cid, sctp_cid_t cid,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk); sctp_chunk_t **err_chunk);
int sctp_verify_param(const sctp_association_t *asoc, int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
sctpParam_t param, const union sctp_addr *peer_addr,
sctp_cid_t cid, sctp_init_chunk_t *peer_init, int priority);
sctp_chunk_t *chunk, int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
sctp_chunk_t **err_chunk); const union sctp_addr *peer_addr, int priority);
int sctp_process_unk_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init, int priority);
int sctp_process_param(sctp_association_t *asoc,
sctpParam_t param,
const sockaddr_storage_t *peer_addr,
sctp_cid_t cid, int priority);
__u32 sctp_generate_tag(const sctp_endpoint_t *ep); __u32 sctp_generate_tag(const sctp_endpoint_t *ep);
__u32 sctp_generate_tsn(const sctp_endpoint_t *ep); __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
...@@ -1163,10 +1176,10 @@ struct SCTP_association { ...@@ -1163,10 +1176,10 @@ struct SCTP_association {
sctp_transport_t *primary_path; sctp_transport_t *primary_path;
/* Cache the primary path address here, when we /* Cache the primary path address here, when we
* need a an address for msg_name. * need a an address for msg_name.
*/ */
sockaddr_storage_t primary_addr; union sctp_addr primary_addr;
/* active_path /* active_path
* The path that we are currently using to * The path that we are currently using to
* transmit new data and most control chunks. * transmit new data and most control chunks.
...@@ -1267,7 +1280,7 @@ struct SCTP_association { ...@@ -1267,7 +1280,7 @@ struct SCTP_association {
/* Overall : The threshold for this association that if /* Overall : The threshold for this association that if
* Error : the Overall Error Count reaches will cause * Error : the Overall Error Count reaches will cause
* Threshold : this association to be torn down. * Threshold : this association to be torn down.
*/ */
int overall_error_threshold; int overall_error_threshold;
...@@ -1313,13 +1326,13 @@ struct SCTP_association { ...@@ -1313,13 +1326,13 @@ struct SCTP_association {
*/ */
__u32 next_tsn; __u32 next_tsn;
/* /*
* Last Rcvd : This is the last TSN received in sequence. This value * Last Rcvd : This is the last TSN received in sequence. This value
* TSN : is set initially by taking the peer's Initial TSN, * TSN : is set initially by taking the peer's Initial TSN,
* : received in the INIT or INIT ACK chunk, and * : received in the INIT or INIT ACK chunk, and
* : subtracting one from it. * : subtracting one from it.
* *
* Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point.
*/ */
__u32 ctsn_ack_point; __u32 ctsn_ack_point;
...@@ -1543,16 +1556,16 @@ void sctp_association_hold(sctp_association_t *); ...@@ -1543,16 +1556,16 @@ void sctp_association_hold(sctp_association_t *);
sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *); sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *);
sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *,
const sockaddr_storage_t *); const union sctp_addr *);
sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *,
const sockaddr_storage_t *address, const union sctp_addr *address,
const int priority); const int priority);
void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *, void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *,
sctp_transport_cmd_t, sctp_sn_error_t); sctp_transport_cmd_t, sctp_sn_error_t);
sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, __u32); sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, __u32);
sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, sctp_transport_t *sctp_assoc_is_match(sctp_association_t *,
const sockaddr_storage_t *, const union sctp_addr *,
const sockaddr_storage_t *); const union sctp_addr *);
void sctp_assoc_migrate(sctp_association_t *, struct sock *); void sctp_assoc_migrate(sctp_association_t *, struct sock *);
void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src);
...@@ -1560,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *); ...@@ -1560,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *);
__u32 __sctp_association_get_tsn_block(sctp_association_t *, int); __u32 __sctp_association_get_tsn_block(sctp_association_t *, int);
__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); __u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid);
int sctp_cmp_addr(const sockaddr_storage_t *ss1, int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const sockaddr_storage_t *ss2); const union sctp_addr *ss2);
int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1,
const sockaddr_storage_t *ss2);
sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc); sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc);
sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc); sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc);
/* A convenience structure to parse out SCTP specific CMSGs. */ /* A convenience structure to parse out SCTP specific CMSGs. */
typedef struct sctp_cmsgs { typedef struct sctp_cmsgs {
struct sctp_initmsg *init; struct sctp_initmsg *init;
......
...@@ -195,6 +195,7 @@ struct xfrm_policy ...@@ -195,6 +195,7 @@ struct xfrm_policy
/* This lock only affects elements except for entry. */ /* This lock only affects elements except for entry. */
rwlock_t lock; rwlock_t lock;
atomic_t refcnt; atomic_t refcnt;
struct timer_list timer;
u32 priority; u32 priority;
u32 index; u32 index;
......
...@@ -266,14 +266,14 @@ config VLAN_8021Q ...@@ -266,14 +266,14 @@ config VLAN_8021Q
tristate "802.1Q VLAN Support" tristate "802.1Q VLAN Support"
config LLC config LLC
tristate "ANSI/IEEE 802.2 Data link layer protocol (IPX, Appletalk)" tristate "ANSI/IEEE 802.2 - aka LLC (IPX, Appletalk, Token Ring)"
help help
This is a Logical Link Layer protocol used for Appletalk, IPX and in This is a Logical Link Layer protocol used for Appletalk, IPX,
the future by NetBEUI and by the linux-sna project. It originally Token Ring devices, the linux-sna.org project and in the future by
came from Procom Inc. that released the code for 2.0.36 and was NetBEUI. It originally came from Procom Inc. that released the code
ported to 2.{4,5}. Select this if you want to have support for for 2.0.36 and was heavily modified to work with 2.{4,5}.
those protocols or if you want to have the sockets interface for Select this if you want to have support for those protocols or if
LLC. you want to have the sockets interface for LLC.
config LLC_UI config LLC_UI
......
...@@ -234,11 +234,12 @@ int ah_output(struct sk_buff *skb) ...@@ -234,11 +234,12 @@ int ah_output(struct sk_buff *skb)
x->curlft.packets++; x->curlft.packets++;
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
if ((skb->dst = dst_pop(dst)) == NULL) if ((skb->dst = dst_pop(dst)) == NULL)
goto error; goto error_nolock;
return NET_XMIT_BYPASS; return NET_XMIT_BYPASS;
error: error:
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
error_nolock:
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
......
...@@ -435,11 +435,12 @@ int esp_output(struct sk_buff *skb) ...@@ -435,11 +435,12 @@ int esp_output(struct sk_buff *skb)
x->curlft.packets++; x->curlft.packets++;
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
if ((skb->dst = dst_pop(dst)) == NULL) if ((skb->dst = dst_pop(dst)) == NULL)
goto error; goto error_nolock;
return NET_XMIT_BYPASS; return NET_XMIT_BYPASS;
error: error:
spin_unlock_bh(&x->lock); spin_unlock_bh(&x->lock);
error_nolock:
kfree_skb(skb); kfree_skb(skb);
return err; return err;
} }
......
...@@ -204,6 +204,50 @@ void xfrm_put_type(struct xfrm_type *type) ...@@ -204,6 +204,50 @@ void xfrm_put_type(struct xfrm_type *type)
__MOD_DEC_USE_COUNT(type->owner); __MOD_DEC_USE_COUNT(type->owner);
} }
static inline unsigned long make_jiffies(long secs)
{
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
return MAX_SCHEDULE_TIMEOUT-1;
else
return secs*HZ;
}
static void xfrm_policy_timer(unsigned long data)
{
struct xfrm_policy *xp = (struct xfrm_policy*)data;
unsigned long now = (unsigned long)xtime.tv_sec;
long next = LONG_MAX;
if (xp->dead)
goto out;
if (xp->lft.hard_add_expires_seconds) {
long tmo = xp->lft.hard_add_expires_seconds +
xp->curlft.add_time - now;
if (tmo <= 0)
goto expired;
if (tmo < next)
next = tmo;
}
if (next != LONG_MAX &&
!mod_timer(&xp->timer, jiffies + make_jiffies(next)))
atomic_inc(&xp->refcnt);
out:
xfrm_pol_put(xp);
return;
expired:
xfrm_pol_put(xp);
/* Not 100% correct. id can be recycled in theory */
xp = xfrm_policy_byid(0, xp->index, 1);
if (xp) {
xfrm_policy_kill(xp);
xfrm_pol_put(xp);
}
}
/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2 /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
* SPD calls. * SPD calls.
...@@ -219,6 +263,9 @@ struct xfrm_policy *xfrm_policy_alloc(int gfp) ...@@ -219,6 +263,9 @@ struct xfrm_policy *xfrm_policy_alloc(int gfp)
memset(policy, 0, sizeof(struct xfrm_policy)); memset(policy, 0, sizeof(struct xfrm_policy));
atomic_set(&policy->refcnt, 1); atomic_set(&policy->refcnt, 1);
policy->lock = RW_LOCK_UNLOCKED; policy->lock = RW_LOCK_UNLOCKED;
init_timer(&policy->timer);
policy->timer.data = (unsigned long)policy;
policy->timer.function = xfrm_policy_timer;
} }
return policy; return policy;
} }
...@@ -233,6 +280,9 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy) ...@@ -233,6 +280,9 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy)
if (policy->bundles) if (policy->bundles)
BUG(); BUG();
if (del_timer(&policy->timer))
BUG();
kfree(policy); kfree(policy);
} }
...@@ -255,6 +305,9 @@ void xfrm_policy_kill(struct xfrm_policy *policy) ...@@ -255,6 +305,9 @@ void xfrm_policy_kill(struct xfrm_policy *policy)
dst_free(dst); dst_free(dst);
} }
if (del_timer(&policy->timer))
atomic_dec(&policy->refcnt);
out: out:
write_unlock_bh(&policy->lock); write_unlock_bh(&policy->lock);
} }
...@@ -302,6 +355,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -302,6 +355,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
policy->index = pol ? pol->index : xfrm_gen_index(dir); policy->index = pol ? pol->index : xfrm_gen_index(dir);
policy->curlft.add_time = (unsigned long)xtime.tv_sec; policy->curlft.add_time = (unsigned long)xtime.tv_sec;
policy->curlft.use_time = 0; policy->curlft.use_time = 0;
if (policy->lft.hard_add_expires_seconds &&
!mod_timer(&policy->timer, jiffies + HZ))
atomic_inc(&policy->refcnt);
write_unlock_bh(&xfrm_policy_lock); write_unlock_bh(&xfrm_policy_lock);
if (pol) { if (pol) {
...@@ -380,7 +436,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), ...@@ -380,7 +436,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
int count = 0; int count = 0;
int error = 0; int error = 0;
read_lock(&xfrm_policy_lock); read_lock_bh(&xfrm_policy_lock);
for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) for (xp = xfrm_policy_list[dir]; xp; xp = xp->next)
count++; count++;
...@@ -400,7 +456,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), ...@@ -400,7 +456,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
} }
out: out:
read_unlock(&xfrm_policy_lock); read_unlock_bh(&xfrm_policy_lock);
return error; return error;
} }
...@@ -411,7 +467,7 @@ struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl) ...@@ -411,7 +467,7 @@ struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl)
{ {
struct xfrm_policy *pol; struct xfrm_policy *pol;
read_lock(&xfrm_policy_lock); read_lock_bh(&xfrm_policy_lock);
for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
struct xfrm_selector *sel = &pol->selector; struct xfrm_selector *sel = &pol->selector;
...@@ -420,7 +476,7 @@ struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl) ...@@ -420,7 +476,7 @@ struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl)
break; break;
} }
} }
read_unlock(&xfrm_policy_lock); read_unlock_bh(&xfrm_policy_lock);
return pol; return pol;
} }
...@@ -428,14 +484,14 @@ struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi ...@@ -428,14 +484,14 @@ struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi
{ {
struct xfrm_policy *pol; struct xfrm_policy *pol;
read_lock(&xfrm_policy_lock); read_lock_bh(&xfrm_policy_lock);
if ((pol = sk->policy[dir]) != NULL) { if ((pol = sk->policy[dir]) != NULL) {
if (xfrm4_selector_match(&pol->selector, fl)) if (xfrm4_selector_match(&pol->selector, fl))
atomic_inc(&pol->refcnt); atomic_inc(&pol->refcnt);
else else
pol = NULL; pol = NULL;
} }
read_unlock(&xfrm_policy_lock); read_unlock_bh(&xfrm_policy_lock);
return pol; return pol;
} }
...@@ -727,8 +783,7 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -727,8 +783,7 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
return 0; return 0;
} }
if (!policy->curlft.use_time) policy->curlft.use_time = (unsigned long)xtime.tv_sec;
policy->curlft.use_time = (unsigned long)xtime.tv_sec;
switch (policy->action) { switch (policy->action) {
case XFRM_POLICY_BLOCK: case XFRM_POLICY_BLOCK:
...@@ -936,8 +991,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb) ...@@ -936,8 +991,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
if (!pol) if (!pol)
return 1; return 1;
if (!pol->curlft.use_time) pol->curlft.use_time = (unsigned long)xtime.tv_sec;
pol->curlft.use_time = (unsigned long)xtime.tv_sec;
if (pol->action == XFRM_POLICY_ALLOW) { if (pol->action == XFRM_POLICY_ALLOW) {
if (pol->xfrm_nr != 0) { if (pol->xfrm_nr != 0) {
......
...@@ -28,7 +28,7 @@ DECLARE_WAIT_QUEUE_HEAD(km_waitq); ...@@ -28,7 +28,7 @@ DECLARE_WAIT_QUEUE_HEAD(km_waitq);
static void __xfrm_state_delete(struct xfrm_state *x); static void __xfrm_state_delete(struct xfrm_state *x);
unsigned long make_jiffies(long secs) static inline unsigned long make_jiffies(long secs)
{ {
if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
return MAX_SCHEDULE_TIMEOUT-1; return MAX_SCHEDULE_TIMEOUT-1;
...@@ -92,7 +92,14 @@ static void xfrm_timer_handler(unsigned long data) ...@@ -92,7 +92,14 @@ static void xfrm_timer_handler(unsigned long data)
goto out; goto out;
expired: expired:
km_expired(x); if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
x->km.state = XFRM_STATE_EXPIRED;
wake_up(&km_waitq);
next = 2;
goto resched;
}
if (x->id.spi != 0)
km_expired(x);
__xfrm_state_delete(x); __xfrm_state_delete(x);
out: out:
...@@ -298,11 +305,13 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, ...@@ -298,11 +305,13 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
x->km.state = XFRM_STATE_DEAD; x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x); xfrm_state_put(x);
x = NULL; x = NULL;
error = 1;
} }
} }
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&xfrm_state_lock);
if (!x) if (!x)
*err = acquire_in_progress ? -EAGAIN : -ENOMEM; *err = acquire_in_progress ? -EAGAIN :
(error ? -ESRCH : -ENOMEM);
return x; return x;
} }
...@@ -612,6 +621,7 @@ void km_expired(struct xfrm_state *x) ...@@ -612,6 +621,7 @@ void km_expired(struct xfrm_state *x)
list_for_each_entry(km, &xfrm_km_list, list) list_for_each_entry(km, &xfrm_km_list, list)
km->notify(x, 1); km->notify(x, 1);
read_unlock(&xfrm_km_lock); read_unlock(&xfrm_km_lock);
wake_up(&km_waitq);
} }
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
......
...@@ -910,9 +910,8 @@ static int xfrm_send_notify(struct xfrm_state *x, int hard) ...@@ -910,9 +910,8 @@ static int xfrm_send_notify(struct xfrm_state *x, int hard)
BUG(); BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
return 0; return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
} }
/* XXX Make this xfrm_state.c:xfrm_get_acqseq() */ /* XXX Make this xfrm_state.c:xfrm_get_acqseq() */
...@@ -971,9 +970,8 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, ...@@ -971,9 +970,8 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
BUG(); BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_ACQUIRE; NETLINK_CB(skb).dst_groups = XFRMGRP_ACQUIRE;
netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC);
return 0; return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC);
} }
/* User gives us xfrm_user_policy_info followed by an array of 0 /* User gives us xfrm_user_policy_info followed by an array of 0
......
...@@ -196,9 +196,11 @@ static int pfkey_release(struct socket *sock) ...@@ -196,9 +196,11 @@ static int pfkey_release(struct socket *sock)
return 0; return 0;
} }
static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
int allocation, struct sock *sk) int allocation, struct sock *sk)
{ {
int err = -ENOBUFS;
sock_hold(sk); sock_hold(sk);
if (*skb2 == NULL) { if (*skb2 == NULL) {
if (atomic_read(&skb->users) != 1) { if (atomic_read(&skb->users) != 1) {
...@@ -215,9 +217,11 @@ static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, ...@@ -215,9 +217,11 @@ static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
skb_queue_tail(&sk->receive_queue, *skb2); skb_queue_tail(&sk->receive_queue, *skb2);
sk->data_ready(sk, (*skb2)->len); sk->data_ready(sk, (*skb2)->len);
*skb2 = NULL; *skb2 = NULL;
err = 0;
} }
} }
sock_put(sk); sock_put(sk);
return err;
} }
/* Send SKB to all pfkey sockets matching selected criteria. */ /* Send SKB to all pfkey sockets matching selected criteria. */
...@@ -225,21 +229,23 @@ static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, ...@@ -225,21 +229,23 @@ static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
#define BROADCAST_ONE 1 #define BROADCAST_ONE 1
#define BROADCAST_REGISTERED 2 #define BROADCAST_REGISTERED 2
#define BROADCAST_PROMISC_ONLY 4 #define BROADCAST_PROMISC_ONLY 4
static void pfkey_broadcast(struct sk_buff *skb, int allocation, static int pfkey_broadcast(struct sk_buff *skb, int allocation,
int broadcast_flags, struct sock *one_sk) int broadcast_flags, struct sock *one_sk)
{ {
struct sock *sk; struct sock *sk;
struct sk_buff *skb2 = NULL; struct sk_buff *skb2 = NULL;
int err = -ESRCH;
/* XXX Do we need something like netlink_overrun? I think /* XXX Do we need something like netlink_overrun? I think
* XXX PF_KEY socket apps will not mind current behavior. * XXX PF_KEY socket apps will not mind current behavior.
*/ */
if (!skb) if (!skb)
return; return -ENOMEM;
pfkey_lock_table(); pfkey_lock_table();
for (sk = pfkey_table; sk; sk = sk->next) { for (sk = pfkey_table; sk; sk = sk->next) {
struct pfkey_opt *pfk = pfkey_sk(sk); struct pfkey_opt *pfk = pfkey_sk(sk);
int err2;
/* Yes, it means that if you are meant to receive this /* Yes, it means that if you are meant to receive this
* pfkey message you receive it twice as promiscuous * pfkey message you receive it twice as promiscuous
...@@ -261,16 +267,22 @@ static void pfkey_broadcast(struct sk_buff *skb, int allocation, ...@@ -261,16 +267,22 @@ static void pfkey_broadcast(struct sk_buff *skb, int allocation,
continue; continue;
} }
pfkey_broadcast_one(skb, &skb2, allocation, sk); err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk);
/* Error is cleare after succecful sending to at least one
* registered KM */
if ((broadcast_flags & BROADCAST_REGISTERED) && err)
err = err2;
} }
pfkey_unlock_table(); pfkey_unlock_table();
if (one_sk != NULL) if (one_sk != NULL)
pfkey_broadcast_one(skb, &skb2, allocation, one_sk); err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
if (skb2) if (skb2)
kfree_skb(skb2); kfree_skb(skb2);
kfree_skb(skb); kfree_skb(skb);
return err;
} }
static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig) static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig)
...@@ -1101,8 +1113,12 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg * ...@@ -1101,8 +1113,12 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *
if (x == NULL) if (x == NULL)
return 0; return 0;
if (x->km.state == XFRM_STATE_ACQ) spin_lock_bh(&x->lock);
xfrm_state_delete(x); if (x->km.state == XFRM_STATE_ACQ) {
x->km.state = XFRM_STATE_ERROR;
wake_up(&km_waitq);
}
spin_unlock_bh(&x->lock);
xfrm_state_put(x); xfrm_state_put(x);
return 0; return 0;
} }
...@@ -1783,14 +1799,10 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h ...@@ -1783,14 +1799,10 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
struct sk_buff *out_skb; struct sk_buff *out_skb;
struct sadb_msg *out_hdr; struct sadb_msg *out_hdr;
if (!ext_hdrs[SADB_X_EXT_POLICY-1]) if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL; return -EINVAL;
pol = ext_hdrs[SADB_X_EXT_POLICY-1]; xp = xfrm_policy_byid(0, pol->sadb_x_policy_id,
if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
return -EINVAL;
xp = xfrm_policy_byid(pol->sadb_x_policy_dir-1, pol->sadb_x_policy_id,
hdr->sadb_msg_type == SADB_X_SPDDELETE2); hdr->sadb_msg_type == SADB_X_SPDDELETE2);
if (xp == NULL) if (xp == NULL)
return -ENOENT; return -ENOENT;
...@@ -2142,9 +2154,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct ...@@ -2142,9 +2154,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
else if (x->id.proto == IPPROTO_ESP) else if (x->id.proto == IPPROTO_ESP)
dump_esp_combs(skb, t); dump_esp_combs(skb, t);
pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
return 0;
} }
static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int *dir) static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int *dir)
......
...@@ -181,22 +181,22 @@ int llc_sk_init(struct sock* sk) ...@@ -181,22 +181,22 @@ int llc_sk_init(struct sock* sk)
llc->inc_cntr = llc->dec_cntr = 2; llc->inc_cntr = llc->dec_cntr = 2;
llc->dec_step = llc->connect_step = 1; llc->dec_step = llc->connect_step = 1;
init_timer(&llc->ack_timer); init_timer(&llc->ack_timer.timer);
llc->ack_timer.expire = LLC_ACK_TIME; llc->ack_timer.expire = LLC_ACK_TIME;
llc->ack_timer.timer.data = (unsigned long)sk; llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb; llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
init_timer(&llc->pf_cycle_timer); init_timer(&llc->pf_cycle_timer.timer);
llc->pf_cycle_timer.expire = LLC_P_TIME; llc->pf_cycle_timer.expire = LLC_P_TIME;
llc->pf_cycle_timer.timer.data = (unsigned long)sk; llc->pf_cycle_timer.timer.data = (unsigned long)sk;
llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb; llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
init_timer(&llc->rej_sent_timer); init_timer(&llc->rej_sent_timer.timer);
llc->rej_sent_timer.expire = LLC_REJ_TIME; llc->rej_sent_timer.expire = LLC_REJ_TIME;
llc->rej_sent_timer.timer.data = (unsigned long)sk; llc->rej_sent_timer.timer.data = (unsigned long)sk;
llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb; llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
init_timer(&llc->busy_state_timer); init_timer(&llc->busy_state_timer.timer);
llc->busy_state_timer.expire = LLC_BUSY_TIME; llc->busy_state_timer.expire = LLC_BUSY_TIME;
llc->busy_state_timer.timer.data = (unsigned long)sk; llc->busy_state_timer.timer.data = (unsigned long)sk;
llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb; llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
......
...@@ -503,13 +503,13 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff ...@@ -503,13 +503,13 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff
return -1; return -1;
} }
void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
u32 group, int allocation) u32 group, int allocation)
{ {
struct sock *sk; struct sock *sk;
struct sk_buff *skb2 = NULL; struct sk_buff *skb2 = NULL;
int protocol = ssk->protocol; int protocol = ssk->protocol;
int failure = 0; int failure = 0, delivered = 0;
/* While we sleep in clone, do not allow to change socket list */ /* While we sleep in clone, do not allow to change socket list */
...@@ -544,8 +544,10 @@ void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -544,8 +544,10 @@ void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
failure = 1; failure = 1;
} else if (netlink_broadcast_deliver(sk, skb2)) { } else if (netlink_broadcast_deliver(sk, skb2)) {
netlink_overrun(sk); netlink_overrun(sk);
} else } else {
delivered = 1;
skb2 = NULL; skb2 = NULL;
}
sock_put(sk); sock_put(sk);
} }
...@@ -554,6 +556,12 @@ void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -554,6 +556,12 @@ void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
if (skb2) if (skb2)
kfree_skb(skb2); kfree_skb(skb2);
kfree_skb(skb); kfree_skb(skb);
if (delivered)
return 0;
if (failure)
return -ENOBUFS;
return -ESRCH;
} }
void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
......
...@@ -283,6 +283,7 @@ extern int (*dlci_ioctl_hook)(unsigned int, void *); ...@@ -283,6 +283,7 @@ extern int (*dlci_ioctl_hook)(unsigned int, void *);
EXPORT_SYMBOL(dlci_ioctl_hook); EXPORT_SYMBOL(dlci_ioctl_hook);
#endif #endif
EXPORT_SYMBOL(km_waitq);
EXPORT_SYMBOL(xfrm_cfg_sem); EXPORT_SYMBOL(xfrm_cfg_sem);
EXPORT_SYMBOL(xfrm_policy_alloc); EXPORT_SYMBOL(xfrm_policy_alloc);
EXPORT_SYMBOL(__xfrm_policy_destroy); EXPORT_SYMBOL(__xfrm_policy_destroy);
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This module provides the abstraction for an SCTP association. * This module provides the abstraction for an SCTP association.
* *
* 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 * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -92,7 +92,7 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, ...@@ -92,7 +92,7 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep,
sctp_association_t *sctp_association_init(sctp_association_t *asoc, sctp_association_t *sctp_association_init(sctp_association_t *asoc,
const sctp_endpoint_t *ep, const sctp_endpoint_t *ep,
const struct sock *sk, const struct sock *sk,
sctp_scope_t scope, sctp_scope_t scope,
int priority) int priority)
{ {
sctp_opt_t *sp; sctp_opt_t *sp;
...@@ -363,48 +363,34 @@ static void sctp_association_destroy(sctp_association_t *asoc) ...@@ -363,48 +363,34 @@ static void sctp_association_destroy(sctp_association_t *asoc)
/* Add a transport address to an association. */ /* Add a transport address to an association. */
sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
const sockaddr_storage_t *addr, const union sctp_addr *addr,
int priority) int priority)
{ {
sctp_transport_t *peer; sctp_transport_t *peer;
sctp_opt_t *sp; sctp_opt_t *sp;
const __u16 *port; unsigned short port;
switch (addr->sa.sa_family) {
case AF_INET:
port = &addr->v4.sin_port;
break;
case AF_INET6: /* AF_INET and AF_INET6 share common port field. */
SCTP_V6( port = addr->v4.sin_port;
port = &addr->v6.sin6_port;
break;
);
default:
return NULL;
};
/* Set the port if it has not been set yet. */ /* Set the port if it has not been set yet. */
if (0 == asoc->peer.port) { if (0 == asoc->peer.port) {
asoc->peer.port = *port; asoc->peer.port = port;
} }
SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", return NULL);
/* Check to see if this is a duplicate. */ /* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr); peer = sctp_assoc_lookup_paddr(asoc, addr);
if (peer) if (peer)
return peer; return peer;
peer = sctp_transport_new(addr, priority); peer = sctp_transport_new(addr, priority);
if (NULL == peer) if (!peer)
return NULL; return NULL;
sctp_transport_set_owner(peer, asoc); sctp_transport_set_owner(peer, asoc);
/* Cache a route for the transport. */ /* Cache a route for the transport. */
sctp_transport_route(peer, NULL); sctp_transport_route(peer, NULL, sctp_sk(asoc->base.sk));
/* If this is the first transport addr on this association, /* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU. * initialize the association PMTU to the peer's PMTU.
...@@ -423,7 +409,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -423,7 +409,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc->frag_point = asoc->pmtu - asoc->frag_point = asoc->pmtu -
(SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t)); (SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t));
/* The asoc->peer.port might not be meaningful as of now, but /* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway. * initialize the packet structure anyway.
*/ */
(asoc->outqueue.init_output)(&peer->packet, (asoc->outqueue.init_output)(&peer->packet,
...@@ -460,6 +446,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -460,6 +446,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
min(asoc->overall_error_threshold + peer->error_threshold, min(asoc->overall_error_threshold + peer->error_threshold,
asoc->max_retrans); asoc->max_retrans);
/* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1;
/* Initialize the peer's heartbeat interval based on the /* Initialize the peer's heartbeat interval based on the
* sock configured value. * sock configured value.
*/ */
...@@ -474,7 +463,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -474,7 +463,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc->peer.primary_path = peer; asoc->peer.primary_path = peer;
/* Set a default msg_name for events. */ /* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &peer->ipaddr, memcpy(&asoc->peer.primary_addr, &peer->ipaddr,
sizeof(sockaddr_storage_t)); sizeof(union sctp_addr));
asoc->peer.active_path = peer; asoc->peer.active_path = peer;
asoc->peer.retran_path = peer; asoc->peer.retran_path = peer;
} }
...@@ -487,7 +476,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -487,7 +476,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
/* Lookup a transport by address. */ /* Lookup a transport by address. */
sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc,
const sockaddr_storage_t *address) const union sctp_addr *address)
{ {
sctp_transport_t *t; sctp_transport_t *t;
struct list_head *pos; struct list_head *pos;
...@@ -522,12 +511,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -522,12 +511,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
/* Record the transition on the transport. */ /* Record the transition on the transport. */
switch (command) { switch (command) {
case SCTP_TRANSPORT_UP: case SCTP_TRANSPORT_UP:
transport->state.active = 1; transport->active = 1;
spc_state = ADDRESS_AVAILABLE; spc_state = ADDRESS_AVAILABLE;
break; break;
case SCTP_TRANSPORT_DOWN: case SCTP_TRANSPORT_DOWN:
transport->state.active = 0; transport->active = 0;
spc_state = ADDRESS_UNREACHABLE; spc_state = ADDRESS_UNREACHABLE;
break; break;
...@@ -557,7 +546,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -557,7 +546,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, sctp_transport_t, transports); t = list_entry(pos, sctp_transport_t, transports);
if (!t->state.active) if (!t->active)
continue; continue;
if (!first || t->last_time_heard > first->last_time_heard) { if (!first || t->last_time_heard > first->last_time_heard) {
second = first; second = first;
...@@ -577,7 +566,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -577,7 +566,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
* [If the primary is active but not most recent, bump the most * [If the primary is active but not most recent, bump the most
* recently used transport.] * recently used transport.]
*/ */
if (asoc->peer.primary_path->state.active && if (asoc->peer.primary_path->active &&
first != asoc->peer.primary_path) { first != asoc->peer.primary_path) {
second = first; second = first;
first = asoc->peer.primary_path; first = asoc->peer.primary_path;
...@@ -645,102 +634,21 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) ...@@ -645,102 +634,21 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
return asoc->ssn[sid]++; return asoc->ssn[sid]++;
} }
/* Compare two addresses to see if they match. Wildcard addresses
* always match within their address family.
*
* FIXME: We do not match address scopes correctly.
*/
int sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2)
{
int len;
const void *base1;
const void *base2;
if (ss1->sa.sa_family != ss2->sa.sa_family)
return 0;
if (ss1->v4.sin_port != ss2->v4.sin_port)
return 0;
switch (ss1->sa.sa_family) {
case AF_INET:
if (INADDR_ANY == ss1->v4.sin_addr.s_addr ||
INADDR_ANY == ss2->v4.sin_addr.s_addr)
goto match;
len = sizeof(struct in_addr);
base1 = &ss1->v4.sin_addr;
base2 = &ss2->v4.sin_addr;
break;
case AF_INET6:
SCTP_V6(
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&ss1->v6.sin6_addr))
goto match;
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&ss2->v6.sin6_addr))
goto match;
len = sizeof(struct in6_addr);
base1 = &ss1->v6.sin6_addr;
base2 = &ss2->v6.sin6_addr;
break;
)
default:
printk(KERN_WARNING
"WARNING, bogus socket address family %d\n",
ss1->sa.sa_family);
return 0;
};
return (0 == memcmp(base1, base2, len));
match:
return 1;
}
/* Compare two addresses to see if they match. Wildcard addresses /* Compare two addresses to see if they match. Wildcard addresses
* only match themselves. * only match themselves.
* *
* FIXME: We do not match address scopes correctly. * FIXME: We do not match address scopes correctly.
*/ */
int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const sockaddr_storage_t *ss2) const union sctp_addr *ss2)
{ {
int len; struct sctp_func *af;
const void *base1;
const void *base2;
if (ss1->sa.sa_family != ss2->sa.sa_family) af = sctp_get_af_specific(ss1->sa.sa_family);
return 0; if (!af)
if (ss1->v4.sin_port != ss2->v4.sin_port)
return 0; return 0;
switch (ss1->sa.sa_family) { return af->cmp_addr(ss1, ss2);
case AF_INET:
len = sizeof(struct in_addr);
base1 = &ss1->v4.sin_addr;
base2 = &ss2->v4.sin_addr;
break;
case AF_INET6:
SCTP_V6(
len = sizeof(struct in6_addr);
base1 = &ss1->v6.sin6_addr;
base2 = &ss2->v6.sin6_addr;
break;
)
default:
printk(KERN_WARNING
"WARNING, bogus socket address family %d\n",
ss1->sa.sa_family);
return 0;
};
return (0 == memcmp(base1, base2, len));
} }
/* Return an ecne chunk to get prepended to a packet. /* Return an ecne chunk to get prepended to a packet.
...@@ -842,8 +750,8 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) ...@@ -842,8 +750,8 @@ sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
/* Is this the association we are looking for? */ /* Is this the association we are looking for? */
sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc,
const sockaddr_storage_t *laddr, const union sctp_addr *laddr,
const sockaddr_storage_t *paddr) const union sctp_addr *paddr)
{ {
sctp_transport_t *transport; sctp_transport_t *transport;
...@@ -855,7 +763,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, ...@@ -855,7 +763,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc,
if (!transport) if (!transport)
goto out; goto out;
if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) if (sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
sctp_sk(asoc->base.sk)))
goto out; goto out;
} }
transport = NULL; transport = NULL;
...@@ -898,21 +807,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -898,21 +807,17 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),
state, ep, asoc, chunk, GFP_ATOMIC); state, ep, asoc, chunk, GFP_ATOMIC);
/* Check to see if the association is freed in response to /* Check to see if the association is freed in response to
* the incoming chunk. If so, get out of the while loop. * the incoming chunk. If so, get out of the while loop.
*/ */
if (!sctp_id2assoc(sk, associd)) if (!sctp_id2assoc(sk, associd))
goto out; break;
if (error != 0) /* If there is an error on chunk, discard this packet. */
goto err_out; if (error && chunk)
chunk->pdiscard = 1;
} }
err_out:
/* Is this the right way to pass errors up to the ULP? */
if (error)
sk->err = -error;
out:
} }
/* This routine moves an association from its old sk to a new sk. */ /* This routine moves an association from its old sk to a new sk. */
...@@ -1017,7 +922,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) ...@@ -1017,7 +922,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
/* Try to find an active transport. */ /* Try to find an active transport. */
if (t->state.active) { if (t->active) {
break; break;
} else { } else {
/* Keep track of the next transport in case /* Keep track of the next transport in case
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) Cisco 1999,2000 * Copyright (c) Cisco 1999,2000
* Copyright (c) Motorola 1999,2000,2001 * Copyright (c) Motorola 1999,2000,2001
* Copyright (c) International Business Machines Corp., 2001 * Copyright (c) International Business Machines Corp., 2001,2002
* Copyright (c) La Monte H.P. Yarroll 2001 * Copyright (c) La Monte H.P. Yarroll 2001
* *
* This file is part of the SCTP kernel reference implementation. * This file is part of the SCTP kernel reference implementation.
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Forward declarations for internal helpers. */ /* Forward declarations for internal helpers. */
static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *,
sctp_scope_t scope, int priority, int flags); sctp_scope_t scope, int priority, int flags);
static void sctp_bind_addr_clean(sctp_bind_addr_t *); static void sctp_bind_addr_clean(sctp_bind_addr_t *);
...@@ -143,7 +143,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp) ...@@ -143,7 +143,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp)
} }
/* Add an address to the bind address list in the SCTP_bind_addr structure. */ /* Add an address to the bind address list in the SCTP_bind_addr structure. */
int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new,
int priority) int priority)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
...@@ -171,7 +171,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, ...@@ -171,7 +171,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new,
/* Delete an address from the bind address list in the SCTP_bind_addr /* Delete an address from the bind address list in the SCTP_bind_addr
* structure. * structure.
*/ */
int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr)
{ {
struct list_head *pos, *temp; struct list_head *pos, *temp;
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
...@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) ...@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr)
* *
* The second argument is the return value for the length. * The second argument is the return value for the length.
*/ */
sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
int priority) int *addrs_len, int priority)
{ {
sctpParam_t addrparms; union sctp_params addrparms;
sctpParam_t retval; union sctp_params retval;
int addrparms_len; int addrparms_len;
sctp_addr_param_t rawaddr; sctp_addr_param_t rawaddr;
int len; int len;
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
struct list_head *pos; struct list_head *pos;
retval.v = NULL;
addrparms_len = 0; addrparms_len = 0;
len = 0; len = 0;
...@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, ...@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
len += sizeof(sctp_addr_param_t); len += sizeof(sctp_addr_param_t);
} }
addrparms.v = kmalloc(len, priority); retval.v = kmalloc(len, priority);
if (!addrparms.v) if (!retval.v)
goto end_raw; goto end_raw;
retval = addrparms; addrparms = retval;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sockaddr_storage_list, list);
...@@ -244,7 +242,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ...@@ -244,7 +242,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
{ {
sctp_addr_param_t *rawaddr; sctp_addr_param_t *rawaddr;
sctp_paramhdr_t *param; sctp_paramhdr_t *param;
sockaddr_storage_t addr; union sctp_addr addr;
int retval = 0; int retval = 0;
int len; int len;
...@@ -254,7 +252,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ...@@ -254,7 +252,7 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
rawaddr = (sctp_addr_param_t *)raw_addr_list; rawaddr = (sctp_addr_param_t *)raw_addr_list;
switch (param->type) { switch (param->type) {
case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV4_ADDRESS:
case SCTP_PARAM_IPV6_ADDRESS: case SCTP_PARAM_IPV6_ADDRESS:
sctp_param2sockaddr(&addr, rawaddr, port); sctp_param2sockaddr(&addr, rawaddr, port);
retval = sctp_add_bind_addr(bp, &addr, priority); retval = sctp_add_bind_addr(bp, &addr, priority);
...@@ -284,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ...@@ -284,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
/* Does this contain a specified address? */ /* Does this contain a specified address? Allow wildcarding. */
int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
struct sctp_opt *opt)
{ {
struct sockaddr_storage_list *laddr; struct sockaddr_storage_list *laddr;
struct list_head *pos; struct list_head *pos;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sockaddr_storage_list, list);
if (sctp_cmp_addr(&laddr->a, addr)) if (opt->pf->cmp_addr(&laddr->a, addr, opt))
return 1; return 1;
} }
...@@ -300,7 +299,7 @@ int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr ...@@ -300,7 +299,7 @@ int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr
} }
/* Copy out addresses from the global local address list. */ /* Copy out addresses from the global local address list. */
static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
sctp_scope_t scope, int priority, int flags) sctp_scope_t scope, int priority, int flags)
{ {
sctp_protocol_t *proto = sctp_get_protocol(); sctp_protocol_t *proto = sctp_get_protocol();
...@@ -325,94 +324,33 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, ...@@ -325,94 +324,33 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr,
return error; return error;
} }
/* Is addr one of the wildcards? */ /* Is this a wildcard address? */
int sctp_is_any(const sockaddr_storage_t *addr) int sctp_is_any(const union sctp_addr *addr)
{ {
int retval = 0; struct sctp_func *af = sctp_get_af_specific(addr->sa.sa_family);
if (!af)
switch (addr->sa.sa_family) { return 0;
case AF_INET: return af->is_any(addr);
if (INADDR_ANY == addr->v4.sin_addr.s_addr)
retval = 1;
break;
case AF_INET6:
SCTP_V6(
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&addr->v6.sin6_addr))
retval = 1;
);
break;
default:
break;
};
return retval;
} }
/* Is 'addr' valid for 'scope'? */ /* Is 'addr' valid for 'scope'? */
int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
{ {
sctp_scope_t addr_scope = sctp_scope(addr); sctp_scope_t addr_scope = sctp_scope(addr);
switch (addr->sa.sa_family) { /* The unusable SCTP addresses will not be considered with
case AF_INET: * any defined scopes.
/* According to the SCTP IPv4 address scoping document - */
* <draft-stewart-tsvwg-sctp-ipv4-00.txt>, the scope has if (SCTP_SCOPE_UNUSABLE == addr_scope)
* a heirarchy of 5 levels:
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
/* The unusable SCTP addresses will not be considered with
* any defined scopes.
*/
if (SCTP_SCOPE_UNUSABLE == addr_scope)
return 0;
/* Note that we are assuming that the scoping are the same
* for both IPv4 addresses and IPv6 addresses, i.e., if the
* scope is link local, both IPv4 link local addresses and
* IPv6 link local addresses would be treated as in the
* scope. There is no filtering for IPv4 vs. IPv6 addresses
* based on scoping alone.
*/
if (addr_scope <= scope)
return 1;
break;
case AF_INET6:
/* FIXME:
* This is almost certainly wrong since scopes have an
* heirarchy. I don't know what RFC to look at.
* There may be some guidance in the SCTP implementors
* guide (an Internet Draft as of October 2001).
*
* Further verification on the correctness of the IPv6
* scoping is needed. According to the IPv6 scoping draft,
* the link local and site local address may require
* further scoping.
*
* Is the heirachy of the IPv6 scoping the same as what's
* defined for IPv4?
* If the same heirarchy indeed applies to both famiies,
* this function can be simplified with one set of code.
* (see the comments for IPv4 above)
*/
if (addr_scope <= scope)
return 1;
break;
default:
return 0; return 0;
}; /*
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
if (addr_scope <= scope)
return 1;
return 0; return 0;
} }
...@@ -422,112 +360,13 @@ int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) ...@@ -422,112 +360,13 @@ int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope)
********************************************************************/ ********************************************************************/
/* What is the scope of 'addr'? */ /* What is the scope of 'addr'? */
sctp_scope_t sctp_scope(const sockaddr_storage_t *addr) sctp_scope_t sctp_scope(const union sctp_addr *addr)
{
sctp_scope_t retval = SCTP_SCOPE_GLOBAL;
switch (addr->sa.sa_family) {
case AF_INET:
/* We are checking the loopback, private and other address
* scopes as defined in RFC 1918.
* The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
* The set of SCTP address scope hopefully can cover both
* types of addresses.
*/
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_UNUSABLE;
} else if (LOOPBACK(addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LOOPBACK;
} else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LINK;
} else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_PRIVATE;
} else {
retval = SCTP_SCOPE_GLOBAL;
}
break;
case AF_INET6:
{
SCTP_V6(
int v6scope;
v6scope = ipv6_addr_scope((struct in6_addr *)
&addr->v6.sin6_addr);
/* The IPv6 scope is really a set of bit
* fields. See IFA_* in <net/if_inet6.h>.
* Mapping them to the generic SCTP scope
* set is an attempt to have code
* consistencies with the IPv4 scoping.
*/
switch (v6scope) {
case IFA_HOST:
retval = SCTP_SCOPE_LOOPBACK;
break;
case IFA_LINK:
retval = SCTP_SCOPE_LINK;
break;
case IFA_SITE:
retval = SCTP_SCOPE_PRIVATE;
break;
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
);
break;
}
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
return retval;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
int sctp_addr_is_valid(const sockaddr_storage_t *addr)
{ {
unsigned short sa_family = addr->sa.sa_family; struct sctp_func *af;
switch (sa_family) {
case AF_INET:
/* Is this a non-unicast address or a unusable SCTP address? */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr))
return 0;
break;
case AF_INET6: af = sctp_get_af_specific(addr->sa.sa_family);
SCTP_V6( if (!af)
{ return SCTP_SCOPE_UNUSABLE;
int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr);
/* Is this a non-unicast address */
if (!(ret & IPV6_ADDR_UNICAST))
return 0;
break;
});
default:
return 0;
};
return 1; return af->scope((union sctp_addr *)addr);
} }
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
...@@ -237,13 +237,14 @@ void sctp_endpoint_put(sctp_endpoint_t *ep) ...@@ -237,13 +237,14 @@ void sctp_endpoint_put(sctp_endpoint_t *ep)
/* Is this the endpoint we are looking for? */ /* Is this the endpoint we are looking for? */
sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
const sockaddr_storage_t *laddr) const union sctp_addr *laddr)
{ {
sctp_endpoint_t *retval; sctp_endpoint_t *retval;
sctp_read_lock(&ep->base.addr_lock); sctp_read_lock(&ep->base.addr_lock);
if (ep->base.bind_addr.port == laddr->v4.sin_port) { if (ep->base.bind_addr.port == laddr->v4.sin_port) {
if (sctp_bind_addr_has_addr(&ep->base.bind_addr, laddr)) { if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
sctp_sk(ep->base.sk))) {
retval = ep; retval = ep;
goto out; goto out;
} }
...@@ -262,7 +263,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -262,7 +263,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
*/ */
sctp_association_t *__sctp_endpoint_lookup_assoc( sctp_association_t *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint, const sctp_endpoint_t *endpoint,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **transport) sctp_transport_t **transport)
{ {
int rport; int rport;
...@@ -289,7 +290,7 @@ sctp_association_t *__sctp_endpoint_lookup_assoc( ...@@ -289,7 +290,7 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
/* Lookup association on an endpoint based on a peer address. BH-safe. */ /* Lookup association on an endpoint based on a peer address. BH-safe. */
sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **transport) sctp_transport_t **transport)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
...@@ -301,6 +302,30 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, ...@@ -301,6 +302,30 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
return asoc; return asoc;
} }
/* 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,
const union sctp_addr *paddr)
{
struct list_head *pos;
struct sockaddr_storage_list *addr;
sctp_bind_addr_t *bp;
sctp_read_lock(&ep->base.addr_lock);
bp = &ep->base.bind_addr;
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list);
if (sctp_has_association(&addr->a, paddr)) {
sctp_read_unlock(&ep->base.addr_lock);
return 1;
}
}
sctp_read_unlock(&ep->base.addr_lock);
return 0;
}
/* Do delayed input processing. This is scheduled by sctp_rcv(). /* Do delayed input processing. This is scheduled by sctp_rcv().
* This may be called on BH or task time. * This may be called on BH or task time.
*/ */
...@@ -316,13 +341,13 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -316,13 +341,13 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
int error = 0; int error = 0;
if (ep->base.dead) if (ep->base.dead)
goto out; return;
asoc = NULL; asoc = NULL;
inqueue = &ep->base.inqueue; inqueue = &ep->base.inqueue;
sk = ep->base.sk; sk = ep->base.sk;
while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { while (NULL != (chunk = sctp_pop_inqueue(inqueue))) {
subtype.chunk = chunk->chunk_hdr->type; subtype.chunk = chunk->chunk_hdr->type;
/* We might have grown an association since last we /* We might have grown an association since last we
...@@ -350,25 +375,16 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -350,25 +375,16 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
if (chunk->transport) if (chunk->transport)
chunk->transport->last_time_heard = jiffies; chunk->transport->last_time_heard = jiffies;
/* FIX ME We really would rather NOT have to use
* GFP_ATOMIC.
*/
error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state, error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state,
ep, asoc, chunk, GFP_ATOMIC); ep, asoc, chunk, GFP_ATOMIC);
if (error != 0) if (error && chunk)
goto err_out; chunk->pdiscard = 1;
/* Check to see if the endpoint is freed in response to /* Check to see if the endpoint is freed in response to
* the incoming chunk. If so, get out of the while loop. * the incoming chunk. If so, get out of the while loop.
*/ */
if (!sctp_sk(sk)->ep) if (!sctp_sk(sk)->ep)
goto out; break;
} }
err_out:
/* Is this the right way to pass errors up to the ULP? */
if (error)
ep->base.sk->err = -error;
out:
} }
...@@ -60,64 +60,11 @@ ...@@ -60,64 +60,11 @@
/* Forward declarations for internal helpers. */ /* Forward declarations for internal helpers. */
static int sctp_rcv_ootb(struct sk_buff *); static int sctp_rcv_ootb(struct sk_buff *);
sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const sockaddr_storage_t *laddr, const union sctp_addr *laddr,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **transportp); sctp_transport_t **transportp);
sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
/* Initialize a sockaddr_storage from in incoming skb.
* FIXME: This belongs with AF specific sctp_func_t. --jgrimm
*/
static sockaddr_storage_t *sctp_sockaddr_storage_init(sockaddr_storage_t *addr,
const struct sk_buff *skb,
int is_saddr)
{
sockaddr_storage_t *ret = NULL;
void *to, *saddr, *daddr;
__u16 *port;
size_t len;
struct sctphdr *sh;
switch (skb->nh.iph->version) {
case 4:
to = &addr->v4.sin_addr.s_addr;
port = &addr->v4.sin_port;
saddr = &skb->nh.iph->saddr;
daddr = &skb->nh.iph->daddr;
len = sizeof(struct in_addr);
addr->v4.sin_family = AF_INET;
break;
case 6:
SCTP_V6(
to = &addr->v6.sin6_addr;
port = &addr->v6.sin6_port;
saddr = &skb->nh.ipv6h->saddr;
daddr = &skb->nh.ipv6h->daddr;
len = sizeof(struct in6_addr);
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_flowinfo = 0; /* FIXME */
addr->v6.sin6_scope_id = 0; /* FIXME */
break;
)
default:
goto out;
};
sh = (struct sctphdr *) skb->h.raw;
if (is_saddr) {
*port = ntohs(sh->source);
memcpy(to, saddr, len);
} else {
*port = ntohs(sh->dest);
memcpy(to, daddr, len);
}
ret = addr;
out:
return ret;
}
/* Calculate the SCTP checksum of an SCTP packet. */ /* Calculate the SCTP checksum of an SCTP packet. */
static inline int sctp_rcv_checksum(struct sk_buff *skb) static inline int sctp_rcv_checksum(struct sk_buff *skb)
...@@ -147,8 +94,9 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -147,8 +94,9 @@ int sctp_rcv(struct sk_buff *skb)
sctp_transport_t *transport = NULL; sctp_transport_t *transport = NULL;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
struct sctphdr *sh; struct sctphdr *sh;
sockaddr_storage_t src; union sctp_addr src;
sockaddr_storage_t dest; union sctp_addr dest;
struct sctp_func *af;
int ret = 0; int ret = 0;
if (skb->pkt_type!=PACKET_HOST) if (skb->pkt_type!=PACKET_HOST)
...@@ -163,10 +111,15 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -163,10 +111,15 @@ int sctp_rcv(struct sk_buff *skb)
if (sctp_rcv_checksum(skb) < 0) if (sctp_rcv_checksum(skb) < 0)
goto bad_packet; goto bad_packet;
skb_pull(skb, sizeof(struct sctphdr)); skb_pull(skb, sizeof(struct sctphdr));
af = sctp_get_af_specific(ipver2af(skb->nh.iph->version));
if (unlikely(!af))
goto bad_packet;
sctp_sockaddr_storage_init(&src, skb, 1); /* Initialize local addresses for lookups. */
sctp_sockaddr_storage_init(&dest, skb, 0); af->from_skb(&src, skb, 1);
af->from_skb(&dest, skb, 0);
/* If the packet is to or from a non-unicast address, /* If the packet is to or from a non-unicast address,
* silently discard the packet. * silently discard the packet.
...@@ -179,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -179,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb)
* IP broadcast addresses cannot be used in an SCTP transport * IP broadcast addresses cannot be used in an SCTP transport
* address." * address."
*/ */
if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) if (!af->addr_valid(&src) || !af->addr_valid(&dest))
goto discard_it; goto discard_it;
asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport);
...@@ -219,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -219,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb)
chunk->sctp_hdr = sh; chunk->sctp_hdr = sh;
/* Set the source and destination addresses of the incoming chunk. */ /* Set the source and destination addresses of the incoming chunk. */
sctp_init_addrs(chunk); sctp_init_addrs(chunk, &src, &dest);
/* Remember where we came from. */ /* Remember where we came from. */
chunk->transport = transport; chunk->transport = transport;
...@@ -431,7 +384,7 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep) ...@@ -431,7 +384,7 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep)
} }
/* Look up an endpoint. */ /* Look up an endpoint. */
sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; sctp_endpoint_common_t *epb;
...@@ -523,8 +476,8 @@ void __sctp_unhash_established(sctp_association_t *asoc) ...@@ -523,8 +476,8 @@ void __sctp_unhash_established(sctp_association_t *asoc)
} }
/* Look up an association. */ /* Look up an association. */
sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr, sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **transportp) sctp_transport_t **transportp)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
...@@ -559,8 +512,8 @@ sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr, ...@@ -559,8 +512,8 @@ sctp_association_t *__sctp_lookup_association(const sockaddr_storage_t *laddr,
} }
/* Look up an association. BH-safe. */ /* Look up an association. BH-safe. */
sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr, sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
sctp_transport_t **transportp) sctp_transport_t **transportp)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
...@@ -568,13 +521,13 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr, ...@@ -568,13 +521,13 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr,
sctp_local_bh_disable(); sctp_local_bh_disable();
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
sctp_local_bh_enable(); sctp_local_bh_enable();
return asoc; return asoc;
} }
/* Is there an association matching the given local and peer addresses? */ /* Is there an association matching the given local and peer addresses? */
int sctp_has_association(const sockaddr_storage_t *laddr, int sctp_has_association(const union sctp_addr *laddr,
const sockaddr_storage_t *paddr) const union sctp_addr *paddr)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_transport_t *transport; sctp_transport_t *transport;
...@@ -606,21 +559,19 @@ int sctp_has_association(const sockaddr_storage_t *laddr, ...@@ -606,21 +559,19 @@ int sctp_has_association(const sockaddr_storage_t *laddr,
* in certain circumstances. * in certain circumstances.
* *
*/ */
static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
const sockaddr_storage_t *laddr, sctp_transport_t **transportp) const union sctp_addr *laddr, sctp_transport_t **transportp)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
sockaddr_storage_t addr; union sctp_addr addr;
sockaddr_storage_t *paddr = &addr; union sctp_addr *paddr = &addr;
struct sctphdr *sh = (struct sctphdr *) skb->h.raw; struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
sctp_chunkhdr_t *ch; sctp_chunkhdr_t *ch;
__u8 *ch_end, *data; union sctp_params params;
sctp_paramhdr_t *parm; sctp_init_chunk_t *init;
ch = (sctp_chunkhdr_t *) skb->data; ch = (sctp_chunkhdr_t *) skb->data;
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* If this is INIT/INIT-ACK look inside the chunk too. */ /* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) { switch (ch->type) {
case SCTP_CID_INIT: case SCTP_CID_INIT:
...@@ -646,24 +597,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, ...@@ -646,24 +597,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Find the start of the TLVs and the end of the chunk. This is /* Find the start of the TLVs and the end of the chunk. This is
* the region we search for address parameters. * the region we search for address parameters.
*/ */
data = skb->data + sizeof(sctp_init_chunk_t); init = (sctp_init_chunk_t *)skb->data;
/* See sctp_process_init() for how to go thru TLVs. */
while (data < ch_end) {
parm = (sctp_paramhdr_t *)data;
if (!parm->length)
break;
data += WORD_ROUND(ntohs(parm->length)); /* Walk the parameters looking for embedded addresses. */
sctp_walk_params(params, init, init_hdr.params) {
/* Note: Ignoring hostname addresses. */ /* Note: Ignoring hostname addresses. */
if ((SCTP_PARAM_IPV4_ADDRESS != parm->type) && if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) &&
(SCTP_PARAM_IPV6_ADDRESS != parm->type)) (SCTP_PARAM_IPV6_ADDRESS != params.p->type))
continue; continue;
sctp_param2sockaddr(paddr, (sctp_addr_param_t *)parm, sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source));
ntohs(sh->source));
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
if (asoc) if (asoc)
return asoc; return asoc;
...@@ -674,20 +618,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, ...@@ -674,20 +618,20 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Lookup an association for an inbound skb. */ /* Lookup an association for an inbound skb. */
sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const sockaddr_storage_t *paddr, const union sctp_addr *paddr,
const sockaddr_storage_t *laddr, const union sctp_addr *laddr,
sctp_transport_t **transportp) sctp_transport_t **transportp)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
/* Further lookup for INIT-ACK packet. /* Further lookup for INIT/INIT-ACK packets.
* SCTP Implementors Guide, 2.18 Handling of address * SCTP Implementors Guide, 2.18 Handling of address
* parameters within the INIT or INIT-ACK. * parameters within the INIT or INIT-ACK.
*/ */
if (!asoc) if (!asoc)
asoc = __sctp_rcv_initack_lookup(skb, laddr, transportp); asoc = __sctp_rcv_init_lookup(skb, laddr, transportp);
return asoc; return asoc;
} }
......
...@@ -172,16 +172,16 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -172,16 +172,16 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
/* Returns the dst cache entry for the given source and destination ip /* Returns the dst cache entry for the given source and destination ip
* addresses. * addresses.
*/ */
struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr, struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
sockaddr_storage_t *saddr) union sctp_addr *saddr)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, struct flowi fl = {
} } }; .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
__FUNCTION__, NIP6(fl.fl6_dst)); __FUNCTION__, NIP6(fl.fl6_dst));
if (saddr) { if (saddr) {
fl.fl6_src = &saddr->v6.sin6_addr; fl.fl6_src = &saddr->v6.sin6_addr;
...@@ -206,12 +206,147 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr, ...@@ -206,12 +206,147 @@ struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr,
return dst; return dst;
} }
/* Check if the dst entry's source addr matches the given source addr. */ /* Make a copy of all potential local addresses. */
int sctp_v6_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr) static void sctp_v6_copy_addrlist(struct list_head *addrlist,
struct net_device *dev)
{
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifp;
struct sockaddr_storage_list *addr;
read_lock(&addrconf_lock);
if ((in6_dev = __in6_dev_get(dev)) == NULL) {
read_unlock(&addrconf_lock);
return;
}
read_lock(&in6_dev->lock);
for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
/* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
if (addr) {
addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0;
addr->a.v6.sin6_addr = ifp->addr;
INIT_LIST_HEAD(&addr->list);
list_add_tail(&addr->list, addrlist);
}
}
read_unlock(&in6_dev->lock);
read_unlock(&addrconf_lock);
}
/* Initialize a sockaddr_storage from in incoming skb. */
static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
int is_saddr)
{
void *from;
__u16 *port;
struct sctphdr *sh;
port = &addr->v6.sin6_port;
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_flowinfo = 0; /* FIXME */
addr->v6.sin6_scope_id = 0; /* FIXME */
sh = (struct sctphdr *) skb->h.raw;
if (is_saddr) {
*port = ntohs(sh->source);
from = &skb->nh.ipv6h->saddr;
} else {
*port = ntohs(sh->dest);
from = &skb->nh.ipv6h->daddr;
}
ipv6_addr_copy(&addr->v6.sin6_addr, from);
}
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
{ {
struct rt6_info *rt = (struct rt6_info *)dst; struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
}
/* Compare addresses exactly. Well.. almost exactly; ignore scope_id
* for now. FIXME.
*/
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
int match;
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr,
(struct in6_addr *)&addr2->v6.sin6_addr);
return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); return match;
}
/* Initialize addr struct to INADDR_ANY. */
static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port)
{
memset(addr, 0x00, sizeof(union sctp_addr));
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
}
/* Is this a wildcard address? */
static int sctp_v6_is_any(const union sctp_addr *addr)
{
int type;
type = ipv6_addr_type((struct in6_addr *)&addr->v6.sin6_addr);
return IPV6_ADDR_ANY == type;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static int sctp_v6_addr_valid(union sctp_addr *addr)
{
int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr);
/* FIXME: v4-mapped-v6 address support. */
/* Is this a non-unicast address */
if (!(ret & IPV6_ADDR_UNICAST))
return 0;
return 1;
}
/* What is the scope of 'addr'? */
static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
{
int v6scope;
sctp_scope_t retval;
/* The IPv6 scope is really a set of bit fields.
* See IFA_* in <net/if_inet6.h>. Map to a generic SCTP scope.
*/
v6scope = ipv6_addr_scope(&addr->v6.sin6_addr);
switch (v6scope) {
case IFA_HOST:
retval = SCTP_SCOPE_LOOPBACK;
break;
case IFA_LINK:
retval = SCTP_SCOPE_LINK;
break;
case IFA_SITE:
retval = SCTP_SCOPE_PRIVATE;
break;
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
return retval;
} }
/* Initialize a PF_INET6 socket msg_name. */ /* Initialize a PF_INET6 socket msg_name. */
...@@ -227,12 +362,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) ...@@ -227,12 +362,13 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
} }
/* Initialize a PF_INET msgname from a ulpevent. */ /* Initialize a PF_INET msgname from a ulpevent. */
static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addrlen) static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname,
int *addrlen)
{ {
struct sockaddr_in6 *sin6, *sin6from; struct sockaddr_in6 *sin6, *sin6from;
if (msgname) { if (msgname) {
sockaddr_storage_t *addr; union sctp_addr *addr;
sctp_inet6_msgname(msgname, addrlen); sctp_inet6_msgname(msgname, addrlen);
sin6 = (struct sockaddr_in6 *)msgname; sin6 = (struct sockaddr_in6 *)msgname;
...@@ -288,6 +424,49 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, ...@@ -288,6 +424,49 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
} }
} }
/* Do we support this AF? */
static int sctp_inet6_af_supported(sa_family_t family)
{
/* FIXME: v4-mapped-v6 addresses. The I-D is still waffling
* on what to do with sockaddr formats for PF_INET6 sockets.
* For now assume we'll support both.
*/
switch (family) {
case AF_INET6:
case AF_INET:
return 1;
default:
return 0;
}
}
/* Address matching with wildcards allowed. This extra level
* of indirection lets us choose whether a PF_INET6 should
* disallow any v4 addresses if we so choose.
*/
static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2,
struct sctp_opt *opt)
{
struct sctp_func *af1, *af2;
af1 = sctp_get_af_specific(addr1->sa.sa_family);
af2 = sctp_get_af_specific(addr2->sa.sa_family);
if (!af1 || !af2)
return 0;
/* Today, wildcard AF_INET/AF_INET6. */
if (sctp_is_any(addr1) || sctp_is_any(addr2))
return 1;
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
return af1->cmp_addr(addr1, addr2);
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
.release = inet6_release, .release = inet6_release,
...@@ -327,7 +506,14 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -327,7 +506,14 @@ static sctp_func_t sctp_ipv6_specific = {
.setsockopt = ipv6_setsockopt, .setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt, .getsockopt = ipv6_getsockopt,
.get_dst = sctp_v6_get_dst, .get_dst = sctp_v6_get_dst,
.cmp_saddr = sctp_v6_cmp_saddr, .copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb,
.dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope,
.addr_valid = sctp_v6_addr_valid,
.inaddr_any = sctp_v6_inaddr_any,
.is_any = sctp_v6_is_any,
.net_header_len = sizeof(struct ipv6hdr), .net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6), .sockaddr_len = sizeof(struct sockaddr_in6),
.sa_family = AF_INET6, .sa_family = AF_INET6,
...@@ -336,6 +522,9 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -336,6 +522,9 @@ static sctp_func_t sctp_ipv6_specific = {
static sctp_pf_t sctp_pf_inet6_specific = { static sctp_pf_t sctp_pf_inet6_specific = {
.event_msgname = sctp_inet6_event_msgname, .event_msgname = sctp_inet6_event_msgname,
.skb_msgname = sctp_inet6_skb_msgname, .skb_msgname = sctp_inet6_skb_msgname,
.af_supported = sctp_inet6_af_supported,
.cmp_addr = sctp_inet6_cmp_addr,
.af = &sctp_ipv6_specific,
}; };
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with inet6 stack. */
......
...@@ -366,18 +366,13 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -366,18 +366,13 @@ int sctp_packet_transmit(sctp_packet_t *packet)
*/ */
sh->checksum = htonl(crc32); sh->checksum = htonl(crc32);
/* FIXME: Delete the rest of this switch statement once phase 2
* of address selection (ipv6 support) drops in.
*/
switch (transport->ipaddr.sa.sa_family) { switch (transport->ipaddr.sa.sa_family) {
case AF_INET:
inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr;
break;
case AF_INET6: case AF_INET6:
SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;)
break; break;
default:
/* This is bogus address type, just bail. */
break;
}; };
/* IP layer ECN support /* IP layer ECN support
...@@ -430,10 +425,12 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -430,10 +425,12 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst = transport->dst; dst = transport->dst;
if (!dst || dst->obsolete) { if (!dst || dst->obsolete) {
sctp_transport_route(transport, NULL); sctp_transport_route(transport, NULL, sctp_sk(sk));
} }
nskb->dst = dst_clone(transport->dst); nskb->dst = dst_clone(transport->dst);
if (!nskb->dst)
goto no_route;
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
nskb->len); nskb->len);
...@@ -441,6 +438,11 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -441,6 +438,11 @@ int sctp_packet_transmit(sctp_packet_t *packet)
out: out:
packet->size = SCTP_IP_OVERHEAD; packet->size = SCTP_IP_OVERHEAD;
return err; return err;
no_route:
kfree_skb(nskb);
IP_INC_STATS_BH(IpOutNoRoutes);
err = -EHOSTUNREACH;
goto out;
} }
/******************************************************************** /********************************************************************
......
...@@ -678,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -678,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if (!new_transport) { if (!new_transport) {
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
} else if (!new_transport->state.active) { } else if (!new_transport->active) {
/* If the chunk is Heartbeat, send it to /* If the chunk is Heartbeat, send it to
* chunk->transport, even it's inactive. * chunk->transport, even it's inactive.
*/ */
...@@ -835,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -835,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/ */
new_transport = chunk->transport; new_transport = chunk->transport;
if (new_transport == NULL || if (new_transport == NULL ||
!new_transport->state.active) !new_transport->active)
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
/* Change packets if necessary. */ /* Change packets if necessary. */
...@@ -1404,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1404,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* Mark the destination transport address as /* Mark the destination transport address as
* active if it is not so marked. * active if it is not so marked.
*/ */
if (!transport->state.active) { if (!transport->active) {
sctp_assoc_control_transport( sctp_assoc_control_transport(
transport->asoc, transport->asoc,
transport, transport,
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Narasimha Budihal <narasimha@refcode.org> * Narasimha Budihal <narasimha@refcode.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT); ...@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT);
DECLARE_PRIMITIVE(SEND); DECLARE_PRIMITIVE(SEND);
/* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
/* COMMENT BUG. Find out where this is mentioned in the spec. */ /* COMMENT BUG. Find out where this is mentioned in the spec. */
int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg)
{ {
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* Initialization/cleanup for SCTP protocol support. * Initialization/cleanup for SCTP protocol support.
* *
* 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 * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -103,8 +103,8 @@ void sctp_proc_exit(void) ...@@ -103,8 +103,8 @@ void sctp_proc_exit(void)
/* Private helper to extract ipv4 address and stash them in /* Private helper to extract ipv4 address and stash them in
* the protocol structure. * the protocol structure.
*/ */
static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, static void sctp_v4_copy_addrlist(struct list_head *addrlist,
struct net_device *dev) struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
...@@ -117,7 +117,6 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, ...@@ -117,7 +117,6 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
} }
read_lock(&in_dev->lock); read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
...@@ -126,7 +125,7 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, ...@@ -126,7 +125,7 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0; addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
list_add_tail(&addr->list, &proto->local_addr_list); list_add_tail(&addr->list, addrlist);
} }
} }
...@@ -134,56 +133,21 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, ...@@ -134,56 +133,21 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
read_unlock(&inetdev_lock); read_unlock(&inetdev_lock);
} }
/* Private helper to extract ipv6 address and stash them in
* the protocol structure.
* FIXME: Make this an address family function.
*/
static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto,
struct net_device *dev)
{
#ifdef SCTP_V6_SUPPORT
/* FIXME: The testframe doesn't support this function. */
#ifndef TEST_FRAME
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifp;
struct sockaddr_storage_list *addr;
read_lock(&addrconf_lock);
if ((in6_dev = __in6_dev_get(dev)) == NULL) {
read_unlock(&addrconf_lock);
return;
}
read_lock_bh(&in6_dev->lock);
for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
/* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
if (addr) {
addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0;
addr->a.v6.sin6_addr = ifp->addr;
INIT_LIST_HEAD(&addr->list);
list_add_tail(&addr->list, &proto->local_addr_list);
}
}
read_unlock_bh(&in6_dev->lock);
read_unlock(&addrconf_lock);
#endif /* TEST_FRAME */
#endif /* SCTP_V6_SUPPORT */
}
/* Extract our IP addresses from the system and stash them in the /* Extract our IP addresses from the system and stash them in the
* protocol structure. * protocol structure.
*/ */
static void __sctp_get_local_addr_list(sctp_protocol_t *proto) static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
{ {
struct net_device *dev; struct net_device *dev;
struct list_head *pos;
struct sctp_func *af;
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
sctp_v4_get_local_addr_list(proto, dev); list_for_each(pos, &proto->address_families) {
sctp_v6_get_local_addr_list(proto, dev); af = list_entry(pos, sctp_func_t, list);
af->copy_addrlist(&proto->local_addr_list, dev);
}
} }
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
} }
...@@ -259,13 +223,15 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, ...@@ -259,13 +223,15 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
/* Returns the dst cache entry for the given source and destination ip /* Returns the dst cache entry for the given source and destination ip
* addresses. * addresses.
*/ */
struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr, struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr,
sockaddr_storage_t *saddr) union sctp_addr *saddr)
{ {
struct rtable *rt; struct rtable *rt;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = struct flowi fl;
daddr->v4.sin_addr.s_addr,
} } }; memset(&fl, 0x0, sizeof(struct flowi));
fl.fl4_dst = daddr->v4.sin_addr.s_addr;
fl.proto = IPPROTO_SCTP;
if (saddr) if (saddr)
fl.fl4_src = saddr->v4.sin_addr.s_addr; fl.fl4_src = saddr->v4.sin_addr.s_addr;
...@@ -285,12 +251,118 @@ struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr, ...@@ -285,12 +251,118 @@ struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr,
return &rt->u.dst; return &rt->u.dst;
} }
/* Check if the dst entry's source addr matches the given source addr. */
int sctp_v4_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr) /* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr)
{
void *from;
__u16 *port;
struct sctphdr *sh;
port = &addr->v4.sin_port;
addr->v4.sin_family = AF_INET;
sh = (struct sctphdr *) skb->h.raw;
if (is_saddr) {
*port = ntohs(sh->source);
from = &skb->nh.iph->saddr;
} else {
*port = ntohs(sh->dest);
from = &skb->nh.iph->daddr;
}
memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr));
}
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst)
{ {
struct rtable *rt = (struct rtable *)dst; struct rtable *rt = (struct rtable *)dst;
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
/* Compare two addresses exactly. */
static int sctp_v4_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
if (addr1->v4.sin_port != addr2->v4.sin_port)
return 0;
if (addr1->v4.sin_addr.s_addr != addr2->v4.sin_addr.s_addr)
return 0;
return 1;
}
return (rt->rt_src == saddr->v4.sin_addr.s_addr); /* Initialize addr struct to INADDR_ANY. */
static void sctp_v4_inaddr_any(union sctp_addr *addr, unsigned short port)
{
addr->v4.sin_family = AF_INET;
addr->v4.sin_addr.s_addr = INADDR_ANY;
addr->v4.sin_port = port;
}
/* Is this a wildcard address? */
static int sctp_v4_is_any(const union sctp_addr *addr)
{
return INADDR_ANY == addr->v4.sin_addr.s_addr;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static int sctp_v4_addr_valid(union sctp_addr *addr)
{
/* Is this a non-unicast address or a unusable SCTP address? */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr))
return 0;
return 1;
}
/* Checking the loopback, private and other address scopes as defined in
* RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
*
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
{
sctp_scope_t retval;
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_UNUSABLE;
} else if (LOOPBACK(addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LOOPBACK;
} else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LINK;
} else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_PRIVATE;
} else {
retval = SCTP_SCOPE_GLOBAL;
}
return retval;
} }
/* Event handler for inet device events. /* Event handler for inet device events.
...@@ -336,11 +408,11 @@ int sctp_ctl_sock_init(void) ...@@ -336,11 +408,11 @@ int sctp_ctl_sock_init(void)
/* Get the table of functions for manipulating a particular address /* Get the table of functions for manipulating a particular address
* family. * family.
*/ */
sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) sctp_func_t *sctp_get_af_specific(sa_family_t family)
{ {
struct list_head *pos; struct list_head *pos;
sctp_protocol_t *proto = sctp_get_protocol(); sctp_protocol_t *proto = sctp_get_protocol();
sctp_func_t *retval, *af; struct sctp_func *retval, *af;
retval = NULL; retval = NULL;
...@@ -349,7 +421,7 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) ...@@ -349,7 +421,7 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
*/ */
list_for_each(pos, &proto->address_families) { list_for_each(pos, &proto->address_families) {
af = list_entry(pos, sctp_func_t, list); af = list_entry(pos, sctp_func_t, list);
if (address->sa.sa_family == af->sa_family) { if (family == af->sa_family) {
retval = af; retval = af;
break; break;
} }
...@@ -362,15 +434,16 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) ...@@ -362,15 +434,16 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
static void sctp_inet_msgname(char *msgname, int *addr_len) static void sctp_inet_msgname(char *msgname, int *addr_len)
{ {
struct sockaddr_in *sin; struct sockaddr_in *sin;
sin = (struct sockaddr_in *)msgname; sin = (struct sockaddr_in *)msgname;
*addr_len = sizeof(struct sockaddr_in); *addr_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET; sin->sin_family = AF_INET;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
} }
/* Copy the primary address of the peer primary address as the msg_name. */ /* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addr_len) static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname,
int *addr_len)
{ {
struct sockaddr_in *sin, *sinfrom; struct sockaddr_in *sin, *sinfrom;
...@@ -381,26 +454,56 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int * ...@@ -381,26 +454,56 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *
sin->sin_port = htons(event->asoc->peer.port); sin->sin_port = htons(event->asoc->peer.port);
sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr;
} }
} }
/* Initialize and copy out a msgname from an inbound skb. */ /* Initialize and copy out a msgname from an inbound skb. */
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len) static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len)
{ {
struct sctphdr *sh; struct sctphdr *sh;
struct sockaddr_in *sin; struct sockaddr_in *sin;
if (msgname) { if (msgname) {
sctp_inet_msgname(msgname, addr_len); sctp_inet_msgname(msgname, len);
sin = (struct sockaddr_in *)msgname; sin = (struct sockaddr_in *)msgname;
sh = (struct sctphdr *)skb->h.raw; sh = (struct sctphdr *)skb->h.raw;
sin->sin_port = sh->source; sin->sin_port = sh->source;
sin->sin_addr.s_addr = skb->nh.iph->saddr; sin->sin_addr.s_addr = skb->nh.iph->saddr;
} }
} }
/* Do we support this AF? */
static int sctp_inet_af_supported(sa_family_t family)
{
/* PF_INET only supports AF_INET addresses. */
return (AF_INET == family);
}
/* Address matching with wildcards allowed. */
static int sctp_inet_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2,
struct sctp_opt *opt)
{
/* PF_INET only supports AF_INET addresses. */
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
if (INADDR_ANY == addr1->v4.sin_addr.s_addr ||
INADDR_ANY == addr2->v4.sin_addr.s_addr)
return 1;
if (addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr)
return 1;
return 0;
}
struct sctp_func sctp_ipv4_specific;
static sctp_pf_t sctp_pf_inet = { static sctp_pf_t sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname, .event_msgname = sctp_inet_event_msgname,
.skb_msgname = sctp_inet_skb_msgname, .skb_msgname = sctp_inet_skb_msgname,
.af_supported = sctp_inet_af_supported,
.cmp_addr = sctp_inet_cmp_addr,
.af = &sctp_ipv4_specific,
}; };
...@@ -448,12 +551,19 @@ static struct inet_protocol sctp_protocol = { ...@@ -448,12 +551,19 @@ static struct inet_protocol sctp_protocol = {
}; };
/* IPv4 address related functions. */ /* IPv4 address related functions. */
sctp_func_t sctp_ipv4_specific = { struct sctp_func sctp_ipv4_specific = {
.queue_xmit = ip_queue_xmit, .queue_xmit = ip_queue_xmit,
.setsockopt = ip_setsockopt, .setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt, .getsockopt = ip_getsockopt,
.get_dst = sctp_v4_get_dst, .get_dst = sctp_v4_get_dst,
.cmp_saddr = sctp_v4_cmp_saddr, .copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb,
.dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid,
.inaddr_any = sctp_v4_inaddr_any,
.is_any = sctp_v4_is_any,
.scope = sctp_v4_scope,
.net_header_len = sizeof(struct iphdr), .net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in), .sockaddr_len = sizeof(struct sockaddr_in),
.sa_family = AF_INET, .sa_family = AF_INET,
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -166,7 +166,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -166,7 +166,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
int priority) int priority)
{ {
sctp_inithdr_t init; sctp_inithdr_t init;
sctpParam_t addrs; union sctp_params addrs;
size_t chunksize; size_t chunksize;
sctp_chunk_t *retval = NULL; sctp_chunk_t *retval = NULL;
int addrs_len = 0; int addrs_len = 0;
...@@ -228,7 +228,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -228,7 +228,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
{ {
sctp_inithdr_t initack; sctp_inithdr_t initack;
sctp_chunk_t *retval; sctp_chunk_t *retval;
sctpParam_t addrs; union sctp_params addrs;
int addrs_len; int addrs_len;
sctp_cookie_param_t *cookie; sctp_cookie_param_t *cookie;
int cookie_len; int cookie_len;
...@@ -1031,51 +1031,15 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, ...@@ -1031,51 +1031,15 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
} }
/* Set chunk->source and dest based on the IP header in chunk->skb. */ /* Set chunk->source and dest based on the IP header in chunk->skb. */
void sctp_init_addrs(sctp_chunk_t *chunk) void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src,
union sctp_addr *dest)
{ {
sockaddr_storage_t *source, *dest; memcpy(&chunk->source, src, sizeof(union sctp_addr));
struct sk_buff *skb; memcpy(&chunk->dest, dest, sizeof(union sctp_addr));
struct sctphdr *sh;
struct iphdr *ih4;
struct ipv6hdr *ih6;
source = &chunk->source;
dest = &chunk->dest;
skb = chunk->skb;
ih4 = skb->nh.iph;
ih6 = skb->nh.ipv6h;
sh = chunk->sctp_hdr;
switch (ih4->version) {
case 4:
source->v4.sin_family = AF_INET;
source->v4.sin_port = ntohs(sh->source);
source->v4.sin_addr.s_addr = ih4->saddr;
dest->v4.sin_family = AF_INET;
dest->v4.sin_port = ntohs(sh->dest);
dest->v4.sin_addr.s_addr = ih4->daddr;
break;
case 6:
SCTP_V6(
source->v6.sin6_family = AF_INET6;
source->v6.sin6_port = ntohs(sh->source);
source->v6.sin6_addr = ih6->saddr;
dest->v6.sin6_family = AF_INET6;
dest->v6.sin6_port = ntohs(sh->dest);
dest->v6.sin6_addr = ih6->daddr;
/* FIXME: What do we do with scope, etc. ? */
break;
)
default:
/* This is a bogus address type, just bail. */
break;
};
} }
/* Extract the source address from a chunk. */ /* Extract the source address from a chunk. */
const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk) const union sctp_addr *sctp_source(const sctp_chunk_t *chunk)
{ {
/* If we have a known transport, use that. */ /* If we have a known transport, use that. */
if (chunk->transport) { if (chunk->transport) {
...@@ -1482,78 +1446,28 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1482,78 +1446,28 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* 3rd Level Abstractions * 3rd Level Abstractions
********************************************************************/ ********************************************************************/
/* Verify the INIT packet before we process it. */ /* Do not attempt to handle the HOST_NAME parm. However, do
int sctp_verify_init(const sctp_association_t *asoc, * send back an indicator to the peer.
sctp_cid_t cid,
sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
sctpParam_t param;
uint8_t *end;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
* parameter" error. */
/* Find unrecognized parameters. */
end = ((uint8_t *)peer_init + ntohs(peer_init->chunk_hdr.length));
for (param.v = peer_init->init_hdr.params;
param.v < end;
param.v += WORD_ROUND(ntohs(param.p->length))) {
if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p))
return 0;
} /* for (loop through all parameters) */
return 1;
}
/* Find unrecognized parameters in the chunk.
* Return values:
* 0 - discard the chunk
* 1 - continue with the chunk
*/ */
int sctp_verify_param(const sctp_association_t *asoc, static int sctp_process_hn_param(const sctp_association_t *asoc,
sctpParam_t param, union sctp_params param,
sctp_cid_t cid, sctp_chunk_t *chunk,
sctp_chunk_t *chunk, sctp_chunk_t **err_chk_p)
sctp_chunk_t **err_chk_p)
{ {
int retval = 1; __u16 len = ntohs(param.p->length);
/* FIXME - This routine is not looking at each parameter per the /* Make an ERROR chunk, preparing enough room for
* chunk type, i.e., unrecognized parameters should be further * returning multiple unknown parameters.
* identified based on the chunk id.
*/ */
if (!*err_chk_p)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
switch (param.p->type) { if (*err_chk_p)
case SCTP_PARAM_IPV4_ADDRESS: sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED,
case SCTP_PARAM_IPV6_ADDRESS: param.v, len);
case SCTP_PARAM_COOKIE_PRESERVATIVE:
/* FIXME - If we don't support the host name parameter, we should
* generate an error for this - Unresolvable address.
*/
case SCTP_PARAM_HOST_NAME_ADDRESS:
case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
case SCTP_PARAM_STATE_COOKIE:
case SCTP_PARAM_HEARTBEAT_INFO:
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
break;
default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid);
return sctp_process_unk_param(asoc, param, chunk, err_chk_p);
break; /* Stop processing this chunk. */
} return 0;
return retval;
} }
/* RFC 3.2.1 & the Implementers Guide 2.2. /* RFC 3.2.1 & the Implementers Guide 2.2.
...@@ -1582,10 +1496,10 @@ int sctp_verify_param(const sctp_association_t *asoc, ...@@ -1582,10 +1496,10 @@ int sctp_verify_param(const sctp_association_t *asoc,
* 0 - discard the chunk * 0 - discard the chunk
* 1 - continue with the chunk * 1 - continue with the chunk
*/ */
int sctp_process_unk_param(const sctp_association_t *asoc, static int sctp_process_unk_param(const sctp_association_t *asoc,
sctpParam_t param, union sctp_params param,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p) sctp_chunk_t **err_chk_p)
{ {
int retval = 1; int retval = 1;
...@@ -1604,7 +1518,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1604,7 +1518,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if (*err_chk_p) if (*err_chk_p)
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p, param.v,
WORD_ROUND(ntohs(param.p->length))); WORD_ROUND(ntohs(param.p->length)));
break; break;
...@@ -1620,7 +1534,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1620,7 +1534,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
if (*err_chk_p) { if (*err_chk_p) {
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
(const void *)param.p, param.v,
WORD_ROUND(ntohs(param.p->length))); WORD_ROUND(ntohs(param.p->length)));
} else { } else {
/* If there is no memory for generating the ERROR /* If there is no memory for generating the ERROR
...@@ -1638,17 +1552,84 @@ int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1638,17 +1552,84 @@ int sctp_process_unk_param(const sctp_association_t *asoc,
return retval; return retval;
} }
/* Unpack the parameters in an INIT packet. /* Find unrecognized parameters in the chunk.
* FIXME: There is no return status to allow callers to do * Return values:
* error handling. * 0 - discard the chunk
* 1 - continue with the chunk
*/ */
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, static int sctp_verify_param(const sctp_association_t *asoc,
const sockaddr_storage_t *peer_addr, union sctp_params param,
sctp_init_chunk_t *peer_init, sctp_cid_t cid,
int priority) sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk)
{ {
sctpParam_t param; int retval = 1;
__u8 *end;
/* FIXME - This routine is not looking at each parameter per the
* chunk type, i.e., unrecognized parameters should be further
* identified based on the chunk id.
*/
switch (param.p->type) {
case SCTP_PARAM_IPV4_ADDRESS:
case SCTP_PARAM_IPV6_ADDRESS:
case SCTP_PARAM_COOKIE_PRESERVATIVE:
case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
case SCTP_PARAM_STATE_COOKIE:
case SCTP_PARAM_HEARTBEAT_INFO:
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
case SCTP_PARAM_ECN_CAPABLE:
break;
case SCTP_PARAM_HOST_NAME_ADDRESS:
/* Tell the peer, we won't support this param. */
return sctp_process_hn_param(asoc, param, chunk, err_chunk);
default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid);
return sctp_process_unk_param(asoc, param, chunk, err_chunk);
break;
}
return retval;
}
/* Verify the INIT packet before we process it. */
int sctp_verify_init(const sctp_association_t *asoc,
sctp_cid_t cid,
sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chk_p)
{
union sctp_params param;
/* FIXME - Verify the fixed fields of the INIT chunk. Also, verify
* the mandatory parameters somewhere here and generate either the
* "Missing mandatory parameter" error or the "Invalid mandatory
* parameter" error.
*/
/* Find unrecognized parameters. */
sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p))
return 0;
} /* for (loop through all parameters) */
return 1;
}
/* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success.
*/
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const union sctp_addr *peer_addr,
sctp_init_chunk_t *peer_init,
int priority)
{
union sctp_params param;
sctp_transport_t *transport; sctp_transport_t *transport;
struct list_head *pos, *temp; struct list_head *pos, *temp;
char *cookie; char *cookie;
...@@ -1664,15 +1645,14 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1664,15 +1645,14 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* be a a better choice than any of the embedded addresses. * be a a better choice than any of the embedded addresses.
*/ */
if (peer_addr) if (peer_addr)
sctp_assoc_add_peer(asoc, peer_addr, priority); if(!sctp_assoc_add_peer(asoc, peer_addr, priority))
goto nomem;
/* Process the initialization parameters. */ /* Process the initialization parameters. */
end = ((__u8 *)peer_init + ntohs(peer_init->chunk_hdr.length));
for (param.v = peer_init->init_hdr.params; sctp_walk_params(param, peer_init, init_hdr.params) {
param.v < end;
param.v += WORD_ROUND(ntohs(param.p->length))) { if (!sctp_process_param(asoc, param, peer_addr, priority))
if (!sctp_process_param(asoc, param, peer_addr, cid,
priority))
goto clean_up; goto clean_up;
} }
...@@ -1738,7 +1718,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1738,7 +1718,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* association to the same value as the Initial TSN. * association to the same value as the Initial TSN.
*/ */
asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
return; return 1;
clean_up: clean_up:
/* Release the transport structures. */ /* Release the transport structures. */
...@@ -1747,8 +1727,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1747,8 +1727,11 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
list_del(pos); list_del(pos);
sctp_transport_free(transport); sctp_transport_free(transport);
} }
nomem:
return 0;
} }
/* Update asoc with the option described in param. /* Update asoc with the option described in param.
* *
* RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT
...@@ -1760,14 +1743,12 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1760,14 +1743,12 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
* work we do. In particular, we should not build transport * work we do. In particular, we should not build transport
* structures for the addresses. * structures for the addresses.
*/ */
int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
const sockaddr_storage_t *peer_addr, const union sctp_addr *peer_addr, int priority)
sctp_cid_t cid, int priority)
{ {
sockaddr_storage_t addr; union sctp_addr addr;
sctp_addr_param_t *addrparm;
int j;
int i; int i;
__u16 sat;
int retval = 1; int retval = 1;
sctp_scope_t scope; sctp_scope_t scope;
...@@ -1776,30 +1757,21 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1776,30 +1757,21 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
* came from a fresh INIT, and INIT ACK, or were stored in a cookie. * came from a fresh INIT, and INIT ACK, or were stored in a cookie.
*/ */
switch (param.p->type) { switch (param.p->type) {
case SCTP_PARAM_IPV6_ADDRESS:
if( PF_INET6 != asoc->base.sk->family)
break;
/* Fall through. */
case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV4_ADDRESS:
addrparm = (sctp_addr_param_t *)param.v; sctp_param2sockaddr(&addr, param.addr, asoc->peer.port);
sctp_param2sockaddr(&addr, addrparm, asoc->peer.port);
scope = sctp_scope(peer_addr); scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope)) if (sctp_in_scope(&addr, scope))
sctp_assoc_add_peer(asoc, &addr, priority); if (!sctp_assoc_add_peer(asoc, &addr, priority))
break; return 0;
case SCTP_PARAM_IPV6_ADDRESS:
/* Rethink this as we may need to keep for
* restart considerations.
*/
if (PF_INET6 == asoc->base.sk->family) {
addrparm = (sctp_addr_param_t *)param.v;
sctp_param2sockaddr(&addr, addrparm, asoc->peer.port);
scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope))
sctp_assoc_add_peer(asoc, &addr, priority);
}
break; break;
case SCTP_PARAM_COOKIE_PRESERVATIVE: case SCTP_PARAM_COOKIE_PRESERVATIVE:
asoc->cookie_preserve = asoc->cookie_preserve =
ntohl(param.bht->lifespan_increment); ntohl(param.life->lifespan_increment);
break; break;
case SCTP_PARAM_HOST_NAME_ADDRESS: case SCTP_PARAM_HOST_NAME_ADDRESS:
...@@ -1813,10 +1785,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1813,10 +1785,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
asoc->peer.ipv4_address = 0; asoc->peer.ipv4_address = 0;
asoc->peer.ipv6_address = 0; asoc->peer.ipv6_address = 0;
j = (ntohs(param.p->length) - /* Cycle through address types; avoid divide by 0. */
sizeof(sctp_paramhdr_t)) / sat = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
sizeof(__u16); if (sat)
for (i = 0; i < j; ++i) { sat /= sizeof(__u16);
for (i = 0; i < sat; ++i) {
switch (param.sat->types[i]) { switch (param.sat->types[i]) {
case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV4_ADDRESS:
asoc->peer.ipv4_address = 1; asoc->peer.ipv4_address = 1;
...@@ -1843,13 +1817,11 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1843,13 +1817,11 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break; break;
case SCTP_PARAM_HEARTBEAT_INFO: case SCTP_PARAM_HEARTBEAT_INFO:
SCTP_DEBUG_PRINTK("unimplemented " /* Would be odd to receive, but it causes no problems. */
"SCTP_PARAM_HEARTBEAT_INFO\n");
break; break;
case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
SCTP_DEBUG_PRINTK("unimplemented " /* Rejected during verify stage. */
"SCTP_PARAM_UNRECOGNIZED_PARAMETERS\n");
break; break;
case SCTP_PARAM_ECN_CAPABLE: case SCTP_PARAM_ECN_CAPABLE:
...@@ -1898,8 +1870,8 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep) ...@@ -1898,8 +1870,8 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
* 4th Level Abstractions * 4th Level Abstractions
********************************************************************/ ********************************************************************/
/* Convert from an SCTP IP parameter to a sockaddr_storage_t. */ /* Convert from an SCTP IP parameter to a union sctp_addr. */
void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param, void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param,
__u16 port) __u16 port)
{ {
switch(param->v4.param_hdr.type) { switch(param->v4.param_hdr.type) {
...@@ -1926,11 +1898,8 @@ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param, ...@@ -1926,11 +1898,8 @@ void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *param,
/* Convert an IP address in an SCTP param into a sockaddr_in. */ /* Convert an IP address in an SCTP param into a sockaddr_in. */
/* Returns true if a valid conversion was possible. */ /* Returns true if a valid conversion was possible. */
int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa)
{ {
if (!p.v)
return 0;
switch (p.p->type) { switch (p.p->type) {
case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV4_ADDRESS:
sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr);
...@@ -1950,30 +1919,10 @@ int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) ...@@ -1950,30 +1919,10 @@ int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa)
return 1; return 1;
} }
/* Convert from an IP version number to an Address Family symbol. */
int ipver2af(__u8 ipver)
{
int family;
switch (ipver) {
case 4:
family = AF_INET;
break;
case 6:
family = AF_INET6;
break;
default:
family = 0;
break;
};
return family;
}
/* Convert a sockaddr_in to an IP address in an SCTP param. /* Convert a sockaddr_in to an IP address in an SCTP param.
* Returns len if a valid conversion was possible. * Returns len if a valid conversion was possible.
*/ */
int sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctp_addr_param_t *p) int sockaddr2sctp_addr(const union sctp_addr *sa, sctp_addr_param_t *p)
{ {
int len = 0; int len = 0;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -68,11 +69,13 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, ...@@ -68,11 +69,13 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc, static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_event_t event_type, sctp_chunk_t *chunk); sctp_event_t event_type, sctp_chunk_t *chunk);
static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, static int sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
int priority); int priority);
static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *);
static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *, sctp_association_t *,
sctp_transport_t *);
static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *,
sctp_bind_addr_t *); sctp_bind_addr_t *);
static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *,
...@@ -83,6 +86,8 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, ...@@ -83,6 +86,8 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *,
sctp_sackhdr_t *); sctp_sackhdr_t *);
static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *,
sctp_chunk_t *); sctp_chunk_t *);
static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *,
sctp_state_t);
/* These three macros allow us to pull the debugging code out of the /* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real * main flow of sctp_do_sm() to keep attention focused on the real
...@@ -193,6 +198,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -193,6 +198,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
/* BUG--we should now recover some memory, probably by /* BUG--we should now recover some memory, probably by
* reneging... * reneging...
*/ */
error = -ENOMEM;
break; break;
case SCTP_DISPOSITION_DELETE_TCB: case SCTP_DISPOSITION_DELETE_TCB:
...@@ -301,8 +307,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -301,8 +307,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_NEW_STATE: case SCTP_CMD_NEW_STATE:
/* Enter a new state. */ /* Enter a new state. */
asoc->state = command->obj.state; sctp_cmd_new_state(commands, asoc, command->obj.state);
asoc->state_timestamp = jiffies;
break; break;
case SCTP_CMD_REPORT_TSN: case SCTP_CMD_REPORT_TSN:
...@@ -339,9 +344,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -339,9 +344,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_PEER_INIT: case SCTP_CMD_PEER_INIT:
/* Process a unified INIT from the peer. */ /* Process a unified INIT from the peer.
sctp_cmd_process_init(commands, asoc, chunk, * Note: Only used during INIT-ACK processing. If
command->obj.ptr, priority); * there is an error just return to the outter
* layer which will bail.
*/
error = sctp_cmd_process_init(commands, asoc, chunk,
command->obj.ptr,
priority);
break; break;
case SCTP_CMD_GEN_COOKIE_ECHO: case SCTP_CMD_GEN_COOKIE_ECHO:
...@@ -561,6 +571,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -561,6 +571,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_hb_timers_start(commands, asoc); sctp_cmd_hb_timers_start(commands, asoc);
break; break;
case SCTP_CMD_HB_TIMERS_UPDATE:
t = command->obj.transport;
sctp_cmd_hb_timers_update(commands, asoc, t);
break;
case SCTP_CMD_REPORT_ERROR: case SCTP_CMD_REPORT_ERROR:
error = command->obj.error; error = command->obj.error;
break; break;
...@@ -581,11 +596,18 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -581,11 +596,18 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
chunk->pdiscard = 1; chunk->pdiscard = 1;
break; break;
case SCTP_CMD_RTO_PENDING:
t = command->obj.transport;
t->rto_pending = 1;
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
command->verb, command->obj.ptr); command->verb, command->obj.ptr);
break; break;
}; };
if (error)
return error;
} }
return error; return error;
...@@ -648,7 +670,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, ...@@ -648,7 +670,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
} }
/* Always try to quiet the other end. In case of lost CWR, /* Always try to quiet the other end. In case of lost CWR,
* resend last_cwr_tsn. * resend last_cwr_tsn.
*/ */
repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
...@@ -978,7 +1000,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, ...@@ -978,7 +1000,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
*/ */
asoc->overall_error_count++; asoc->overall_error_count++;
if (transport->state.active && if (transport->active &&
(transport->error_count++ >= transport->error_threshold)) { (transport->error_count++ >= transport->error_threshold)) {
SCTP_DEBUG_PRINTK("transport_strike: transport " SCTP_DEBUG_PRINTK("transport_strike: transport "
"IP:%d.%d.%d.%d failed.\n", "IP:%d.%d.%d.%d failed.\n",
...@@ -1058,22 +1080,32 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1058,22 +1080,32 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
} }
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT /* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
* inside the cookie. * inside the cookie. In reality, this is only used for INIT-ACK processing
* since all other cases use "temporary" associations and can do all
* their work in statefuns directly.
*/ */
static void sctp_cmd_process_init(sctp_cmd_seq_t *commands, static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
sctp_association_t *asoc, sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
int priority) int priority)
{ {
/* The command sequence holds commands assuming that the int error;
* processing will happen successfully. If this is not the
* case, rewind the sequence and add appropriate error handling /* We only process the init as a sideeffect in a single
* to the sequence. * case. This is when we process the INIT-ACK. If we
* fail during INIT processing (due to malloc problems),
* just return the error and stop processing the stack.
*/ */
sctp_process_init(asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, if (!sctp_process_init(asoc, chunk->chunk_hdr->type,
priority); sctp_source(chunk), peer_init,
priority))
error = -ENOMEM;
else
error = 0;
return error;
} }
/* Helper function to break out starting up of heartbeat timers. */ /* Helper function to break out starting up of heartbeat timers. */
...@@ -1096,6 +1128,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, ...@@ -1096,6 +1128,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
} }
} }
/* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc,
sctp_transport_t *t)
{
/* Update the heartbeat timer. */
if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies))
sctp_transport_hold(t);
}
/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ /* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */
void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
sctp_bind_addr_t *bp) sctp_bind_addr_t *bp)
...@@ -1131,7 +1173,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, ...@@ -1131,7 +1173,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
/* Mark the destination transport address as active if it is not so /* Mark the destination transport address as active if it is not so
* marked. * marked.
*/ */
if (!t->state.active) if (!t->active)
sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
SCTP_HEARTBEAT_SUCCESS); SCTP_HEARTBEAT_SUCCESS);
...@@ -1154,10 +1196,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, ...@@ -1154,10 +1196,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
/* Mark one strike against a transport. */ /* Mark one strike against a transport. */
sctp_do_8_2_transport_strike(asoc, t); sctp_do_8_2_transport_strike(asoc, t);
/* Update the heartbeat timer. */
if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies))
sctp_transport_hold(t);
} }
/* Helper function to process the process SACK command. */ /* Helper function to process the process SACK command. */
...@@ -1196,3 +1234,18 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, ...@@ -1196,3 +1234,18 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
chunk->transport = t; chunk->transport = t;
} }
/* Helper function to change the state of an association. */
static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
sctp_state_t state)
{
asoc->state = state;
asoc->state_timestamp = jiffies;
/* Wake up any process waiting for the association to
* get established.
*/
if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
(waitqueue_active(&asoc->wait)))
wake_up_interruptible(&asoc->wait);
}
...@@ -236,20 +236,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -236,20 +236,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data;
/* Tag the variable length parameters. */ /* Tag the variable length parameters. */
chunk->param_hdr.v = chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC);
if (!new_asoc) if (!new_asoc)
goto nomem; goto nomem;
/* FIXME: sctp_process_init can fail, but there is no /* The call, sctp_process_init(), can fail on memory allocation. */
* status nor handling. if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
*/ sctp_source(chunk),
sctp_process_init(new_asoc, chunk->chunk_hdr->type, (sctp_init_chunk_t *)chunk->chunk_hdr,
sctp_source(chunk), GFP_ATOMIC))
(sctp_init_chunk_t *)chunk->chunk_hdr, goto nomem_init;
GFP_ATOMIC);
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
...@@ -302,10 +300,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -302,10 +300,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
nomem_ack: nomem_ack:
sctp_association_free(new_asoc);
if (err_chunk) if (err_chunk)
sctp_free_chunk(err_chunk); sctp_free_chunk(err_chunk);
nomem_init:
sctp_association_free(new_asoc);
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
...@@ -563,9 +561,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -563,9 +561,11 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
* effects--it is safe to run them here. * effects--it is safe to run them here.
*/ */
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
sctp_process_init(new_asoc, chunk->chunk_hdr->type,
&chunk->subh.cookie_hdr->c.peer_addr, peer_init, if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
GFP_ATOMIC); &chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
goto nomem_init;
repl = sctp_make_cookie_ack(new_asoc, chunk); repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl) if (!repl)
...@@ -592,10 +592,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -592,10 +592,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
nomem_ev: nomem_ev:
sctp_free_chunk(repl); sctp_free_chunk(repl);
nomem_repl: nomem_repl:
nomem_init:
sctp_association_free(new_asoc); sctp_association_free(new_asoc);
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
...@@ -664,6 +663,39 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, ...@@ -664,6 +663,39 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
/* Generate and sendout a heartbeat packet. */
sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_transport_t *transport = (sctp_transport_t *) arg;
sctp_chunk_t *reply;
sctp_sender_hb_info_t hbinfo;
size_t paylen = 0;
hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
hbinfo.daddr = transport->ipaddr;
hbinfo.sent_at = jiffies;
/* Send a heartbeat to our peer. */
paylen = sizeof(sctp_sender_hb_info_t);
reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);
if (!reply)
return SCTP_DISPOSITION_NOMEM;
/* Set rto_pending indicating that an RTT measurement
* is started with this heartbeat chunk.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_RTO_PENDING,
SCTP_TRANSPORT(transport));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
}
/* Generate a HEARTBEAT packet on the given transport. */ /* Generate a HEARTBEAT packet on the given transport. */
sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
const sctp_association_t *asoc, const sctp_association_t *asoc,
...@@ -672,9 +704,6 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, ...@@ -672,9 +704,6 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_transport_t *transport = (sctp_transport_t *) arg; sctp_transport_t *transport = (sctp_transport_t *) arg;
sctp_chunk_t *reply;
sctp_sender_hb_info_t hbinfo;
size_t paylen = 0;
if (asoc->overall_error_count >= asoc->overall_error_threshold) { if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
...@@ -689,34 +718,21 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, ...@@ -689,34 +718,21 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
* HEARTBEAT is sent (see Section 8.3). * HEARTBEAT is sent (see Section 8.3).
*/ */
hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; if (transport->hb_allowed) {
hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); if (SCTP_DISPOSITION_NOMEM ==
hbinfo.daddr = transport->ipaddr; sctp_sf_heartbeat(ep, asoc, type, arg,
hbinfo.sent_at = jiffies; commands))
return SCTP_DISPOSITION_NOMEM;
/* Set rto_pending indicating that an RTT measurement is started /* Set transport error counter and association error counter
* with this heartbeat chunk. * when sending heartbeat.
*/ */
transport->rto_pending = 1; sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
SCTP_TRANSPORT(transport));
/* Send a heartbeat to our peer. */ }
paylen = sizeof(sctp_sender_hb_info_t); sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_UPDATE,
reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
/* Set transport error counter and association error counter
* when sending heartbeat.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
SCTP_TRANSPORT(transport)); SCTP_TRANSPORT(transport));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
} }
/* /*
...@@ -817,7 +833,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, ...@@ -817,7 +833,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sockaddr_storage_t from_addr; union sctp_addr from_addr;
sctp_transport_t *link; sctp_transport_t *link;
sctp_sender_hb_info_t *hbinfo; sctp_sender_hb_info_t *hbinfo;
unsigned long max_interval; unsigned long max_interval;
...@@ -866,7 +882,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, ...@@ -866,7 +882,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
/* Helper function to send out an abort for the restart /* Helper function to send out an abort for the restart
* condition. * condition.
*/ */
static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa, static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
sctp_chunk_t *init, sctp_chunk_t *init,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
...@@ -1125,8 +1141,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1125,8 +1141,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* Verification Tag and Peers Verification tag into a reserved * Verification Tag and Peers Verification tag into a reserved
* place (local tie-tag and per tie-tag) within the state cookie. * place (local tie-tag and per tie-tag) within the state cookie.
*/ */
sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk), if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
(sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC); sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC)) {
retval = SCTP_DISPOSITION_NOMEM;
goto nomem_init;
}
/* Make sure no new addresses are being added during the /* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state, * restart. Do not do this check for COOKIE-WAIT state,
...@@ -1197,6 +1218,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1197,6 +1218,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
nomem: nomem:
retval = SCTP_DISPOSITION_NOMEM; retval = SCTP_DISPOSITION_NOMEM;
goto cleanup; goto cleanup;
nomem_init:
cleanup_asoc: cleanup_asoc:
sctp_association_free(new_asoc); sctp_association_free(new_asoc);
goto cleanup; goto cleanup;
...@@ -1326,15 +1348,16 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -1326,15 +1348,16 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
* side effects--it is safe to run them here. * side effects--it is safe to run them here.
*/ */
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, GFP_ATOMIC); if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, GFP_ATOMIC))
goto nomem;
/* Make sure no new addresses are being added during the /* Make sure no new addresses are being added during the
* restart. Though this is a pretty complicated attack * restart. Though this is a pretty complicated attack
* since you'd have to get inside the cookie. * since you'd have to get inside the cookie.
*/ */
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
printk("cookie echo check\n");
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -1391,8 +1414,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, ...@@ -1391,8 +1414,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
* side effects--it is safe to run them here. * side effects--it is safe to run them here.
*/ */
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
sctp_process_init(new_asoc, chunk->chunk_hdr->type, if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, GFP_ATOMIC); sctp_source(chunk), peer_init, GFP_ATOMIC))
goto nomem;
/* Update the content of current association. */ /* Update the content of current association. */
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
...@@ -3656,6 +3680,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( ...@@ -3656,6 +3680,39 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands); return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands);
} }
/*
* Process the REQUESTHEARTBEAT primitive
*
* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
return sctp_sf_heartbeat(ep, asoc, type, (sctp_transport_t *)arg,
commands);
}
/* /*
* Ignore the primitive event * Ignore the primitive event
* *
...@@ -4257,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, ...@@ -4257,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
/* Cache a route for the transport with the chunk's destination as /* Cache a route for the transport with the chunk's destination as
* the source address. * the source address.
*/ */
sctp_transport_route(transport, (sockaddr_storage_t *)&chunk->dest); sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
sctp_sk(sctp_get_ctl_sock()));
packet = sctp_packet_init(packet, transport, sport, dport); packet = sctp_packet_init(packet, transport, sport, dport);
packet = sctp_packet_config(packet, vtag, 0, NULL); packet = sctp_packet_config(packet, vtag, 0, NULL);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { ...@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ #define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
......
...@@ -86,15 +86,16 @@ static void sctp_wfree(struct sk_buff *skb); ...@@ -86,15 +86,16 @@ static void sctp_wfree(struct sk_buff *skb);
static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
int msg_len); int msg_len);
static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p);
static inline void sctp_sk_addr_set(struct sock *, static inline void sctp_sk_addr_set(struct sock *,
const sockaddr_storage_t *newaddr, const union sctp_addr *newaddr,
sockaddr_storage_t *saveaddr); union sctp_addr *saveaddr);
static inline void sctp_sk_addr_restore(struct sock *, static inline void sctp_sk_addr_restore(struct sock *,
const sockaddr_storage_t *); const union sctp_addr *);
static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); static inline int sctp_verify_addr(struct sock *, struct sockaddr *, int);
static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
static int sctp_do_bind(struct sock *, sockaddr_storage_t *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int);
static int sctp_autobind(struct sock *sk); static int sctp_autobind(struct sock *sk);
...@@ -122,7 +123,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -122,7 +123,7 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
/* Disallow binding twice. */ /* Disallow binding twice. */
if (!sctp_sk(sk)->ep->base.bind_addr.port) if (!sctp_sk(sk)->ep->base.bind_addr.port)
retval = sctp_do_bind(sk, (sockaddr_storage_t *)uaddr, retval = sctp_do_bind(sk, (union sctp_addr *)uaddr,
addr_len); addr_len);
else else
retval = -EINVAL; retval = -EINVAL;
...@@ -135,14 +136,14 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -135,14 +136,14 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
static long sctp_get_port_local(struct sock *, unsigned short); static long sctp_get_port_local(struct sock *, unsigned short);
/* Bind a local address either to an endpoint or to an association. */ /* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr,
int addr_len) int addr_len)
{ {
sctp_opt_t *sp = sctp_sk(sk); sctp_opt_t *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; sctp_endpoint_t *ep = sp->ep;
sctp_bind_addr_t *bp = &ep->base.bind_addr; sctp_bind_addr_t *bp = &ep->base.bind_addr;
unsigned short sa_family = newaddr->sa.sa_family; unsigned short sa_family = newaddr->sa.sa_family;
sockaddr_storage_t tmpaddr, saveaddr; union sctp_addr tmpaddr, saveaddr;
unsigned short *snum; unsigned short *snum;
int ret = 0; int ret = 0;
...@@ -403,7 +404,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -403,7 +404,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
goto err_bindx_add; goto err_bindx_add;
}; };
retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], retval = sctp_do_bind(sk, (union sctp_addr *)&addrs[cnt],
addr_len); addr_len);
err_bindx_add: err_bindx_add:
...@@ -481,7 +482,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -481,7 +482,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
int cnt; int cnt;
sctp_bind_addr_t *bp = &ep->base.bind_addr; sctp_bind_addr_t *bp = &ep->base.bind_addr;
int retval = 0; int retval = 0;
sockaddr_storage_t saveaddr; union sctp_addr saveaddr;
SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n",
sk, addrs, addrcnt); sk, addrs, addrcnt);
...@@ -500,7 +501,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -500,7 +501,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*/ */
switch (((struct sockaddr *)&addrs[cnt])->sa_family) { switch (((struct sockaddr *)&addrs[cnt])->sa_family) {
case AF_INET: case AF_INET:
saveaddr = *((sockaddr_storage_t *) saveaddr = *((union sctp_addr *)
&addrs[cnt]); &addrs[cnt]);
saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port); saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
/* Verify the port. */ /* Verify the port. */
...@@ -511,7 +512,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -511,7 +512,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
break; break;
case AF_INET6: case AF_INET6:
saveaddr = *((sockaddr_storage_t *) saveaddr = *((union sctp_addr *)
&addrs[cnt]); &addrs[cnt]);
saveaddr.v6.sin6_port = saveaddr.v6.sin6_port =
ntohs(saveaddr.v6.sin6_port); ntohs(saveaddr.v6.sin6_port);
...@@ -741,7 +742,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -741,7 +742,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_association_t *new_asoc=NULL, *asoc=NULL; sctp_association_t *new_asoc=NULL, *asoc=NULL;
sctp_transport_t *transport; sctp_transport_t *transport;
sctp_chunk_t *chunk = NULL; sctp_chunk_t *chunk = NULL;
sockaddr_storage_t to; union sctp_addr to;
struct sockaddr *msg_name = NULL; struct sockaddr *msg_name = NULL;
struct sctp_sndrcvinfo default_sinfo = { 0 }; struct sctp_sndrcvinfo default_sinfo = { 0 };
struct sctp_sndrcvinfo *sinfo; struct sctp_sndrcvinfo *sinfo;
...@@ -777,7 +778,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -777,7 +778,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* For a peeled-off socket, msg_name is ignored. * For a peeled-off socket, msg_name is ignored.
*/ */
if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) {
err = sctp_sendmsg_verify_name(sk, msg); err = sctp_verify_addr(sk, (struct sockaddr *)msg->msg_name,
msg->msg_namelen);
if (err) if (err)
return err; return err;
...@@ -826,28 +828,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -826,28 +828,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* Look for a matching association on the endpoint. */ /* Look for a matching association on the endpoint. */
asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
if (!asoc) { if (!asoc) {
struct list_head *pos; /* If we could not find a matching association on the
struct sockaddr_storage_list *addr; * endpoint, make sure that there is no peeled-off
sctp_bind_addr_t *bp = &ep->base.bind_addr; * association on another socket.
*/
sctp_read_lock(&ep->base.addr_lock); if (sctp_endpoint_is_peeled_off(ep, &to)) {
err = -EADDRNOTAVAIL;
/* If we could not find a matching association on goto out_unlock;
* the endpoint, make sure that there is no peeled-
* off association.
*/
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos,
struct sockaddr_storage_list,
list);
if (sctp_has_association(&addr->a, &to)) {
err = -EINVAL;
sctp_read_unlock(&ep->base.addr_lock);
goto out_unlock;
}
} }
sctp_read_unlock(&ep->base.addr_lock);
} }
} else { } else {
/* For a peeled-off socket, ignore any associd specified by /* For a peeled-off socket, ignore any associd specified by
...@@ -1116,6 +1104,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1116,6 +1104,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
#endif /* 0 */ #endif /* 0 */
} }
/* This is an extended version of skb_pull() that removes the data from the
* start of a skb even when data is spread across the list of skb's in the
* frag_list. len specifies the total amount of data that needs to be removed.
* when 'len' bytes could be removed from the skb, it returns 0.
* If 'len' exceeds the total skb length, it returns the no. of bytes that
* could not be removed.
*/
static int sctp_skb_pull(struct sk_buff *skb, int len)
{
struct sk_buff *list;
if (len <= skb->len) {
__skb_pull(skb, len);
return 0;
}
len -= skb->len;
__skb_pull(skb, skb->len);
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
len = sctp_skb_pull(list, len);
if (!len)
return 0;
}
return len;
}
/* API 3.1.3 recvmsg() - UDP Style Syntax /* API 3.1.3 recvmsg() - UDP Style Syntax
* *
* ssize_t recvmsg(int socket, struct msghdr *message, * ssize_t recvmsg(int socket, struct msghdr *message,
...@@ -1138,9 +1153,10 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1138,9 +1153,10 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
{ {
sctp_ulpevent_t *event = NULL; sctp_ulpevent_t *event = NULL;
sctp_opt_t *sp = sctp_sk(sk); sctp_opt_t *sp = sctp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb, *list;
int copied; int copied;
int err = 0; int err = 0;
int skb_len;
SCTP_DEBUG_PRINTK("sctp_recvmsg(" SCTP_DEBUG_PRINTK("sctp_recvmsg("
"%s: %p, %s: %p, %s: %d, %s: %d, %s: " "%s: %p, %s: %p, %s: %d, %s: %d, %s: "
...@@ -1157,21 +1173,16 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1157,21 +1173,16 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
if (!skb) if (!skb)
goto out; goto out;
copied = skb->len; /* Get the total length of the skb including any skb's in the
* frag_list.
*/
skb_len = skb->len;
for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
skb_len += list->len;
if (skb_shinfo(skb)->frag_list) { copied = skb_len;
struct sk_buff *list; if (copied > len)
for (list = skb_shinfo(skb)->frag_list;
list;
list = list->next)
copied += list->len;
}
if (copied > len) {
copied = len; copied = len;
msg->msg_flags |= MSG_TRUNC;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
...@@ -1199,8 +1210,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1199,8 +1210,19 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
err = copied; err = copied;
/* FIXME: We need to support MSG_EOR correctly. */ /* If skb's length exceeds the user's buffer, update the skb and
msg->msg_flags |= MSG_EOR; * push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
*/
if (skb_len > copied) {
sctp_skb_pull(skb, copied);
skb_queue_head(&sk->receive_queue, skb);
msg->msg_flags &= ~MSG_EOR;
goto out;
} else {
msg->msg_flags |= MSG_EOR;
}
out_free: out_free:
sctp_ulpevent_free(event); /* Free the skb. */ sctp_ulpevent_free(event); /* Free the skb. */
...@@ -1252,6 +1274,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1252,6 +1274,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return 0; return 0;
} }
static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
char *optval,
int optlen)
{
struct sctp_paddrparams params;
sctp_association_t *asoc;
union sctp_addr *addr;
sctp_transport_t *trans;
int error;
if (optlen != sizeof(struct sctp_paddrparams))
return -EINVAL;
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id);
if (!asoc)
return -EINVAL;
addr = (union sctp_addr *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans)
return -ENOENT;
/* Applications can enable or disable heartbeats for any peer address
* of an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable.
*
* The value of the heartbeat interval, in milliseconds. A value of
* UINT32_MAX (4294967295), when modifying the parameter, specifies
* that a heartbeat should be sent immediately to the peer address,
* and the current interval should remain unchanged.
*/
if (0xffffffff == params.spp_hbinterval) {
error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans);
if (error)
return error;
}
else {
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
* address should be disabled.
*/
if (params.spp_hbinterval) {
trans->hb_allowed = 1;
trans->hb_interval = params.spp_hbinterval * HZ / 1000;
} else
trans->hb_allowed = 0;
}
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
trans->error_threshold = params.spp_pathmaxrxt;
return 0;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -1342,6 +1425,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1342,6 +1425,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_autoclose(sk, optval, optlen); retval = sctp_setsockopt_autoclose(sk, optval, optlen);
break; break;
case SCTP_SET_PEER_ADDR_PARAMS:
retval = sctp_setsockopt_set_peer_addr_params(sk, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -1354,11 +1442,107 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1354,11 +1442,107 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
return retval; return retval;
} }
/* FIXME: Write comments. */ /* API 3.1.6 connect() - UDP Style Syntax
*
* An application may use the connect() call in the UDP model to initiate an
* association without sending data.
*
* The syntax is:
*
* ret = connect(int sd, const struct sockaddr *nam, socklen_t len);
*
* sd: the socket descriptor to have a new association added to.
*
* nam: the address structure (either struct sockaddr_in or struct
* sockaddr_in6 defined in RFC2553 [7]).
*
* len: the size of the address.
*/
SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len) int addr_len)
{ {
return -EOPNOTSUPP; /* STUB */ sctp_opt_t *sp;
sctp_endpoint_t *ep;
sctp_association_t *asoc;
sctp_transport_t *transport;
union sctp_addr to;
sctp_scope_t scope;
long timeo;
int err = 0;
sctp_lock_sock(sk);
SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d)\n",
__FUNCTION__, sk, uaddr, addr_len);
sp = sctp_sk(sk);
ep = sp->ep;
/* connect() cannot be done on a peeled-off socket. */
if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) {
err = -EISCONN;
goto out_unlock;
}
err = sctp_verify_addr(sk, uaddr, addr_len);
if (err)
goto out_unlock;
memcpy(&to, uaddr, addr_len);
to.v4.sin_port = ntohs(to.v4.sin_port);
asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
if (asoc) {
if (asoc->state >= SCTP_STATE_ESTABLISHED)
err = -EISCONN;
else
err = -EALREADY;
goto out_unlock;
}
/* If we could not find a matching association on the endpoint,
* make sure that there is no peeled-off association matching the
* peer address even on another socket.
*/
if (sctp_endpoint_is_peeled_off(ep, &to)) {
err = -EADDRNOTAVAIL;
goto out_unlock;
}
/* If a bind() or sctp_bindx() is not called prior to a connect()
* call, the system picks an ephemeral port and will choose an address
* set equivalent to binding with a wildcard address.
*/
if (!ep->base.bind_addr.port) {
if (sctp_autobind(sk)) {
err = -EAGAIN;
goto out_unlock;
}
}
scope = sctp_scope(&to);
asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
if (!asoc) {
err = -ENOMEM;
goto out_unlock;
}
/* Prime the peer's transport structures. */
transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL);
err = sctp_primitive_ASSOCIATE(asoc, NULL);
if (err < 0) {
sctp_association_free(asoc);
goto out_unlock;
}
timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
err = sctp_wait_for_connect(asoc, &timeo);
out_unlock:
sctp_release_sock(sk);
return err;
} }
/* FIXME: Write comments. */ /* FIXME: Write comments. */
...@@ -1503,28 +1687,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1503,28 +1687,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (len != sizeof(status)) { if (len != sizeof(status)) {
retval = -EINVAL; retval = -EINVAL;
goto out_nounlock; goto out;
} }
if (copy_from_user(&status, optval, sizeof(status))) { if (copy_from_user(&status, optval, sizeof(status))) {
retval = -EFAULT; retval = -EFAULT;
goto out_nounlock; goto out;
} }
sctp_lock_sock(sk);
associd = status.sstat_assoc_id; associd = status.sstat_assoc_id;
if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) { if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) {
assoc = sctp_id2assoc(sk, associd); assoc = sctp_id2assoc(sk, associd);
if (!assoc) { if (!assoc) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
} else { } else {
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
if (list_empty(&ep->asocs)) { if (list_empty(&ep->asocs)) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); assoc = list_entry(ep->asocs.next, sctp_association_t, asocs);
...@@ -1542,8 +1724,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1542,8 +1724,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_fragmentation_point = assoc->frag_point; status.sstat_fragmentation_point = assoc->frag_point;
status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
memcpy(&status.sstat_primary.spinfo_address, memcpy(&status.sstat_primary.spinfo_address,
&(transport->ipaddr), sizeof(sockaddr_storage_t)); &(transport->ipaddr), sizeof(union sctp_addr));
status.sstat_primary.spinfo_state = transport->state.active; status.sstat_primary.spinfo_state = transport->active;
status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_cwnd = transport->cwnd;
status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_srtt = transport->srtt;
status.sstat_primary.spinfo_rto = transport->rto; status.sstat_primary.spinfo_rto = transport->rto;
...@@ -1551,7 +1733,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1551,7 +1733,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
retval = -EFAULT; retval = -EFAULT;
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n",
...@@ -1560,13 +1742,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1560,13 +1742,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (copy_to_user(optval, &status, len)) { if (copy_to_user(optval, &status, len)) {
retval = -EFAULT; retval = -EFAULT;
goto out_unlock; goto out;
} }
out_unlock: out:
sctp_release_sock(sk);
out_nounlock:
return (retval); return (retval);
} }
...@@ -1684,25 +1863,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval ...@@ -1684,25 +1863,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if (copy_from_user(&peeloff, optval, len)) if (copy_from_user(&peeloff, optval, len))
return -EFAULT; return -EFAULT;
sctp_lock_sock(sk);
assoc = sctp_id2assoc(sk, peeloff.associd); assoc = sctp_id2assoc(sk, peeloff.associd);
if (NULL == assoc) { if (NULL == assoc) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc);
retval = sctp_do_peeloff(assoc, &newsock); retval = sctp_do_peeloff(assoc, &newsock);
if (retval < 0) if (retval < 0)
goto out_unlock; goto out;
/* Map the socket to an unused fd that can be returned to the user. */ /* Map the socket to an unused fd that can be returned to the user. */
retval = sock_map_fd(newsock); retval = sock_map_fd(newsock);
if (retval < 0) { if (retval < 0) {
sock_release(newsock); sock_release(newsock);
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n",
...@@ -1713,11 +1890,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval ...@@ -1713,11 +1890,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if (copy_to_user(optval, &peeloff, len)) if (copy_to_user(optval, &peeloff, len))
retval = -EFAULT; retval = -EFAULT;
out_unlock: out:
sctp_release_sock(sk);
return retval; return retval;
} }
static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
int len, char *optval, int *optlen)
{
struct sctp_paddrparams params;
sctp_association_t *asoc;
union sctp_addr *addr;
sctp_transport_t *trans;
if (len != sizeof(struct sctp_paddrparams))
return -EINVAL;
if (copy_from_user(&params, optval, *optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id);
if (!asoc)
return -EINVAL;
addr = (union sctp_addr *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans)
return -ENOENT;
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
* address should be disabled.
*/
if (!trans->hb_allowed)
params.spp_hbinterval = 0;
else
params.spp_hbinterval = trans->hb_interval * 1000 / HZ;
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
params.spp_pathmaxrxt = trans->error_threshold;
if (copy_to_user(optval, &params, len))
return -EFAULT;
*optlen = len;
return 0;
}
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
...@@ -1748,6 +1968,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1748,6 +1968,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; return -EFAULT;
sctp_lock_sock(sk);
switch (optname) { switch (optname) {
case SCTP_STATUS: case SCTP_STATUS:
retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
...@@ -1770,11 +1992,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1770,11 +1992,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
break; break;
case SCTP_GET_PEER_ADDR_PARAMS:
retval = sctp_getsockopt_get_peer_addr_params(sk, len, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
}; };
sctp_release_sock(sk);
return retval; return retval;
} }
...@@ -1880,7 +2108,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1880,7 +2108,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* socket is going to be sk2. * socket is going to be sk2.
*/ */
int sk_reuse = sk->reuse; int sk_reuse = sk->reuse;
sockaddr_storage_t tmpaddr; union sctp_addr tmpaddr;
struct sock *sk2 = pp->sk; struct sock *sk2 = pp->sk;
SCTP_DEBUG_PRINTK("sctp_get_port() found a " SCTP_DEBUG_PRINTK("sctp_get_port() found a "
...@@ -1923,12 +2151,13 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1923,12 +2151,13 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
sctp_endpoint_t *ep2; sctp_endpoint_t *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
if (!sk_reuse || !sk2->reuse) { if (sk_reuse && sk2->reuse)
if (sctp_bind_addr_has_addr( continue;
&ep2->base.bind_addr, &tmpaddr)) {
goto found; if (sctp_bind_addr_match(&ep2->base.bind_addr,
} &tmpaddr,
} sctp_sk(sk)))
goto found;
} }
found: found:
...@@ -2183,34 +2412,17 @@ void sctp_put_port(struct sock *sk) ...@@ -2183,34 +2412,17 @@ void sctp_put_port(struct sock *sk)
*/ */
static int sctp_autobind(struct sock *sk) static int sctp_autobind(struct sock *sk)
{ {
sockaddr_storage_t autoaddr; union sctp_addr autoaddr;
int addr_len = 0; struct sctp_func *af;
unsigned short port;
memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); /* Initialize a local sockaddr structure to INADDR_ANY. */
af = sctp_sk(sk)->pf->af;
switch (sk->family) {
case PF_INET:
autoaddr.v4.sin_family = AF_INET;
autoaddr.v4.sin_addr.s_addr = INADDR_ANY;
autoaddr.v4.sin_port = htons(inet_sk(sk)->num);
addr_len = sizeof(struct sockaddr_in);
break;
case PF_INET6: port = htons(inet_sk(sk)->num);
SCTP_V6( af->inaddr_any(&autoaddr, port);
/* FIXME: Write me for v6! */
BUG();
autoaddr.v6.sin6_family = AF_INET6;
autoaddr.v6.sin6_port = htons(inet_sk(sk)->num);
addr_len = sizeof(struct sockaddr_in6);
);
break;
default: /* This should not happen. */ return sctp_do_bind(sk, &autoaddr, af->sockaddr_len);
break;
};
return sctp_do_bind(sk, &autoaddr, addr_len);
} }
/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation.
...@@ -2327,8 +2539,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -2327,8 +2539,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
/* Setup sk->rcv_saddr before calling get_port(). */ /* Setup sk->rcv_saddr before calling get_port(). */
static inline void sctp_sk_addr_set(struct sock *sk, static inline void sctp_sk_addr_set(struct sock *sk,
const sockaddr_storage_t *newaddr, const union sctp_addr *newaddr,
sockaddr_storage_t *saveaddr) union sctp_addr *saveaddr)
{ {
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
...@@ -2355,7 +2567,7 @@ static inline void sctp_sk_addr_set(struct sock *sk, ...@@ -2355,7 +2567,7 @@ static inline void sctp_sk_addr_set(struct sock *sk,
} }
/* Restore sk->rcv_saddr after failing get_port(). */ /* Restore sk->rcv_saddr after failing get_port(). */
static inline void sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) static inline void sctp_sk_addr_restore(struct sock *sk, const union sctp_addr *addr)
{ {
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
...@@ -2498,38 +2710,33 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -2498,38 +2710,33 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
return NULL; return NULL;
} }
static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) /* Verify that this is a valid address. */
static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len)
{ {
sockaddr_storage_t *sa; struct sctp_func *af;
if (msg->msg_namelen < sizeof (struct sockaddr)) /* Check minimum size. */
if (len < sizeof (struct sockaddr))
return -EINVAL; return -EINVAL;
sa = (sockaddr_storage_t *) msg->msg_name; /* Do we support this address family in general? */
switch (sa->sa.sa_family) { af = sctp_get_af_specific(addr->sa_family);
case AF_INET: if (!af)
if (msg->msg_namelen < sizeof(struct sockaddr_in)) return -EINVAL;
return -EINVAL;
break;
case AF_INET6:
if (PF_INET == sk->family)
return -EINVAL;
SCTP_V6(
if (msg->msg_namelen < sizeof(struct sockaddr_in6))
return -EINVAL;
break;
);
default: /* Does this PF support this AF? */
if (!sctp_sk(sk)->pf->af_supported(addr->sa_family))
return -EINVAL;
/* Verify the minimum for this AF sockaddr. */
if (len < af->sockaddr_len)
return -EINVAL; return -EINVAL;
};
/* Disallow any illegal addresses to be used as destinations. */ /* Is this a valid SCTP address? */
if (!sctp_addr_is_valid(sa)) if (!af->addr_valid((union sctp_addr *)addr))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
/* Get the sndbuf space available at the time on the association. */ /* Get the sndbuf space available at the time on the association. */
...@@ -2710,6 +2917,70 @@ static int sctp_writeable(struct sock *sk) ...@@ -2710,6 +2917,70 @@ static int sctp_writeable(struct sock *sk)
return amt; return amt;
} }
/* Wait for an association to go into ESTABLISHED state. If timeout is 0,
* returns immediately with EINPROGRESS.
*/
static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
{
struct sock *sk = asoc->base.sk;
int err = 0;
long current_timeo = *timeo_p;
DECLARE_WAITQUEUE(wait, current);
SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
(long)(*timeo_p));
add_wait_queue_exclusive(&asoc->wait, &wait);
/* Increment the association's refcnt. */
sctp_association_hold(asoc);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!*timeo_p)
goto do_nonblock;
if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
asoc->base.dead)
goto do_error;
if (signal_pending(current))
goto do_interrupted;
if (asoc->state == SCTP_STATE_ESTABLISHED)
break;
/* Let another process have a go. Since we are going
* to sleep anyway.
*/
sctp_release_sock(sk);
current_timeo = schedule_timeout(current_timeo);
sctp_lock_sock(sk);
*timeo_p = current_timeo;
}
out:
remove_wait_queue(&asoc->wait, &wait);
/* Release the association's refcnt. */
sctp_association_put(asoc);
__set_current_state(TASK_RUNNING);
return err;
do_error:
err = -ECONNABORTED;
goto out;
do_interrupted:
err = sock_intr_errno(*timeo_p);
goto out;
do_nonblock:
err = -EINPROGRESS;
goto out;
}
/* This proto struct describes the ULP interface for SCTP. */ /* This proto struct describes the ULP interface for SCTP. */
struct proto sctp_prot = { struct proto sctp_prot = {
.name = "SCTP", .name = "SCTP",
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* This module provides the abstraction for an SCTP tranport representing * This module provides the abstraction for an SCTP tranport representing
* a remote transport address. For local transport addresses, we just use * a remote transport address. For local transport addresses, we just use
* sockaddr_storage_t. * union sctp_addr.
* *
* 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 * you can redistribute it and/or modify it under the terms of
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
/* 1st Level Abstractions. */ /* 1st Level Abstractions. */
/* Allocate and initialize a new transport. */ /* Allocate and initialize a new transport. */
sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priority) sctp_transport_t *sctp_transport_new(const union sctp_addr *addr, int priority)
{ {
sctp_transport_t *transport; sctp_transport_t *transport;
...@@ -78,14 +78,14 @@ sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priorit ...@@ -78,14 +78,14 @@ sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priorit
/* Intialize a new transport from provided memory. */ /* Intialize a new transport from provided memory. */
sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
const sockaddr_storage_t *addr, const union sctp_addr *addr,
int priority) int priority)
{ {
sctp_protocol_t *proto = sctp_get_protocol(); sctp_protocol_t *proto = sctp_get_protocol();
/* Copy in the address. */ /* Copy in the address. */
peer->ipaddr = *addr; peer->ipaddr = *addr;
peer->af_specific = sctp_get_af_specific(addr); peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
peer->asoc = NULL; peer->asoc = NULL;
/* From 6.3.1 RTO Calculation: /* From 6.3.1 RTO Calculation:
...@@ -104,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, ...@@ -104,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
peer->last_time_used = jiffies; peer->last_time_used = jiffies;
peer->last_time_ecne_reduced = jiffies; peer->last_time_ecne_reduced = jiffies;
peer->state.active = 1; peer->active = 1;
peer->state.hb_allowed = 0; peer->hb_allowed = 0;
/* Initialize the default path max_retrans. */ /* Initialize the default path max_retrans. */
peer->max_retrans = proto->max_retrans_path; peer->max_retrans = proto->max_retrans_path;
...@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport, ...@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport,
/* Caches the dst entry for a transport's destination address and an optional /* Caches the dst entry for a transport's destination address and an optional
* souce address. * souce address.
*/ */
void sctp_transport_route(sctp_transport_t *transport, void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr,
sockaddr_storage_t *saddr) struct sctp_opt *opt)
{ {
sctp_association_t *asoc = transport->asoc; sctp_association_t *asoc = transport->asoc;
sctp_func_t *af = transport->af_specific; struct sctp_func *af = transport->af_specific;
sockaddr_storage_t *daddr = &transport->ipaddr; union sctp_addr *daddr = &transport->ipaddr;
sctp_bind_addr_t *bp; sctp_bind_addr_t *bp;
rwlock_t *addr_lock; rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr; struct sockaddr_storage_list *laddr;
struct list_head *pos; struct list_head *pos;
struct dst_entry *dst; struct dst_entry *dst;
union sctp_addr dst_saddr;
dst = af->get_dst(daddr, saddr); dst = af->get_dst(daddr, saddr);
...@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport, ...@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport,
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, laddr = list_entry(pos, struct sockaddr_storage_list,
list); list);
if (af->cmp_saddr(dst, &laddr->a)) af->dst_saddr(&dst_saddr, dst);
if (opt->pf->cmp_addr(&dst_saddr, &laddr->a, opt))
goto out_unlock; goto out_unlock;
} }
sctp_read_unlock(addr_lock); sctp_read_unlock(addr_lock);
......
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