Commit ce1de957 authored by David S. Miller's avatar David S. Miller

Merge http://linux-lksctp.bkbits.net/lksctp-2.5

into nuts.ninka.net:/home/davem/src/BK/sctp-2.5
parents 438ea4e5 3e446c25
...@@ -182,7 +182,7 @@ typedef struct { ...@@ -182,7 +182,7 @@ typedef struct {
/* Create a new sctp_command_sequence. /* Create a new sctp_command_sequence.
* Return NULL if creating a new sequence fails. * Return NULL if creating a new sequence fails.
*/ */
sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp);
/* Initialize a block of memory as a command sequence. /* Initialize a block of memory as a command sequence.
* Return 0 if the initialization fails. * Return 0 if the initialization fails.
......
...@@ -6,46 +6,42 @@ ...@@ -6,46 +6,42 @@
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This file is part of the implementation of the add-IP extension, * The SCTP reference implementation is free software;
* based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
* for the SCTP kernel reference Implementation.
*
* The SCTP reference implementation is free software;
* 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 warranty * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* 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 one of the following email * Please send any bug reports or fixes you make to the
* addresses: * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
* *
* La Monte H.P. Yarroll <piggy@acm.org> * Written or modified by:
* Karl Knutson <karl@athena.chicago.il.us> * La Monte H.P. Yarroll <piggy@acm.org>
* Randall Stewart <randall@stewart.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ken Morneau <kmorneau@cisco.com> * Randall Stewart <randall@stewart.chicago.il.us>
* Qiaobing Xie <qxie1@motorola.com> * Ken Morneau <kmorneau@cisco.com>
* Xingang Guo <xingang.guo@intel.com> * Qiaobing Xie <qxie1@motorola.com>
* Sridhar Samudrala <samudrala@us.ibm.com> * Xingang Guo <xingang.guo@intel.com>
* Daisy Chang <daisyc@us.ibm.com> * Sridhar Samudrala <samudrala@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * 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.
*
* There are still LOTS of bugs in this code... I always run on the motto
* "it is a wonder any code ever works :)"
*
*
*/ */
#ifndef __sctp_constants_h__ #ifndef __sctp_constants_h__
...@@ -220,7 +216,7 @@ typedef enum { ...@@ -220,7 +216,7 @@ typedef enum {
* - A socket in SCTP_SS_LISTENING state indicates that it is willing to * - A socket in SCTP_SS_LISTENING state indicates that it is willing to
* accept new associations, but cannot initiate the creation of new ones. * accept new associations, but cannot initiate the creation of new ones.
* - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single
* association in ESTABLISHED state. * association.
*/ */
typedef enum { typedef enum {
SCTP_SS_CLOSED = TCP_CLOSE, SCTP_SS_CLOSED = TCP_CLOSE,
...@@ -336,10 +332,18 @@ typedef enum { ...@@ -336,10 +332,18 @@ typedef enum {
#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ #define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */
#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash #define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash
* functions simpler to write. * functions simpler to write.
*/ */
#if defined (CONFIG_SCTP_HMAC_MD5)
#define SCTP_COOKIE_HMAC_ALG "md5"
#elif defined (CONFIG_SCTP_HMAC_SHA1)
#define SCTP_COOKIE_HMAC_ALG "sha1"
#else
#define SCTP_COOKIE_HMAC_ALG NULL
#endif
/* These return values describe the success or failure of a number of /* These return values describe the success or failure of a number of
* routines which form the lower interface to SCTP_outqueue. * routines which form the lower interface to SCTP_outqueue.
*/ */
......
...@@ -125,65 +125,61 @@ extern struct sctp_protocol sctp_proto; ...@@ -125,65 +125,61 @@ extern struct sctp_protocol sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(struct sctp_protocol *, extern int sctp_copy_local_addr_list(struct sctp_protocol *,
struct sctp_bind_addr *, struct sctp_bind_addr *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int gfp, int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t); extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
/* /*
* sctp/socket.c * sctp/socket.c
*/ */
extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
extern int sctp_inet_listen(struct socket *sock, int backlog); int sctp_inet_listen(struct socket *sock, int backlog);
extern void sctp_write_space(struct sock *sk); void sctp_write_space(struct sock *sk);
extern unsigned int sctp_poll(struct file *file, struct socket *sock, unsigned int sctp_poll(struct file *file, struct socket *sock,
poll_table *wait); poll_table *wait);
/* /*
* sctp/primitive.c * sctp/primitive.c
*/ */
extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg);
extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg);
extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); int sctp_primitive_ABORT(struct sctp_association *, void *arg);
extern int sctp_primitive_SEND(sctp_association_t *, void *arg); int sctp_primitive_SEND(struct sctp_association *, void *arg);
extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg); int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg);
/* /*
* sctp/crc32c.c * sctp/crc32c.c
*/ */
extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count); __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
extern __u32 sctp_end_cksum(__u32 cksum); __u32 sctp_end_cksum(__u32 cksum);
__u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum);
/* /*
* sctp/input.c * sctp/input.c
*/ */
extern int sctp_rcv(struct sk_buff *skb); int sctp_rcv(struct sk_buff *skb);
extern void sctp_v4_err(struct sk_buff *skb, u32 info); void sctp_v4_err(struct sk_buff *skb, u32 info);
extern void sctp_hash_established(sctp_association_t *); void sctp_hash_established(struct sctp_association *);
extern void __sctp_hash_established(sctp_association_t *); void __sctp_hash_established(struct sctp_association *);
extern void sctp_unhash_established(sctp_association_t *); void sctp_unhash_established(struct sctp_association *);
extern void __sctp_unhash_established(sctp_association_t *); void __sctp_unhash_established(struct sctp_association *);
extern void sctp_hash_endpoint(sctp_endpoint_t *); void sctp_hash_endpoint(struct sctp_endpoint *);
extern void __sctp_hash_endpoint(sctp_endpoint_t *); void __sctp_hash_endpoint(struct sctp_endpoint *);
extern void sctp_unhash_endpoint(sctp_endpoint_t *); void sctp_unhash_endpoint(struct sctp_endpoint *);
extern void __sctp_unhash_endpoint(sctp_endpoint_t *); void __sctp_unhash_endpoint(struct sctp_endpoint *);
extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *, struct sctp_association *__sctp_lookup_association(
const union sctp_addr *, const union sctp_addr *,
struct sctp_transport **); const union sctp_addr *,
extern struct sock *sctp_err_lookup(int family, struct sk_buff *, struct sctp_transport **);
struct sctphdr *, struct sctp_endpoint **, struct sock *sctp_err_lookup(int family, struct sk_buff *,
struct sctp_association **, struct sctphdr *, struct sctp_endpoint **,
struct sctp_transport **); struct sctp_association **,
extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, struct sctp_transport **);
void sctp_err_finish(struct sock *, struct sctp_endpoint *,
struct sctp_association *); struct sctp_association *);
extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
struct sctp_transport *t, __u32 pmtu); struct sctp_transport *t, __u32 pmtu);
/*
* sctp/hashdriver.c
*/
extern void sctp_hash_digest(const char *secret, const int secret_len,
const char *text, const int text_len,
__u8 *digest);
/* /*
* Section: Macros, externs, and inlines * Section: Macros, externs, and inlines
...@@ -281,6 +277,7 @@ extern atomic_t sctp_dbg_objcnt_chunk; ...@@ -281,6 +277,7 @@ extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_bind_addr;
extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap; extern atomic_t sctp_dbg_objcnt_ssnmap;
extern atomic_t sctp_dbg_objcnt_datamsg;
/* Macros to atomically increment/decrement objcnt counters. */ /* Macros to atomically increment/decrement objcnt counters. */
#define SCTP_DBG_OBJCNT_INC(name) \ #define SCTP_DBG_OBJCNT_INC(name) \
...@@ -296,8 +293,8 @@ atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) ...@@ -296,8 +293,8 @@ atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0)
#define SCTP_DBG_OBJCNT_ENTRY(name) \ #define SCTP_DBG_OBJCNT_ENTRY(name) \
{.label= #name, .counter= &sctp_dbg_objcnt_## name} {.label= #name, .counter= &sctp_dbg_objcnt_## name}
extern void sctp_dbg_objcnt_init(void); void sctp_dbg_objcnt_init(void);
extern void sctp_dbg_objcnt_exit(void); void sctp_dbg_objcnt_exit(void);
#else #else
...@@ -310,8 +307,8 @@ static inline void sctp_dbg_objcnt_exit(void) { return; } ...@@ -310,8 +307,8 @@ static inline void sctp_dbg_objcnt_exit(void) { return; }
#endif /* CONFIG_SCTP_DBG_OBJCOUNT */ #endif /* CONFIG_SCTP_DBG_OBJCOUNT */
#if defined CONFIG_SYSCTL #if defined CONFIG_SYSCTL
extern void sctp_sysctl_register(void); void sctp_sysctl_register(void);
extern void sctp_sysctl_unregister(void); void sctp_sysctl_unregister(void);
#else #else
static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_register(void) { return; }
static inline void sctp_sysctl_unregister(void) { return; } static inline void sctp_sysctl_unregister(void) { return; }
...@@ -322,9 +319,9 @@ static inline void sctp_sysctl_unregister(void) { return; } ...@@ -322,9 +319,9 @@ static inline void sctp_sysctl_unregister(void) { return; }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
extern int sctp_v6_init(void); int sctp_v6_init(void);
extern void sctp_v6_exit(void); void sctp_v6_exit(void);
extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info); int type, int code, int offset, __u32 info);
#else /* #ifdef defined(CONFIG_IPV6) */ #else /* #ifdef defined(CONFIG_IPV6) */
...@@ -334,15 +331,26 @@ static inline void sctp_v6_exit(void) { return; } ...@@ -334,15 +331,26 @@ static inline void sctp_v6_exit(void) { return; }
#endif /* #if defined(CONFIG_IPV6) */ #endif /* #if defined(CONFIG_IPV6) */
/* Some wrappers, in case crypto not available. */
#if defined (CONFIG_CRYPTO_HMAC)
#define sctp_crypto_alloc_tfm crypto_alloc_tfm
#define sctp_crypto_free_tfm crypto_free_tfm
#define sctp_crypto_hmac crypto_hmac
#else
#define sctp_crypto_alloc_tfm(x...) NULL
#define sctp_crypto_free_tfm(x...)
#define sctp_crypto_hmac(x...)
#endif
/* Map an association to an assoc_id. */ /* Map an association to an assoc_id. */
static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
{ {
return (sctp_assoc_t) asoc; return (sctp_assoc_t) asoc;
} }
/* Look up the association by its id. */ /* Look up the association by its id. */
sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
/* A macro to walk a list of skbs. */ /* A macro to walk a list of skbs. */
...@@ -422,12 +430,16 @@ static inline __s32 sctp_jitter(__u32 rto) ...@@ -422,12 +430,16 @@ static inline __s32 sctp_jitter(__u32 rto)
} }
/* Break down data chunks at this point. */ /* Break down data chunks at this point. */
static inline int sctp_frag_point(int pmtu) static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
{ {
pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); int frag = pmtu;
pmtu -= sizeof(struct sctp_sack_chunk); frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
frag -= sizeof(struct sctp_sack_chunk);
return pmtu; if (sp->user_frag)
frag = min_t(int, frag, sp->user_frag);
return frag;
} }
/* Walk through a list of TLV parameters. Don't trust the /* Walk through a list of TLV parameters. Don't trust the
...@@ -475,7 +487,7 @@ static inline void tv_add(const struct timeval *entered, struct timeval *leaved) ...@@ -475,7 +487,7 @@ static inline void tv_add(const struct timeval *entered, struct timeval *leaved)
extern struct proto sctp_prot; extern struct proto sctp_prot;
extern struct proc_dir_entry *proc_net_sctp; extern struct proc_dir_entry *proc_net_sctp;
extern void sctp_put_port(struct sock *sk); void sctp_put_port(struct sock *sk);
/* Static inline functions. */ /* Static inline functions. */
...@@ -501,10 +513,10 @@ static inline int ipver2af(__u8 ipver) ...@@ -501,10 +513,10 @@ static inline int ipver2af(__u8 ipver)
/* Perform some sanity checks. */ /* Perform some sanity checks. */
static inline int sctp_sanity_check(void) static inline int sctp_sanity_check(void)
{ {
SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= SCTP_ASSERT(sizeof(struct sctp_ulpevent) <=
sizeof(((struct sk_buff *)0)->cb), sizeof(((struct sk_buff *)0)->cb),
"SCTP: ulpevent does not fit in skb!\n", return 0); "SCTP: ulpevent does not fit in skb!\n", return 0);
return 1; return 1;
} }
...@@ -566,4 +578,26 @@ struct sctp6_sock { ...@@ -566,4 +578,26 @@ struct sctp6_sock {
#define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp)
/* Is a socket of this style? */
#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style))
int static inline __sctp_style(const struct sock *sk, sctp_socket_type_t style)
{
return sctp_sk(sk)->type == style;
}
/* Is the association in this state? */
#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state))
int static inline __sctp_state(const struct sctp_association *asoc,
sctp_state_t state)
{
return asoc->state == state;
}
/* Is the socket in this state? */
#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state))
int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state)
{
return sk->state == state;
}
#endif /* __net_sctp_h__ */ #endif /* __net_sctp_h__ */
...@@ -6,10 +6,6 @@ ...@@ -6,10 +6,6 @@
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This file is part of the implementation of the add-IP extension,
* based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
* for the SCTP kernel reference Implementation.
*
* These are definitions needed by the state machine. * These are definitions needed by the state machine.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
...@@ -50,7 +46,6 @@ ...@@ -50,7 +46,6 @@
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -81,8 +76,8 @@ typedef struct { ...@@ -81,8 +76,8 @@ typedef struct {
int action; int action;
} sctp_sm_command_t; } sctp_sm_command_t;
typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *,
const sctp_association_t *, const struct sctp_association *,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *); sctp_cmd_seq_t *);
...@@ -209,109 +204,104 @@ __u32 sctp_generate_verification_tag(void); ...@@ -209,109 +204,104 @@ __u32 sctp_generate_verification_tag(void);
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. */
sctp_chunk_t *sctp_make_init(const sctp_association_t *, struct sctp_chunk *sctp_make_init(const struct sctp_association *,
const sctp_bind_addr_t *, const struct sctp_bind_addr *,
int priority, int vparam_len); int gfp, int vparam_len);
sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *,
const sctp_chunk_t *, const struct sctp_chunk *,
const int priority, const int gfp,
const int unkparam_len); const int unkparam_len);
sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *,
const sctp_chunk_t *); const struct sctp_chunk *);
sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *,
const sctp_chunk_t *); const struct sctp_chunk *);
sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
const __u32 lowest_tsn, const __u32 lowest_tsn,
const sctp_chunk_t *); const struct sctp_chunk *);
sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, struct sctp_chunk *sctp_make_datafrag(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 *data, int len, const __u8 *data,
__u8 flags, __u16 ssn); __u8 flags, __u16 ssn);
sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 flags, int len, const __u8 flags,
__u16 ssn); __u16 ssn);
sctp_chunk_t *sctp_make_data(sctp_association_t *, struct sctp_chunk *sctp_make_data(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 *data); int len, const __u8 *data);
sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, struct sctp_chunk *sctp_make_data_empty(struct sctp_association *,
const struct sctp_sndrcvinfo *, int len); const struct sctp_sndrcvinfo *, int len);
sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
const __u32); const __u32);
sctp_chunk_t *sctp_make_sack(const sctp_association_t *); struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc);
sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
const sctp_chunk_t *); const struct sctp_chunk *);
sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *,
const sctp_chunk_t *); const struct sctp_chunk *);
void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); void sctp_init_cause(struct sctp_chunk *, __u16 cause, const void *, size_t);
sctp_chunk_t *sctp_make_abort(const sctp_association_t *, struct sctp_chunk *sctp_make_abort(const struct sctp_association *,
const sctp_chunk_t *, const struct sctp_chunk *,
const size_t hint); const size_t hint);
sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *,
const sctp_chunk_t *, const struct sctp_chunk *,
__u32 tsn); __u32 tsn);
sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *, struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *,
const sctp_chunk_t *, const struct sctp_chunk *,
const struct msghdr *); const struct msghdr *);
sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
const struct sctp_transport *, const struct sctp_transport *,
const void *payload, const void *payload,
const size_t paylen); const size_t paylen);
sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *,
const sctp_chunk_t *, const struct sctp_chunk *,
const void *payload, const void *payload,
const size_t paylen); const size_t paylen);
sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, struct sctp_chunk *sctp_make_op_error(const struct sctp_association *,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
__u16 cause_code, __u16 cause_code,
const void *payload, const void *payload,
size_t paylen); size_t paylen);
void sctp_chunk_assign_tsn(sctp_chunk_t *); void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(sctp_chunk_t *); void sctp_chunk_assign_ssn(struct sctp_chunk *);
int sctp_datachunks_from_user(sctp_association_t *,
const struct sctp_sndrcvinfo *,
struct msghdr *, int len,
struct sk_buff_head *);
/* Prototypes for statetable processing. */ /* Prototypes for statetable processing. */
int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_state_t state,
sctp_endpoint_t *, struct sctp_endpoint *,
sctp_association_t *asoc, struct sctp_association *asoc,
void *event_arg, void *event_arg,
int priority); int gfp);
int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_state_t state,
sctp_endpoint_t *, struct sctp_endpoint *,
sctp_association_t *asoc, struct sctp_association *asoc,
void *event_arg, void *event_arg,
sctp_disposition_t status, sctp_disposition_t status,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
int priority); int gfp);
/* 2nd level prototypes */ /* 2nd level prototypes */
int int
sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_state_t state,
sctp_endpoint_t *ep, struct sctp_endpoint *ep,
sctp_association_t *asoc, struct sctp_association *asoc,
void *event_arg, void *event_arg,
sctp_disposition_t status, sctp_disposition_t status,
sctp_cmd_seq_t *retval, sctp_cmd_seq_t *retval,
int priority); int gfp);
int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *); int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap); void sctp_do_TSNdup(struct sctp_association *, struct sctp_chunk *, long gap);
void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer);
sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *);
struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *, struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
const struct sctp_association *, const struct sctp_association *,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
...@@ -325,21 +315,21 @@ sctp_cookie_param_t * ...@@ -325,21 +315,21 @@ sctp_cookie_param_t *
sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *, sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
const struct sctp_chunk *, int *cookie_len, const struct sctp_chunk *, int *cookie_len,
const __u8 *, int addrs_len); const __u8 *, int addrs_len);
sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
const sctp_association_t *, const struct sctp_association *,
sctp_chunk_t *, int priority, int *err, struct sctp_chunk *, int gfp, int *err,
sctp_chunk_t **err_chk_p); struct sctp_chunk **err_chk_p);
int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
struct sockaddr_storage*, int); struct sockaddr_storage*, int);
void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_chunk_t *err_chunk); struct sctp_chunk *err_chunk);
/* 3rd level prototypes */ /* 3rd level prototypes */
__u32 sctp_generate_tag(const sctp_endpoint_t *); __u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const sctp_endpoint_t *); __u32 sctp_generate_tsn(const struct sctp_endpoint *);
/* 4th level prototypes */ /* 4th level prototypes */
void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *, void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *,
...@@ -361,7 +351,7 @@ extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; ...@@ -361,7 +351,7 @@ extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES];
/* Get the size of a DATA chunk payload. */ /* Get the size of a DATA chunk payload. */
static inline __u16 sctp_data_size(sctp_chunk_t *chunk) static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
{ {
__u16 size; __u16 size;
...@@ -449,8 +439,8 @@ static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_a ...@@ -449,8 +439,8 @@ static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_a
* tag and the T bit is set in the Chunk Flags. * tag and the T bit is set in the Chunk Flags.
*/ */
static inline int static inline int
sctp_vtag_verify_either(const sctp_chunk_t *chunk, sctp_vtag_verify_either(const struct sctp_chunk *chunk,
const sctp_association_t *asoc) const struct sctp_association *asoc)
{ {
/* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2 /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2
* *
......
...@@ -70,7 +70,6 @@ union sctp_addr { ...@@ -70,7 +70,6 @@ union sctp_addr {
struct sockaddr sa; struct sockaddr sa;
}; };
/* Forward declarations for data structures. */ /* Forward declarations for data structures. */
struct sctp_protocol; struct sctp_protocol;
struct sctp_endpoint; struct sctp_endpoint;
...@@ -83,14 +82,9 @@ struct sctp_outq; ...@@ -83,14 +82,9 @@ struct sctp_outq;
struct sctp_bind_addr; struct sctp_bind_addr;
struct sctp_ulpq; struct sctp_ulpq;
struct sctp_opt; struct sctp_opt;
struct sctp_endpoint_common; struct sctp_ep_common;
struct sctp_ssnmap; struct sctp_ssnmap;
typedef struct sctp_endpoint sctp_endpoint_t;
typedef struct sctp_association sctp_association_t;
typedef struct sctp_chunk sctp_chunk_t;
typedef struct sctp_bind_addr sctp_bind_addr_t;
typedef struct sctp_endpoint_common sctp_endpoint_common_t;
#include <net/sctp/tsnmap.h> #include <net/sctp/tsnmap.h>
#include <net/sctp/ulpevent.h> #include <net/sctp/ulpevent.h>
...@@ -114,7 +108,7 @@ typedef struct sctp_bind_hashbucket { ...@@ -114,7 +108,7 @@ typedef struct sctp_bind_hashbucket {
/* Used for hashing all associations. */ /* Used for hashing all associations. */
typedef struct sctp_hashbucket { typedef struct sctp_hashbucket {
rwlock_t lock; rwlock_t lock;
sctp_endpoint_common_t *chain; struct sctp_ep_common *chain;
} sctp_hashbucket_t __attribute__((__aligned__(8))); } sctp_hashbucket_t __attribute__((__aligned__(8)));
...@@ -235,7 +229,9 @@ struct sctp_af { ...@@ -235,7 +229,9 @@ struct sctp_af {
int saddr); int saddr);
void (*from_sk) (union sctp_addr *, void (*from_sk) (union sctp_addr *,
struct sock *sk); struct sock *sk);
void (*to_sk) (union sctp_addr *, void (*to_sk_saddr) (union sctp_addr *,
struct sock *sk);
void (*to_sk_daddr) (union sctp_addr *,
struct sock *sk); struct sock *sk);
int (*addr_valid) (union sctp_addr *); int (*addr_valid) (union sctp_addr *);
sctp_scope_t (*scope) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *);
...@@ -243,6 +239,7 @@ struct sctp_af { ...@@ -243,6 +239,7 @@ struct sctp_af {
int (*is_any) (const union sctp_addr *); int (*is_any) (const union sctp_addr *);
int (*available) (const union sctp_addr *); int (*available) (const union sctp_addr *);
int (*skb_iif) (const struct sk_buff *sk); int (*skb_iif) (const struct sk_buff *sk);
int (*is_ce) (const struct sk_buff *sk);
__u16 net_header_len; __u16 net_header_len;
int sockaddr_len; int sockaddr_len;
sa_family_t sa_family; sa_family_t sa_family;
...@@ -283,8 +280,11 @@ struct sctp_opt { ...@@ -283,8 +280,11 @@ struct sctp_opt {
/* PF_ family specific functions. */ /* PF_ family specific functions. */
struct sctp_pf *pf; struct sctp_pf *pf;
/* Access to HMAC transform. */
struct crypto_tfm *hmac;
/* What is our base endpointer? */ /* What is our base endpointer? */
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
/* Various Socket Options. */ /* Various Socket Options. */
__u16 default_stream; __u16 default_stream;
...@@ -293,10 +293,12 @@ struct sctp_opt { ...@@ -293,10 +293,12 @@ struct sctp_opt {
struct sctp_rtoinfo rtoinfo; struct sctp_rtoinfo rtoinfo;
struct sctp_paddrparams paddrparam; struct sctp_paddrparams paddrparam;
struct sctp_event_subscribe subscribe; struct sctp_event_subscribe subscribe;
int user_frag;
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
__u8 disable_fragments; __u8 disable_fragments;
__u8 pd_mode; __u8 pd_mode;
__u8 v4mapped;
/* Receive to here while partial delivery is in effect. */ /* Receive to here while partial delivery is in effect. */
struct sk_buff_head pd_lobby; struct sk_buff_head pd_lobby;
...@@ -448,6 +450,37 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) ...@@ -448,6 +450,37 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
return stream->ssn[id]++; return stream->ssn[id]++;
} }
/* Structure to track chunk fragments that have been acked, but peer
* fragments of the same message have not.
*/
struct sctp_datamsg {
/* Chunks waiting to be submitted to lower layer. */
struct list_head chunks;
/* Chunks that have been transmitted. */
struct list_head track;
/* Reference counting. */
atomic_t refcnt;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */
int send_error;
char send_failed;
/* Control whether fragments from this message can expire. */
char can_expire;
};
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
struct sctp_sndrcvinfo *,
struct msghdr *, int len);
struct sctp_datamsg *sctp_datamsg_new(int gfp);
void sctp_datamsg_put(struct sctp_datamsg *);
void sctp_datamsg_hold(struct sctp_datamsg *);
void sctp_datamsg_free(struct sctp_datamsg *);
void sctp_datamsg_track(struct sctp_chunk *);
void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
void sctp_datamsg_fail(struct sctp_chunk *, int error);
int sctp_datamsg_expires(struct sctp_chunk *);
/* RFC2960 1.4 Key Terms /* RFC2960 1.4 Key Terms
* *
...@@ -462,9 +495,10 @@ struct sctp_chunk { ...@@ -462,9 +495,10 @@ struct sctp_chunk {
* three elements of struct sk_buff. This allows us to reuse * three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions. * all the skb_* queue management functions.
*/ */
sctp_chunk_t *next; struct sctp_chunk *next;
sctp_chunk_t *prev; struct sctp_chunk *prev;
struct sk_buff_head *list; struct sk_buff_head *list;
atomic_t refcnt;
/* This is our link to the per-transport transmitted list. */ /* This is our link to the per-transport transmitted list. */
struct list_head transmitted_list; struct list_head transmitted_list;
...@@ -514,43 +548,52 @@ struct sctp_chunk { ...@@ -514,43 +548,52 @@ struct sctp_chunk {
struct sctp_association *asoc; struct sctp_association *asoc;
/* What endpoint received this chunk? */ /* What endpoint received this chunk? */
sctp_endpoint_common_t *rcvr; struct sctp_ep_common *rcvr;
/* We fill this in if we are calculating RTT. */ /* We fill this in if we are calculating RTT. */
unsigned long sent_at; unsigned long sent_at;
__u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */
__u8 num_times_sent; /* How man times did we send this? */
__u8 has_tsn; /* Does this chunk have a TSN yet? */
__u8 has_ssn; /* Does this chunk have a SSN yet? */
__u8 singleton; /* Was this the only chunk in the packet? */
__u8 end_of_packet; /* Was this the last chunk in the packet? */
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__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? */
union sctp_addr source; union sctp_addr source;
/* Destination address for this chunk. */ /* Destination address for this chunk. */
union sctp_addr dest; union sctp_addr dest;
/* For outbound message, track all fragments for SEND_FAILED. */
struct sctp_datamsg *msg;
/* 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
* go. It is NULL if we have no preference. * go. It is NULL if we have no preference.
*/ */
struct sctp_transport *transport; struct sctp_transport *transport;
__u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */
__u8 resent; /* Has this chunk ever been retransmitted. */
__u8 has_tsn; /* Does this chunk have a TSN yet? */
__u8 has_ssn; /* Does this chunk have a SSN yet? */
__u8 singleton; /* Was this the only chunk in the packet? */
__u8 end_of_packet; /* Was this the last chunk in the packet? */
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */
}; };
sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type, void sctp_chunk_hold(struct sctp_chunk *);
__u8 flags, int size); void sctp_chunk_put(struct sctp_chunk *);
void sctp_free_chunk(sctp_chunk_t *); int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); struct iovec *data);
sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *, struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
struct sock *); __u8 flags, int size);
void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *); void sctp_chunk_free(struct sctp_chunk *);
const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
struct sctp_chunk *sctp_chunkify(struct sk_buff *,
const struct sctp_association *,
struct sock *);
void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *,
union sctp_addr *);
const union sctp_addr *sctp_source(const struct sctp_chunk *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
...@@ -562,7 +605,7 @@ struct sockaddr_storage_list { ...@@ -562,7 +605,7 @@ struct sockaddr_storage_list {
union sctp_addr a; union sctp_addr a;
}; };
typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *); typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
/* This structure holds lists of chunks as we are assembling for /* This structure holds lists of chunks as we are assembling for
* transmission. * transmission.
...@@ -619,7 +662,7 @@ typedef struct sctp_packet *(sctp_outq_ohandler_config_t) ...@@ -619,7 +662,7 @@ typedef struct sctp_packet *(sctp_outq_ohandler_config_t)
int ecn_capable, int ecn_capable,
sctp_packet_phandler_t *get_prepend_chunk); sctp_packet_phandler_t *get_prepend_chunk);
typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
sctp_chunk_t *); struct sctp_chunk *);
typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
sctp_outq_ohandler_init_t sctp_packet_init; sctp_outq_ohandler_init_t sctp_packet_init;
...@@ -697,7 +740,6 @@ struct sctp_transport { ...@@ -697,7 +740,6 @@ struct sctp_transport {
*/ */
int rto_pending; int rto_pending;
/* /*
* These are the congestion stats. * These are the congestion stats.
*/ */
...@@ -771,9 +813,6 @@ struct sctp_transport { ...@@ -771,9 +813,6 @@ struct sctp_transport {
*/ */
int max_retrans; int max_retrans;
/* We use this name for debugging output... */
char *debug_name;
/* Per : A timer used by each destination. /* Per : A timer used by each destination.
* Destination : * Destination :
* Timer : * Timer :
...@@ -799,6 +838,35 @@ struct sctp_transport { ...@@ -799,6 +838,35 @@ struct sctp_transport {
struct list_head send_ready; struct list_head send_ready;
int malloced; /* Is this structure kfree()able? */ int malloced; /* Is this structure kfree()able? */
/* State information saved for SFR_CACC algorithm. The key
* idea in SFR_CACC is to maintain state at the sender on a
* per-destination basis when a changeover happens.
* char changeover_active;
* char cycling_changeover;
* __u32 next_tsn_at_change;
* char cacc_saw_newack;
*/
struct {
/* An unsigned integer, which stores the next TSN to be
* used by the sender, at the moment of changeover.
*/
__u32 next_tsn_at_change;
/* A flag which indicates the occurrence of a changeover */
char changeover_active;
/* A glag which indicates whether the change of primary is
* the first switch to this destination address during an
* active switch.
*/
char cycling_changeover;
/* A temporary flag, which is used during the processing of
* a SACK to estimate the causative TSN(s)'s group.
*/
char cacc_saw_newack;
} cacc;
}; };
struct sctp_transport *sctp_transport_new(const union sctp_addr *, int); struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
...@@ -831,7 +899,7 @@ struct sctp_inq { ...@@ -831,7 +899,7 @@ struct sctp_inq {
/* This is the packet which is currently off the in queue and is /* This is the packet which is currently off the in queue and is
* being worked on through the inbound chunk processing. * being worked on through the inbound chunk processing.
*/ */
sctp_chunk_t *in_progress; struct sctp_chunk *in_progress;
/* This is the delayed task to finish delivering inbound /* This is the delayed task to finish delivering inbound
* messages. * messages.
...@@ -844,7 +912,7 @@ struct sctp_inq { ...@@ -844,7 +912,7 @@ struct sctp_inq {
struct sctp_inq *sctp_inq_new(void); struct sctp_inq *sctp_inq_new(void);
void sctp_inq_init(struct sctp_inq *); void sctp_inq_init(struct sctp_inq *);
void sctp_inq_free(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *);
void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet); void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
...@@ -904,18 +972,21 @@ struct sctp_outq { ...@@ -904,18 +972,21 @@ struct sctp_outq {
/* How many unackd bytes do we have in-flight? */ /* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes; __u32 outstanding_bytes;
/* Corked? */
char cork;
/* Is this structure empty? */ /* Is this structure empty? */
int empty; char empty;
/* Are we kfree()able? */ /* Are we kfree()able? */
int malloced; char malloced;
}; };
struct sctp_outq *sctp_outq_new(struct sctp_association *); struct sctp_outq *sctp_outq_new(struct sctp_association *);
void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *);
void sctp_outq_free(struct sctp_outq*); void sctp_outq_free(struct sctp_outq*);
int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk); int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk);
int sctp_outq_flush(struct sctp_outq *, int); int sctp_outq_flush(struct sctp_outq *, int);
int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *); int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *);
int sctp_outq_is_empty(const struct sctp_outq *); int sctp_outq_is_empty(const struct sctp_outq *);
...@@ -926,10 +997,16 @@ int sctp_outq_set_output_handlers(struct sctp_outq *, ...@@ -926,10 +997,16 @@ int sctp_outq_set_output_handlers(struct sctp_outq *,
sctp_outq_ohandler_t build, sctp_outq_ohandler_t build,
sctp_outq_ohandler_force_t force); sctp_outq_ohandler_force_t force);
void sctp_outq_restart(struct sctp_outq *); void sctp_outq_restart(struct sctp_outq *);
void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
sctp_retransmit_reason_t); sctp_retransmit_reason_t);
void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
int sctp_outq_uncork(struct sctp_outq *);
/* Uncork and flush an outqueue. */
static inline void sctp_outq_cork(struct sctp_outq *q)
{
q->cork = 1;
}
/* These bind address data fields common between endpoints and associations */ /* These bind address data fields common between endpoints and associations */
struct sctp_bind_addr { struct sctp_bind_addr {
...@@ -952,15 +1029,16 @@ struct sctp_bind_addr { ...@@ -952,15 +1029,16 @@ struct sctp_bind_addr {
int malloced; /* Are we kfree()able? */ int malloced; /* Are we kfree()able? */
}; };
sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
void sctp_bind_addr_free(sctp_bind_addr_t *); void sctp_bind_addr_free(struct sctp_bind_addr *);
int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src,
sctp_scope_t scope, int gfp,int flags); sctp_scope_t scope, int gfp,int flags);
int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
int gfp); int gfp);
int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *, int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_opt *); struct sctp_opt *);
union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int *addrs_len, int gfp); int *addrs_len, int gfp);
...@@ -973,7 +1051,7 @@ int sctp_is_any(const union sctp_addr *addr); ...@@ -973,7 +1051,7 @@ int sctp_is_any(const union sctp_addr *addr);
int sctp_addr_is_valid(const union sctp_addr *addr); int sctp_addr_is_valid(const union sctp_addr *addr);
/* What type of sctp_endpoint_common? */ /* What type of endpoint? */
typedef enum { typedef enum {
SCTP_EP_TYPE_SOCKET, SCTP_EP_TYPE_SOCKET,
SCTP_EP_TYPE_ASSOCIATION, SCTP_EP_TYPE_ASSOCIATION,
...@@ -995,10 +1073,10 @@ typedef enum { ...@@ -995,10 +1073,10 @@ typedef enum {
* *
*/ */
struct sctp_endpoint_common { struct sctp_ep_common {
/* Fields to help us manage our entries in the hash tables. */ /* Fields to help us manage our entries in the hash tables. */
sctp_endpoint_common_t *next; struct sctp_ep_common *next;
sctp_endpoint_common_t **pprev; struct sctp_ep_common **pprev;
int hashent; int hashent;
/* Runtime type information. What kind of endpoint is this? */ /* Runtime type information. What kind of endpoint is this? */
...@@ -1024,7 +1102,7 @@ struct sctp_endpoint_common { ...@@ -1024,7 +1102,7 @@ struct sctp_endpoint_common {
* bind_addr.port is our shared port number. * bind_addr.port is our shared port number.
* bind_addr.address_list is our set of local IP addresses. * bind_addr.address_list is our set of local IP addresses.
*/ */
sctp_bind_addr_t bind_addr; struct sctp_bind_addr bind_addr;
/* Protection during address list comparisons. */ /* Protection during address list comparisons. */
rwlock_t addr_lock; rwlock_t addr_lock;
...@@ -1052,12 +1130,7 @@ struct sctp_endpoint_common { ...@@ -1052,12 +1130,7 @@ struct sctp_endpoint_common {
struct sctp_endpoint { struct sctp_endpoint {
/* Common substructure for endpoint and association. */ /* Common substructure for endpoint and association. */
sctp_endpoint_common_t base; struct sctp_ep_common base;
/* These are the system-wide defaults and other stuff which is
* endpoint-independent.
*/
struct sctp_protocol *proto;
/* Associations: A list of current associations and mappings /* Associations: A list of current associations and mappings
* to the data consumers for each association. This * to the data consumers for each association. This
...@@ -1092,28 +1165,29 @@ struct sctp_endpoint { ...@@ -1092,28 +1165,29 @@ struct sctp_endpoint {
}; };
/* Recover the outter endpoint structure. */ /* Recover the outter endpoint structure. */
static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
ep = container_of(base, sctp_endpoint_t, base); ep = container_of(base, struct sctp_endpoint, base);
return ep; return ep;
} }
/* These are function signatures for manipulating endpoints. */ /* These are function signatures for manipulating endpoints. */
sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int); struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *, struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *,
struct sctp_protocol *, struct sock *, int gfp);
struct sock *, int gfp); void sctp_endpoint_free(struct sctp_endpoint *);
void sctp_endpoint_free(sctp_endpoint_t *); void sctp_endpoint_put(struct sctp_endpoint *);
void sctp_endpoint_put(sctp_endpoint_t *); void sctp_endpoint_hold(struct sctp_endpoint *);
void sctp_endpoint_hold(sctp_endpoint_t *); void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *);
void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc); struct sctp_association *sctp_endpoint_lookup_assoc(
struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const union sctp_addr *paddr, const union sctp_addr *paddr,
struct sctp_transport **); struct sctp_transport **);
int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); int sctp_endpoint_is_peeled_off(struct sctp_endpoint *,
sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, const union sctp_addr *);
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
const union sctp_addr *); const union sctp_addr *);
int sctp_has_association(const union sctp_addr *laddr, int sctp_has_association(const union sctp_addr *laddr,
const union sctp_addr *paddr); const union sctp_addr *paddr);
...@@ -1126,8 +1200,8 @@ int sctp_process_init(struct sctp_association *, sctp_cid_t cid, ...@@ -1126,8 +1200,8 @@ int sctp_process_init(struct sctp_association *, sctp_cid_t cid,
sctp_init_chunk_t *init, int gfp); sctp_init_chunk_t *init, int gfp);
int sctp_process_param(struct sctp_association *, union sctp_params param, int sctp_process_param(struct sctp_association *, union sctp_params param,
const union sctp_addr *from, int gfp); const union sctp_addr *from, int gfp);
__u32 sctp_generate_tag(const sctp_endpoint_t *); __u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const sctp_endpoint_t *); __u32 sctp_generate_tsn(const struct sctp_endpoint *);
/* RFC2960 /* RFC2960
...@@ -1150,7 +1224,7 @@ struct sctp_association { ...@@ -1150,7 +1224,7 @@ struct sctp_association {
* In this context, it represents the associations's view * In this context, it represents the associations's view
* of the local endpoint of the association. * of the local endpoint of the association.
*/ */
sctp_endpoint_common_t base; struct sctp_ep_common base;
/* Associations on the same socket. */ /* Associations on the same socket. */
struct list_head asocs; struct list_head asocs;
...@@ -1162,7 +1236,7 @@ struct sctp_association { ...@@ -1162,7 +1236,7 @@ struct sctp_association {
__u32 eyecatcher; __u32 eyecatcher;
/* This is our parent endpoint. */ /* This is our parent endpoint. */
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
/* These are those association elements needed in the cookie. */ /* These are those association elements needed in the cookie. */
sctp_cookie_t c; sctp_cookie_t c;
...@@ -1337,7 +1411,6 @@ struct sctp_association { ...@@ -1337,7 +1411,6 @@ struct sctp_association {
/* The largest timeout or RTO value to use in attempting an INIT */ /* The largest timeout or RTO value to use in attempting an INIT */
__u16 max_init_timeo; __u16 max_init_timeo;
int timeouts[SCTP_NUM_TIMEOUT_TYPES]; int timeouts[SCTP_NUM_TIMEOUT_TYPES];
struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];
...@@ -1438,9 +1511,6 @@ struct sctp_association { ...@@ -1438,9 +1511,6 @@ struct sctp_association {
*/ */
struct sctp_ulpq ulpq; struct sctp_ulpq ulpq;
/* Need to send an ECNE Chunk? */
int need_ecne;
/* Last TSN that caused an ECNE Chunk to be sent. */ /* Last TSN that caused an ECNE Chunk to be sent. */
__u32 last_ecne_tsn; __u32 last_ecne_tsn;
...@@ -1453,9 +1523,6 @@ struct sctp_association { ...@@ -1453,9 +1523,6 @@ struct sctp_association {
/* Number of seconds of idle time before an association is closed. */ /* Number of seconds of idle time before an association is closed. */
__u32 autoclose; __u32 autoclose;
/* Name for debugging output... */
char *debug_name;
/* These are to support /* These are to support
* "SCTP Extensions for Dynamic Reconfiguration of IP Addresses * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses
* and Enforcement of Flow and Message Limits" * and Enforcement of Flow and Message Limits"
...@@ -1463,8 +1530,7 @@ struct sctp_association { ...@@ -1463,8 +1530,7 @@ struct sctp_association {
* or "ADDIP" for short. * or "ADDIP" for short.
*/ */
/* Is the ADDIP extension enabled for this association? */
int addip_enable;
/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
* *
...@@ -1480,7 +1546,7 @@ struct sctp_association { ...@@ -1480,7 +1546,7 @@ struct sctp_association {
* [This is our one-and-only-one ASCONF in flight. If we do * [This is our one-and-only-one ASCONF in flight. If we do
* not have an ASCONF in flight, this is NULL.] * not have an ASCONF in flight, this is NULL.]
*/ */
sctp_chunk_t *addip_last_asconf; struct sctp_chunk *addip_last_asconf;
/* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk.
* *
...@@ -1495,7 +1561,7 @@ struct sctp_association { ...@@ -1495,7 +1561,7 @@ struct sctp_association {
* [This is our saved ASCONF-ACK. We invalidate it when a new * [This is our saved ASCONF-ACK. We invalidate it when a new
* ASCONF serial number arrives.] * ASCONF serial number arrives.]
*/ */
sctp_chunk_t *addip_last_asconf_ack; struct sctp_chunk *addip_last_asconf_ack;
/* These ASCONF chunks are waiting to be sent. /* These ASCONF chunks are waiting to be sent.
* *
...@@ -1548,6 +1614,15 @@ struct sctp_association { ...@@ -1548,6 +1614,15 @@ struct sctp_association {
* after reaching 4294967295. * after reaching 4294967295.
*/ */
__u32 addip_serial; __u32 addip_serial;
/* Is the ADDIP extension enabled for this association? */
char addip_enable;
/* Need to send an ECNE Chunk? */
char need_ecne;
/* Is it a temporary association? */
char temp;
}; };
...@@ -1559,7 +1634,7 @@ enum { ...@@ -1559,7 +1634,7 @@ enum {
}; };
/* Recover the outter association structure. */ /* Recover the outter association structure. */
static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base) static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -1571,10 +1646,10 @@ static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base) ...@@ -1571,10 +1646,10 @@ static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base)
struct sctp_association * struct sctp_association *
sctp_association_new(const sctp_endpoint_t *, const struct sock *, sctp_association_new(const struct sctp_endpoint *, const struct sock *,
sctp_scope_t scope, int gfp); sctp_scope_t scope, int gfp);
struct sctp_association * struct sctp_association *
sctp_association_init(struct sctp_association *, const sctp_endpoint_t *, sctp_association_init(struct sctp_association *, const struct sctp_endpoint *,
const struct sock *, sctp_scope_t scope, const struct sock *, sctp_scope_t scope,
int gfp); int gfp);
void sctp_association_free(struct sctp_association *); void sctp_association_free(struct sctp_association *);
...@@ -1614,8 +1689,8 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, ...@@ -1614,8 +1689,8 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
int sctp_cmp_addr_exact(const union sctp_addr *ss1, int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2); const union sctp_addr *ss2);
sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc); struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc); struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *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 {
......
...@@ -114,7 +114,7 @@ struct sctp_tsnmap_iter { ...@@ -114,7 +114,7 @@ struct sctp_tsnmap_iter {
}; };
/* Create a new tsnmap. */ /* Create a new tsnmap. */
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority); struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp);
/* Dispose of a tsnmap. */ /* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *); void sctp_tsnmap_free(struct sctp_tsnmap *);
......
...@@ -10,13 +10,15 @@ ...@@ -10,13 +10,15 @@
* sctp_ulpevent type is used to carry information from the state machine * sctp_ulpevent type is used to carry information from the state machine
* upwards to the ULP. * upwards to the ULP.
* *
* The SCTP reference implementation is free software; * This file is part of the SCTP kernel reference Implementation
*
* 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.
...@@ -27,12 +29,17 @@ ...@@ -27,12 +29,17 @@
* 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 one of the * Please send any bug reports or fixes you make to the
* following email addresses: * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
* *
* Jon Grimm <jgrimm@us.ibm.com> * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * Jon Grimm <jgrimm@us.ibm.com>
* Karl Knutson <karl@athena.chicago.il.us> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* *
* 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.
...@@ -64,7 +71,7 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) ...@@ -64,7 +71,7 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
return (struct sctp_ulpevent *)skb->cb; return (struct sctp_ulpevent *)skb->cb;
} }
struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority); struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp);
struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
void sctp_ulpevent_free(struct sctp_ulpevent *); void sctp_ulpevent_free(struct sctp_ulpevent *);
int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
...@@ -76,7 +83,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( ...@@ -76,7 +83,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
__u16 error, __u16 error,
__u16 outbound, __u16 outbound,
__u16 inbound, __u16 inbound,
int priority); int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const struct sctp_association *asoc, const struct sctp_association *asoc,
...@@ -84,32 +91,32 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( ...@@ -84,32 +91,32 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
int flags, int flags,
int state, int state,
int error, int error,
int priority); int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_remote_error( struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const struct sctp_association *asoc, const struct sctp_association *asoc,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
__u16 flags, __u16 flags,
int priority); int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_send_failed( struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
const struct sctp_association *asoc, const struct sctp_association *asoc,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
__u16 flags, __u16 flags,
__u32 error, __u32 error,
int priority); int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const struct sctp_association *asoc, const struct sctp_association *asoc,
__u16 flags, __u16 flags,
int priority); int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_pdapi( struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const struct sctp_association *asoc, const struct sctp_association *asoc,
__u32 indication, int priority); __u32 indication, int gfp);
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
int priority); int gfp);
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
struct msghdr *); struct msghdr *);
......
...@@ -50,14 +50,15 @@ ...@@ -50,14 +50,15 @@
struct sctp_ulpq { struct sctp_ulpq {
char malloced; char malloced;
char pd_mode; char pd_mode;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sk_buff_head reasm; struct sk_buff_head reasm;
struct sk_buff_head lobby; struct sk_buff_head lobby;
}; };
/* Prototypes. */ /* Prototypes. */
struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority); struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp);
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *); struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
struct sctp_association *);
void sctp_ulpq_free(struct sctp_ulpq *); void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */ /* Add a new DATA chunk for processing. */
......
...@@ -110,6 +110,10 @@ enum sctp_optname { ...@@ -110,6 +110,10 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
SCTP_NODELAY, /* Get/set nodelay option. */ SCTP_NODELAY, /* Get/set nodelay option. */
#define SCTP_NODELAY SCTP_NODELAY #define SCTP_NODELAY SCTP_NODELAY
SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */
#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR
SCTP_MAXSEG, /* Get/set maximum fragment. */
#define SCTP_MAXSEG SCTP_MAXSEG
}; };
......
...@@ -43,12 +43,12 @@ config SCTP_ADLER32 ...@@ -43,12 +43,12 @@ config SCTP_ADLER32
bool "SCTP: Use old checksum (Adler-32)" bool "SCTP: Use old checksum (Adler-32)"
depends on IP_SCTP depends on IP_SCTP
help help
RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP.
This has been deprecated and replaced by an algorithm now referred This has been deprecated and replaced by an algorithm now referred
to as crc32c. to as crc32c.
If you say Y, this will use the Adler-32 algorithm, this might be useful If you say Y, this will use the Adler-32 algorithm, this might be
for interoperation with downlevel peers. useful for interoperation with downlevel peers.
If unsure, say N. If unsure, say N.
...@@ -58,19 +58,46 @@ config SCTP_DBG_MSG ...@@ -58,19 +58,46 @@ config SCTP_DBG_MSG
help help
If you say Y, this will enable verbose debugging messages. If you say Y, this will enable verbose debugging messages.
If unsure, say N. However, if you are running into problems, use this If unsure, say N. However, if you are running into problems, use
option to gather detailed trace information this option to gather detailed trace information
config SCTP_DBG_OBJCNT config SCTP_DBG_OBJCNT
bool "SCTP: Debug object counts" bool "SCTP: Debug object counts"
depends on IP_SCTP depends on IP_SCTP
help help
If you say Y, this will enable debugging support for counting the types If you say Y, this will enable debugging support for counting the
of objects that are currently allocated. This is useful for identifying type of objects that are currently allocated. This is useful for
memory leaks. If the /proc filesystem is enabled this debug information identifying memory leaks. If the /proc filesystem is enabled this
can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' debug information can be viewed by
'cat /proc/net/sctp/sctp_dbg_objcnt'
If unsure, say N If unsure, say N
endmenu choice
prompt "SCTP: Cookie HMAC Algorithm"
help
HMAC algorithm to be used during association initialization. It
is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See
configuration for Cryptographic API and enable those algorithms
to make usable by SCTP.
config SCTP_HMAC_NONE
bool "None"
help
Choosing this disables the use of an HMAC during association
establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1.
config SCTP_HMAC_SHA1
bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m
help
Enable the use of HMAC-SHA1 during association establishment. It
is advised to use either HMAC-MD5 or HMAC-SHA1.
config SCTP_HMAC_MD5
bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m
help
Enable the use of HMAC-MD5 during association establishment. It is
advised to use either HMAC-MD5 or HMAC-SHA1.
endchoice
endmenu
...@@ -6,11 +6,10 @@ obj-$(CONFIG_IP_SCTP) += sctp.o ...@@ -6,11 +6,10 @@ obj-$(CONFIG_IP_SCTP) += sctp.o
sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
protocol.o endpointola.o associola.o \ protocol.o endpointola.o associola.o \
transport.o sm_make_chunk.o ulpevent.o \ transport.o chunk.o sm_make_chunk.o ulpevent.o \
inqueue.o outqueue.o ulpqueue.o command.o \ inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \ tsnmap.o bind_addr.o socket.o primitive.o \
output.o input.o hashdriver.o sla1.o \ output.o input.o debug.o ssnmap.o proc.o
debug.o ssnmap.o proc.o
ifeq ($(CONFIG_SCTP_ADLER32), y) ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o sctp-y += adler32.o
......
...@@ -2,43 +2,43 @@ ...@@ -2,43 +2,43 @@
* 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) 2003 International Business Machines, Corp. * Copyright (c) 2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This file has direct heritage from the SCTP user-level reference * This file has direct heritage from the SCTP user-level reference
* implementation by R. Stewart, et al. These functions implement the * implementation by R. Stewart, et al. These functions implement the
* Adler-32 algorithm as specified by RFC 2960. * Adler-32 algorithm as specified by RFC 2960.
* *
* 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:
* Randall Stewart <rstewar1@email.mot.com> * Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com> * Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com> * Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@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.
*/ */
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
* tad, but I have commented the original lines below * tad, but I have commented the original lines below
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#define BASE 65521 /* largest prime smaller than 65536 */ #define BASE 65521 /* largest prime smaller than 65536 */
...@@ -111,7 +111,7 @@ unsigned long update_adler32(unsigned long adler, ...@@ -111,7 +111,7 @@ unsigned long update_adler32(unsigned long adler,
* This would then be (2 * BASE) - 2, which * This would then be (2 * BASE) - 2, which
* will still only do one subtract. On Intel * will still only do one subtract. On Intel
* this is much better to do this way and * this is much better to do this way and
* avoid the divide. Have not -pg'd on * avoid the divide. Have not -pg'd on
* sparc. * sparc.
*/ */
if (s2 >= BASE) { if (s2 >= BASE) {
...@@ -135,7 +135,7 @@ __u32 sctp_start_cksum(__u8 *ptr, __u16 count) ...@@ -135,7 +135,7 @@ __u32 sctp_start_cksum(__u8 *ptr, __u16 count)
__u32 zero = 0L; __u32 zero = 0L;
/* Calculate the CRC up to the checksum field. */ /* Calculate the CRC up to the checksum field. */
adler = update_adler32(adler, ptr, adler = update_adler32(adler, ptr,
sizeof(struct sctphdr) - sizeof(__u32)); sizeof(struct sctphdr) - sizeof(__u32));
/* Skip over the checksum field. */ /* Skip over the checksum field. */
adler = update_adler32(adler, (unsigned char *) &zero, adler = update_adler32(adler, (unsigned char *) &zero,
...@@ -156,6 +156,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler) ...@@ -156,6 +156,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
return adler; return adler;
} }
__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 count, __u32 adler)
{
/* Its not worth it to try harder. Adler32 is obsolescent. */
adler = update_adler32(adler, from, count);
memcpy(to, from, count);
return adler;
}
__u32 sctp_end_cksum(__u32 adler) __u32 sctp_end_cksum(__u32 adler)
{ {
return adler; return adler;
......
...@@ -58,23 +58,23 @@ ...@@ -58,23 +58,23 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
/* Forward declarations for internal functions. */ /* Forward declarations for internal functions. */
static void sctp_assoc_bh_rcv(sctp_association_t *asoc); static void sctp_assoc_bh_rcv(struct sctp_association *asoc);
/* 1st Level Abstractions. */ /* 1st Level Abstractions. */
/* Allocate and initialize a new association */ /* Allocate and initialize a new association */
sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
const struct sock *sk, const struct sock *sk,
sctp_scope_t scope, int priority) sctp_scope_t scope, int gfp)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
asoc = t_new(sctp_association_t, priority); asoc = t_new(struct sctp_association, gfp);
if (!asoc) if (!asoc)
goto fail; goto fail;
if (!sctp_association_init(asoc, ep, sk, scope, priority)) if (!sctp_association_init(asoc, ep, sk, scope, gfp))
goto fail_init; goto fail_init;
asoc->base.malloced = 1; asoc->base.malloced = 1;
...@@ -89,23 +89,24 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, ...@@ -89,23 +89,24 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep,
} }
/* Initialize a new association from provided memory. */ /* Initialize a new association from provided memory. */
sctp_association_t *sctp_association_init(sctp_association_t *asoc, struct sctp_association *sctp_association_init(struct sctp_association *asoc,
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const struct sock *sk, const struct sock *sk,
sctp_scope_t scope, sctp_scope_t scope,
int priority) int gfp)
{ {
struct sctp_opt *sp; struct sctp_opt *sp;
struct sctp_protocol *proto = sctp_get_protocol();
int i; int i;
/* Retrieve the SCTP per socket area. */ /* Retrieve the SCTP per socket area. */
sp = sctp_sk((struct sock *)sk); sp = sctp_sk((struct sock *)sk);
/* Init all variables to a known value. */ /* Init all variables to a known value. */
memset(asoc, 0, sizeof(sctp_association_t)); memset(asoc, 0, sizeof(struct sctp_association));
/* Discarding const is appropriate here. */ /* Discarding const is appropriate here. */
asoc->ep = (sctp_endpoint_t *)ep; asoc->ep = (struct sctp_endpoint *)ep;
sctp_endpoint_hold(asoc->ep); sctp_endpoint_hold(asoc->ep);
/* Hold the sock. */ /* Hold the sock. */
...@@ -136,10 +137,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -136,10 +137,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->frag_point = 0; asoc->frag_point = 0;
/* Initialize the default association max_retrans and RTO values. */ /* Initialize the default association max_retrans and RTO values. */
asoc->max_retrans = ep->proto->max_retrans_association; asoc->max_retrans = proto->max_retrans_association;
asoc->rto_initial = ep->proto->rto_initial; asoc->rto_initial = proto->rto_initial;
asoc->rto_max = ep->proto->rto_max; asoc->rto_max = proto->rto_max;
asoc->rto_min = ep->proto->rto_min; asoc->rto_min = proto->rto_min;
asoc->overall_error_threshold = 0; asoc->overall_error_threshold = 0;
asoc->overall_error_count = 0; asoc->overall_error_count = 0;
...@@ -147,7 +148,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -147,7 +148,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Initialize the maximum mumber of new data packets that can be sent /* Initialize the maximum mumber of new data packets that can be sent
* in a burst. * in a burst.
*/ */
asoc->max_burst = ep->proto->max_burst; asoc->max_burst = proto->max_burst;
/* Copy things from the endpoint. */ /* Copy things from the endpoint. */
for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) {
...@@ -255,7 +256,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -255,7 +256,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
sctp_packet_transmit_chunk, sctp_packet_transmit_chunk,
sctp_packet_transmit); sctp_packet_transmit);
if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc)) if (!sctp_ulpq_init(&asoc->ulpq, asoc))
goto fail_init; goto fail_init;
/* Set up the tsn tracking. */ /* Set up the tsn tracking. */
...@@ -265,7 +266,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -265,7 +266,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->need_ecne = 0; asoc->need_ecne = 0;
asoc->debug_name = "unnamedasoc";
asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; asoc->eyecatcher = SCTP_ASSOC_EYECATCHER;
/* Assume that peer would support both address types unless we are /* Assume that peer would support both address types unless we are
...@@ -288,7 +288,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -288,7 +288,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Free this association if possible. There may still be users, so /* Free this association if possible. There may still be users, so
* the actual deallocation may be delayed. * the actual deallocation may be delayed.
*/ */
void sctp_association_free(sctp_association_t *asoc) void sctp_association_free(struct sctp_association *asoc)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct sctp_transport *transport; struct sctp_transport *transport;
...@@ -298,8 +298,7 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -298,8 +298,7 @@ void sctp_association_free(sctp_association_t *asoc)
list_del(&asoc->asocs); list_del(&asoc->asocs);
/* Decrement the backlog value for a TCP-style listening socket. */ /* Decrement the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog--; sk->ack_backlog--;
/* Mark as dead, so other users can know this structure is /* Mark as dead, so other users can know this structure is
...@@ -351,7 +350,7 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -351,7 +350,7 @@ void sctp_association_free(sctp_association_t *asoc)
} }
/* Cleanup and free up an association. */ /* Cleanup and free up an association. */
static void sctp_association_destroy(sctp_association_t *asoc) static void sctp_association_destroy(struct sctp_association *asoc)
{ {
SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return);
...@@ -379,31 +378,56 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, ...@@ -379,31 +378,56 @@ void sctp_assoc_set_primary(struct sctp_association *asoc,
*/ */
if (transport->active) if (transport->active)
asoc->peer.active_path = transport; asoc->peer.active_path = transport;
/*
* SFR-CACC algorithm:
* Upon the receipt of a request to change the primary
* destination address, on the data structure for the new
* primary destination, the sender MUST do the following:
*
* 1) If CHANGEOVER_ACTIVE is set, then there was a switch
* to this destination address earlier. The sender MUST set
* CYCLING_CHANGEOVER to indicate that this switch is a
* double switch to the same destination address.
*/
if (transport->cacc.changeover_active)
transport->cacc.cycling_changeover = 1;
/* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that
* a changeover has occurred.
*/
transport->cacc.changeover_active = 1;
/* 3) The sender MUST store the next TSN to be sent in
* next_tsn_at_change.
*/
transport->cacc.next_tsn_at_change = asoc->next_tsn;
} }
/* Add a transport address to an association. */ /* Add a transport address to an association. */
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
const union sctp_addr *addr, const union sctp_addr *addr,
int priority) int gfp)
{ {
struct sctp_transport *peer; struct sctp_transport *peer;
struct sctp_opt *sp; struct sctp_opt *sp;
unsigned short port; unsigned short port;
sp = sctp_sk(asoc->base.sk);
/* AF_INET and AF_INET6 share common port field. */ /* AF_INET and AF_INET6 share common port field. */
port = addr->v4.sin_port; port = addr->v4.sin_port;
/* 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;
}
/* 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, gfp);
if (!peer) if (!peer)
return NULL; return NULL;
...@@ -425,7 +449,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -425,7 +449,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
"%d\n", asoc, asoc->pmtu); "%d\n", asoc, asoc->pmtu);
asoc->frag_point = sctp_frag_point(asoc->pmtu); asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);
/* The asoc->peer.port might not be meaningful yet, but /* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway. * initialize the packet structure anyway.
...@@ -470,14 +494,14 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -470,14 +494,14 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* Initialize the peer's heartbeat interval based on the /* Initialize the peer's heartbeat interval based on the
* sock configured value. * sock configured value.
*/ */
sp = sctp_sk(asoc->base.sk);
peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ;
/* Attach the remote transport to our asoc. */ /* Attach the remote transport to our asoc. */
list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
/* If we do not yet have a primary path, set one. */ /* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) { if (!asoc->peer.primary_path) {
sctp_assoc_set_primary(asoc, peer); sctp_assoc_set_primary(asoc, peer);
asoc->peer.retran_path = peer; asoc->peer.retran_path = peer;
} }
...@@ -489,8 +513,9 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -489,8 +513,9 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
} }
/* Lookup a transport by address. */ /* Lookup a transport by address. */
struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, struct sctp_transport *sctp_assoc_lookup_paddr(
const union sctp_addr *address) const struct sctp_association *asoc,
const union sctp_addr *address)
{ {
struct sctp_transport *t; struct sctp_transport *t;
struct list_head *pos; struct list_head *pos;
...@@ -510,7 +535,7 @@ struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, ...@@ -510,7 +535,7 @@ struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc,
* Mark the transport up or down and send a notification to the user. * Mark the transport up or down and send a notification to the user.
* Select and update the new active and retran paths. * Select and update the new active and retran paths.
*/ */
void sctp_assoc_control_transport(sctp_association_t *asoc, void sctp_assoc_control_transport(struct sctp_association *asoc,
struct sctp_transport *transport, struct sctp_transport *transport,
sctp_transport_cmd_t command, sctp_transport_cmd_t command,
sctp_sn_error_t error) sctp_sn_error_t error)
...@@ -589,7 +614,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -589,7 +614,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
/* If we failed to find a usable transport, just camp on the /* If we failed to find a usable transport, just camp on the
* primary, even if it is inactive. * primary, even if it is inactive.
*/ */
if (NULL == first) { if (!first) {
first = asoc->peer.primary_path; first = asoc->peer.primary_path;
second = asoc->peer.primary_path; second = asoc->peer.primary_path;
} }
...@@ -600,7 +625,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -600,7 +625,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
} }
/* Hold a reference to an association. */ /* Hold a reference to an association. */
void sctp_association_hold(sctp_association_t *asoc) void sctp_association_hold(struct sctp_association *asoc)
{ {
atomic_inc(&asoc->base.refcnt); atomic_inc(&asoc->base.refcnt);
} }
...@@ -608,7 +633,7 @@ void sctp_association_hold(sctp_association_t *asoc) ...@@ -608,7 +633,7 @@ void sctp_association_hold(sctp_association_t *asoc)
/* Release a reference to an association and cleanup /* Release a reference to an association and cleanup
* if there are no more references. * if there are no more references.
*/ */
void sctp_association_put(sctp_association_t *asoc) void sctp_association_put(struct sctp_association *asoc)
{ {
if (atomic_dec_and_test(&asoc->base.refcnt)) if (atomic_dec_and_test(&asoc->base.refcnt))
sctp_association_destroy(asoc); sctp_association_destroy(asoc);
...@@ -617,7 +642,7 @@ void sctp_association_put(sctp_association_t *asoc) ...@@ -617,7 +642,7 @@ void sctp_association_put(sctp_association_t *asoc)
/* Allocate the next TSN, Transmission Sequence Number, for the given /* Allocate the next TSN, Transmission Sequence Number, for the given
* association. * association.
*/ */
__u32 sctp_association_get_next_tsn(sctp_association_t *asoc) __u32 sctp_association_get_next_tsn(struct sctp_association *asoc)
{ {
/* From Section 1.6 Serial Number Arithmetic: /* From Section 1.6 Serial Number Arithmetic:
* Transmission Sequence Numbers wrap around when they reach * Transmission Sequence Numbers wrap around when they reach
...@@ -632,7 +657,7 @@ __u32 sctp_association_get_next_tsn(sctp_association_t *asoc) ...@@ -632,7 +657,7 @@ __u32 sctp_association_get_next_tsn(sctp_association_t *asoc)
} }
/* Allocate 'num' TSNs by incrementing the association's TSN by num. */ /* Allocate 'num' TSNs by incrementing the association's TSN by num. */
__u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num) __u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num)
{ {
__u32 retval = asoc->next_tsn; __u32 retval = asoc->next_tsn;
...@@ -662,7 +687,7 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, ...@@ -662,7 +687,7 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1,
* Note: We are sly and return a shared, prealloced chunk. FIXME: * Note: We are sly and return a shared, prealloced chunk. FIXME:
* No we don't, but we could/should. * No we don't, but we could/should.
*/ */
sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc) struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc)
{ {
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
...@@ -680,7 +705,7 @@ sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc) ...@@ -680,7 +705,7 @@ sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc)
/* Use this function for the packet prepend callback when no ECNE /* Use this function for the packet prepend callback when no ECNE
* packet is desired (e.g. some packets don't like to be bundled). * packet is desired (e.g. some packets don't like to be bundled).
*/ */
sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc)
{ {
return NULL; return NULL;
} }
...@@ -688,13 +713,14 @@ sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) ...@@ -688,13 +713,14 @@ sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc)
/* /*
* Find which transport this TSN was sent on. * Find which transport this TSN was sent on.
*/ */
struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
__u32 tsn)
{ {
struct sctp_transport *active; struct sctp_transport *active;
struct sctp_transport *match; struct sctp_transport *match;
struct list_head *entry, *pos; struct list_head *entry, *pos;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
__u32 key = htonl(tsn); __u32 key = htonl(tsn);
match = NULL; match = NULL;
...@@ -717,7 +743,7 @@ struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn ...@@ -717,7 +743,7 @@ struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn
active = asoc->peer.active_path; active = asoc->peer.active_path;
list_for_each(entry, &active->transmitted) { list_for_each(entry, &active->transmitted) {
chunk = list_entry(entry, sctp_chunk_t, transmitted_list); chunk = list_entry(entry, struct sctp_chunk, transmitted_list);
if (key == chunk->subh.data_hdr->tsn) { if (key == chunk->subh.data_hdr->tsn) {
match = active; match = active;
...@@ -732,7 +758,7 @@ struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn ...@@ -732,7 +758,7 @@ struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn
if (transport == active) if (transport == active)
break; break;
list_for_each(entry, &transport->transmitted) { list_for_each(entry, &transport->transmitted) {
chunk = list_entry(entry, sctp_chunk_t, chunk = list_entry(entry, struct sctp_chunk,
transmitted_list); transmitted_list);
if (key == chunk->subh.data_hdr->tsn) { if (key == chunk->subh.data_hdr->tsn) {
match = transport; match = transport;
...@@ -745,7 +771,7 @@ struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn ...@@ -745,7 +771,7 @@ struct sctp_transport *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? */
struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc, struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
const union sctp_addr *laddr, const union sctp_addr *laddr,
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
...@@ -771,10 +797,10 @@ struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc, ...@@ -771,10 +797,10 @@ struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc,
} }
/* Do delayed input processing. This is scheduled by sctp_rcv(). */ /* Do delayed input processing. This is scheduled by sctp_rcv(). */
static void sctp_assoc_bh_rcv(sctp_association_t *asoc) static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sock *sk; struct sock *sk;
struct sctp_inq *inqueue; struct sctp_inq *inqueue;
int state, subtype; int state, subtype;
...@@ -819,7 +845,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -819,7 +845,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
} }
/* 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. */
void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk)
{ {
struct sctp_opt *newsp = sctp_sk(newsk); struct sctp_opt *newsp = sctp_sk(newsk);
struct sock *oldsk = assoc->base.sk; struct sock *oldsk = assoc->base.sk;
...@@ -830,7 +856,7 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) ...@@ -830,7 +856,7 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
list_del(&assoc->asocs); list_del(&assoc->asocs);
/* Decrement the backlog value for a TCP-style socket. */ /* Decrement the backlog value for a TCP-style socket. */
if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type) if (sctp_style(oldsk, TCP))
oldsk->ack_backlog--; oldsk->ack_backlog--;
/* Release references to the old endpoint and the sock. */ /* Release references to the old endpoint and the sock. */
...@@ -850,7 +876,8 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) ...@@ -850,7 +876,8 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
} }
/* Update an association (possibly from unexpected COOKIE-ECHO processing). */ /* Update an association (possibly from unexpected COOKIE-ECHO processing). */
void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) void sctp_assoc_update(struct sctp_association *asoc,
struct sctp_association *new)
{ {
/* Copy in new parameters of peer. */ /* Copy in new parameters of peer. */
asoc->c = new->c; asoc->c = new->c;
...@@ -872,7 +899,7 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) ...@@ -872,7 +899,7 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
* current next_tsn in case data sent to peer * current next_tsn in case data sent to peer
* has been discarded and needs retransmission. * has been discarded and needs retransmission.
*/ */
if (SCTP_STATE_ESTABLISHED == asoc->state) { if (sctp_state(asoc, ESTABLISHED)) {
asoc->next_tsn = new->next_tsn; asoc->next_tsn = new->next_tsn;
asoc->ctsn_ack_point = new->ctsn_ack_point; asoc->ctsn_ack_point = new->ctsn_ack_point;
...@@ -898,7 +925,7 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) ...@@ -898,7 +925,7 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
* through the inactive transports as this is the next best thing * through the inactive transports as this is the next best thing
* we can try. * we can try.
*/ */
void sctp_assoc_update_retran_path(sctp_association_t *asoc) void sctp_assoc_update_retran_path(struct sctp_association *asoc)
{ {
struct sctp_transport *t, *next; struct sctp_transport *t, *next;
struct list_head *head = &asoc->peer.transport_addr_list; struct list_head *head = &asoc->peer.transport_addr_list;
...@@ -944,7 +971,8 @@ void sctp_assoc_update_retran_path(sctp_association_t *asoc) ...@@ -944,7 +971,8 @@ void sctp_assoc_update_retran_path(sctp_association_t *asoc)
} }
/* Choose the transport for sending a SHUTDOWN packet. */ /* Choose the transport for sending a SHUTDOWN packet. */
struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) struct sctp_transport *sctp_assoc_choose_shutdown_transport(
struct sctp_association *asoc)
{ {
/* If this is the first time SHUTDOWN is sent, use the active path, /* If this is the first time SHUTDOWN is sent, use the active path,
* else use the retran path. If the last SHUTDOWN was sent over the * else use the retran path. If the last SHUTDOWN was sent over the
...@@ -963,7 +991,7 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t * ...@@ -963,7 +991,7 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
/* Update the association's pmtu and frag_point by going through all the /* Update the association's pmtu and frag_point by going through all the
* transports. This routine is called when a transport's PMTU has changed. * transports. This routine is called when a transport's PMTU has changed.
*/ */
void sctp_assoc_sync_pmtu(sctp_association_t *asoc) void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
{ {
struct sctp_transport *t; struct sctp_transport *t;
struct list_head *pos; struct list_head *pos;
...@@ -980,8 +1008,9 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc) ...@@ -980,8 +1008,9 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
} }
if (pmtu) { if (pmtu) {
struct sctp_opt *sp = sctp_sk(asoc->base.sk);
asoc->pmtu = pmtu; asoc->pmtu = pmtu;
asoc->frag_point = sctp_frag_point(pmtu); asoc->frag_point = sctp_frag_point(sp, pmtu);
} }
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
...@@ -1007,9 +1036,9 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) ...@@ -1007,9 +1036,9 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
} }
/* Increase asoc's rwnd by len and send any window update SACK if needed. */ /* Increase asoc's rwnd by len and send any window update SACK if needed. */
void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len)
{ {
sctp_chunk_t *sack; struct sctp_chunk *sack;
struct timer_list *timer; struct timer_list *timer;
if (asoc->rwnd_over) { if (asoc->rwnd_over) {
...@@ -1053,7 +1082,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -1053,7 +1082,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
} }
/* Decrease asoc's rwnd by len. */ /* Decrease asoc's rwnd by len. */
void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len) void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len)
{ {
SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); SCTP_ASSERT(asoc->rwnd, "rwnd zero", return);
SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);
...@@ -1092,7 +1121,7 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp) ...@@ -1092,7 +1121,7 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp)
} }
/* Build the association's bind address list from the cookie. */ /* Build the association's bind address list from the cookie. */
int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *asoc, int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
sctp_cookie_t *cookie, int gfp) sctp_cookie_t *cookie, int gfp)
{ {
int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);
......
...@@ -52,16 +52,17 @@ ...@@ -52,16 +52,17 @@
#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 *, union sctp_addr *, static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *,
sctp_scope_t scope, int gfp, int flags); sctp_scope_t scope, int gfp, int flags);
static void sctp_bind_addr_clean(sctp_bind_addr_t *); static void sctp_bind_addr_clean(struct sctp_bind_addr *);
/* First Level Abstractions. */ /* First Level Abstractions. */
/* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses
* in 'src' which have a broader scope than 'scope'. * in 'src' which have a broader scope than 'scope'.
*/ */
int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src,
sctp_scope_t scope, int gfp, int flags) sctp_scope_t scope, int gfp, int flags)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
...@@ -80,6 +81,22 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, ...@@ -80,6 +81,22 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
goto out; goto out;
} }
/* If there are no addresses matching the scope and
* this is global scope, try to get a link scope address, with
* the assumption that we must be sitting behind a NAT.
*/
if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
list_for_each(pos, &src->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list,
list);
error = sctp_copy_one_addr(dest, &addr->a,
SCTP_SCOPE_LINK, gfp,
flags);
if (error < 0)
goto out;
}
}
out: out:
if (error) if (error)
sctp_bind_addr_clean(dest); sctp_bind_addr_clean(dest);
...@@ -88,11 +105,11 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, ...@@ -88,11 +105,11 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
} }
/* Create a new SCTP_bind_addr from nothing. */ /* Create a new SCTP_bind_addr from nothing. */
sctp_bind_addr_t *sctp_bind_addr_new(int gfp) struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
{ {
sctp_bind_addr_t *retval; struct sctp_bind_addr *retval;
retval = t_new(sctp_bind_addr_t, gfp); retval = t_new(struct sctp_bind_addr, gfp);
if (!retval) if (!retval)
goto nomem; goto nomem;
...@@ -107,7 +124,7 @@ sctp_bind_addr_t *sctp_bind_addr_new(int gfp) ...@@ -107,7 +124,7 @@ sctp_bind_addr_t *sctp_bind_addr_new(int gfp)
/* Initialize the SCTP_bind_addr structure for either an endpoint or /* Initialize the SCTP_bind_addr structure for either an endpoint or
* an association. * an association.
*/ */
void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
{ {
bp->malloced = 0; bp->malloced = 0;
...@@ -116,7 +133,7 @@ void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) ...@@ -116,7 +133,7 @@ void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port)
} }
/* Dispose of the address list. */ /* Dispose of the address list. */
static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
...@@ -131,7 +148,7 @@ static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) ...@@ -131,7 +148,7 @@ static void sctp_bind_addr_clean(sctp_bind_addr_t *bp)
} }
/* Dispose of an SCTP_bind_addr structure */ /* Dispose of an SCTP_bind_addr structure */
void sctp_bind_addr_free(sctp_bind_addr_t *bp) void sctp_bind_addr_free(struct sctp_bind_addr *bp)
{ {
/* Empty the bind address list. */ /* Empty the bind address list. */
sctp_bind_addr_clean(bp); sctp_bind_addr_clean(bp);
...@@ -143,7 +160,7 @@ void sctp_bind_addr_free(sctp_bind_addr_t *bp) ...@@ -143,7 +160,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, union sctp_addr *new, int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
int gfp) int gfp)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
...@@ -171,7 +188,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new, ...@@ -171,7 +188,7 @@ int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *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, union sctp_addr *del_addr) int sctp_del_bind_addr(struct sctp_bind_addr *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,7 +213,7 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) ...@@ -196,7 +213,7 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr)
* *
* The second argument is the return value for the length. * The second argument is the return value for the length.
*/ */
union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int *addrs_len, int gfp) int *addrs_len, int gfp)
{ {
union sctp_params addrparms; union sctp_params addrparms;
...@@ -214,6 +231,14 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, ...@@ -214,6 +231,14 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
len += sizeof(sctp_addr_param_t); len += sizeof(sctp_addr_param_t);
} }
/* Don't even bother embedding an address if there
* is only one.
*/
if (len == sizeof(sctp_addr_param_t)) {
retval.v = NULL;
goto end_raw;
}
retval.v = kmalloc(len, gfp); retval.v = kmalloc(len, gfp);
if (!retval.v) if (!retval.v)
goto end_raw; goto end_raw;
...@@ -237,7 +262,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, ...@@ -237,7 +262,7 @@ union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
* Create an address list out of the raw address list format (IPv4 and IPv6 * Create an address list out of the raw address list format (IPv4 and IPv6
* address parameters). * address parameters).
*/ */
int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
int addrs_len, __u16 port, int gfp) int addrs_len, __u16 port, int gfp)
{ {
sctp_addr_param_t *rawaddr; sctp_addr_param_t *rawaddr;
...@@ -283,7 +308,8 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ...@@ -283,7 +308,8 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
********************************************************************/ ********************************************************************/
/* Does this contain a specified address? Allow wildcarding. */ /* Does this contain a specified address? Allow wildcarding. */
int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, int sctp_bind_addr_match(struct sctp_bind_addr *bp,
const union sctp_addr *addr,
struct sctp_opt *opt) struct sctp_opt *opt)
{ {
struct sockaddr_storage_list *laddr; struct sockaddr_storage_list *laddr;
...@@ -299,7 +325,8 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, ...@@ -299,7 +325,8 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *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, union sctp_addr *addr, static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union sctp_addr *addr,
sctp_scope_t scope, int gfp, int flags) sctp_scope_t scope, int gfp, int flags)
{ {
struct sctp_protocol *proto = sctp_get_protocol(); struct sctp_protocol *proto = sctp_get_protocol();
......
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* This file contains the code relating the the chunk abstraction.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* This file is mostly in anticipation of future work, but initially
* populate with fragment tracking for an outbound message.
*/
/* Initialize datamsg from memory. */
void sctp_datamsg_init(struct sctp_datamsg *msg)
{
atomic_set(&msg->refcnt, 1);
msg->send_failed = 0;
msg->send_error = 0;
msg->can_expire = 0;
INIT_LIST_HEAD(&msg->chunks);
}
/* Allocate and initialize datamsg. */
struct sctp_datamsg *sctp_datamsg_new(int gfp)
{
struct sctp_datamsg *msg;
msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
if (msg)
sctp_datamsg_init(msg);
SCTP_DBG_OBJCNT_INC(datamsg);
return msg;
}
/* Final destructruction of datamsg memory. */
static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
{
struct list_head *pos, *temp;
struct sctp_chunk *chunk;
struct sctp_opt *sp;
struct sctp_ulpevent *ev;
struct sctp_association *asoc = NULL;
int error = 0, notify;
/* If we failed, we may need to notify. */
notify = msg->send_failed ? -1 : 0;
/* Release all references. */
list_for_each_safe(pos, temp, &msg->chunks) {
list_del(pos);
chunk = list_entry(pos, struct sctp_chunk, frag_list);
/* Check whether we _really_ need to notify. */
if (notify < 0) {
asoc = chunk->asoc;
if (msg->send_error)
error = msg->send_error;
else
error = asoc->outqueue.error;
sp = sctp_sk(asoc->base.sk);
notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED,
&sp->subscribe);
}
/* Generate a SEND FAILED event only if enabled. */
if (notify > 0) {
int sent;
if (chunk->has_tsn)
sent = SCTP_DATA_SENT;
else
sent = SCTP_DATA_UNSENT;
ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
error, GFP_ATOMIC);
if (ev)
sctp_ulpq_tail_event(&asoc->ulpq, ev);
}
sctp_chunk_put(chunk);
}
SCTP_DBG_OBJCNT_DEC(datamsg);
kfree(msg);
}
/* Hold a reference. */
void sctp_datamsg_hold(struct sctp_datamsg *msg)
{
atomic_inc(&msg->refcnt);
}
/* Release a reference. */
void sctp_datamsg_put(struct sctp_datamsg *msg)
{
if (atomic_dec_and_test(&msg->refcnt))
sctp_datamsg_destroy(msg);
}
/* Free a message. Really just give up a reference, the
* really free happens in sctp_datamsg_destroy().
*/
void sctp_datamsg_free(struct sctp_datamsg *msg)
{
sctp_datamsg_put(msg);
}
/* Hold on to all the fragments until all chunks have been sent. */
void sctp_datamsg_track(struct sctp_chunk *chunk)
{
sctp_chunk_hold(chunk);
}
/* Assign a chunk to this datamsg. */
void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
{
sctp_datamsg_hold(msg);
chunk->msg = msg;
}
/* A data chunk can have a maximum payload of (2^16 - 20). Break
* down any such message into smaller chunks. Opportunistically, fragment
* the chunks down to the current MTU constraints. We may get refragmented
* later if the PMTU changes, but it is _much better_ to fragment immediately
* with a reasonable guess than always doing our fragmentation on the
* soft-interrupt.
*/
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct sctp_sndrcvinfo *sinfo,
struct msghdr *msgh, int msg_len)
{
int max, whole, i, offset, over, err;
int len, first_len;
struct sctp_chunk *chunk;
struct sctp_datamsg *msg;
struct list_head *pos, *temp;
__u8 frag;
msg = sctp_datamsg_new(GFP_KERNEL);
if (!msg)
return NULL;
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
*/
if (sinfo->sinfo_timetolive) {
struct timeval tv;
__u32 ttl = sinfo->sinfo_timetolive;
/* sinfo_timetolive is in milliseconds */
tv.tv_sec = ttl / 1000;
tv.tv_usec = ttl % 1000 * 1000;
msg->expires_at = jiffies + timeval_to_jiffies(&tv);
msg->can_expire = 1;
}
/* What is a reasonable fragmentation point right now? */
max = asoc->pmtu;
if (max < SCTP_MIN_PMTU)
max = SCTP_MIN_PMTU;
max -= SCTP_IP_OVERHEAD;
/* Make sure not beyond maximum chunk size. */
if (max > SCTP_MAX_CHUNK_LEN)
max = SCTP_MAX_CHUNK_LEN;
/* Subtract out the overhead of a data chunk header. */
max -= sizeof(struct sctp_data_chunk);
whole = 0;
/* If user has specified smaller fragmentation, make it so. */
if (sctp_sk(asoc->base.sk)->user_frag)
max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag);
first_len = max;
/* Encourage Cookie-ECHO bundling. */
if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
/* Account for the DATA to be bundled with the COOKIE-ECHO. */
if (whole) {
first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
msg_len -= first_len;
whole = 1;
}
}
/* How many full sized? How many bytes leftover? */
whole += msg_len / max;
over = msg_len % max;
offset = 0;
if ((whole > 1) || (whole && over))
SCTP_INC_STATS_USER(SctpFragUsrMsgs);
/* Create chunks for all the full sized DATA chunks. */
for (i=0, len=first_len; i < whole; i++) {
frag = SCTP_DATA_MIDDLE_FRAG;
if (0 == i)
frag |= SCTP_DATA_FIRST_FRAG;
if ((i == (whole - 1)) && !over)
frag |= SCTP_DATA_LAST_FRAG;
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
if (!chunk)
goto errout;
err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov);
if (err < 0)
goto errout;
offset += len;
/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks);
/* The first chunk, the first chunk was likely short
* to allow bundling, so reset to full size.
*/
if (0 == i)
len = max;
}
/* .. now the leftover bytes. */
if (over) {
if (!whole)
frag = SCTP_DATA_NOT_FRAG;
else
frag = SCTP_DATA_LAST_FRAG;
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
if (!chunk)
goto errout;
err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov);
/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
if (err < 0)
goto errout;
sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks);
}
return msg;
errout:
list_for_each_safe(pos, temp, &msg->chunks) {
list_del(pos);
chunk = list_entry(pos, struct sctp_chunk, frag_list);
sctp_chunk_free(chunk);
}
sctp_datamsg_free(msg);
return NULL;
}
/* Check whether this message has expired. */
int sctp_datamsg_expires(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg = chunk->msg;
/* FIXME: When PR-SCTP is supported we can make this
* check more lenient.
*/
if (!msg->can_expire)
return 0;
if (time_after(jiffies, msg->expires_at))
return 1;
return 0;
}
/* This chunk (and consequently entire message) has failed in its sending. */
void sctp_datamsg_fail(struct sctp_chunk *chunk, int error)
{
chunk->msg->send_failed = 1;
chunk->msg->send_error = error;
}
...@@ -43,9 +43,9 @@ ...@@ -43,9 +43,9 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Create a new sctp_command_sequence. */ /* Create a new sctp_command_sequence. */
sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp)
{ {
sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority); sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp);
if (retval) if (retval)
sctp_init_cmd_seq(retval); sctp_init_cmd_seq(retval);
......
...@@ -170,6 +170,23 @@ __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) ...@@ -170,6 +170,23 @@ __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
return crc32; return crc32;
} }
__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 length, __u32 crc32)
{
__u32 i;
__u32 *_to = (__u32 *)to;
__u32 *_from = (__u32 *)from;
for (i = 0; i < (length/4); i++) {
_to[i] = _from[i];
CRC32C(crc32, from[i*4]);
CRC32C(crc32, from[i*4+1]);
CRC32C(crc32, from[i*4+2]);
CRC32C(crc32, from[i*4+3]);
}
return crc32;
}
__u32 sctp_end_cksum(__u32 crc32) __u32 sctp_end_cksum(__u32 crc32)
{ {
__u32 result; __u32 result;
......
...@@ -54,27 +54,27 @@ ...@@ -54,27 +54,27 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/random.h> /* get_random_bytes() */ #include <linux/random.h> /* get_random_bytes() */
#include <linux/crypto.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Forward declarations for internal helpers. */ /* Forward declarations for internal helpers. */
static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
/* Create a sctp_endpoint_t with all that boring stuff initialized. /* Create a sctp_endpoint with all that boring stuff initialized.
* Returns NULL if there isn't enough memory. * Returns NULL if there isn't enough memory.
*/ */
sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto, struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
struct sock *sk, int priority)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
/* Build a local endpoint. */ /* Build a local endpoint. */
ep = t_new(sctp_endpoint_t, priority); ep = t_new(struct sctp_endpoint, gfp);
if (!ep) if (!ep)
goto fail; goto fail;
if (!sctp_endpoint_init(ep, proto, sk, priority)) if (!sctp_endpoint_init(ep, sk, gfp))
goto fail_init; goto fail_init;
ep->base.malloced = 1; ep->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(ep); SCTP_DBG_OBJCNT_INC(ep);
...@@ -89,12 +89,11 @@ sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto, ...@@ -89,12 +89,11 @@ sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto,
/* /*
* Initialize the base fields of the endpoint structure. * Initialize the base fields of the endpoint structure.
*/ */
sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
struct sctp_protocol *proto, struct sock *sk, int gfp)
struct sock *sk, int priority)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
memset(ep, 0, sizeof(sctp_endpoint_t)); memset(ep, 0, sizeof(struct sctp_endpoint));
/* Initialize the base structure. */ /* Initialize the base structure. */
/* What type of endpoint are we? */ /* What type of endpoint are we? */
...@@ -110,8 +109,7 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ...@@ -110,8 +109,7 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
/* Set its top-half handler */ /* Set its top-half handler */
sctp_inq_set_th_handler(&ep->base.inqueue, sctp_inq_set_th_handler(&ep->base.inqueue,
(void (*)(void *))sctp_endpoint_bh_rcv, (void (*)(void *))sctp_endpoint_bh_rcv, ep);
ep);
/* Initialize the bind addr area */ /* Initialize the bind addr area */
sctp_bind_addr_init(&ep->base.bind_addr, 0); sctp_bind_addr_init(&ep->base.bind_addr, 0);
...@@ -121,21 +119,16 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ...@@ -121,21 +119,16 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
ep->base.sk = sk; ep->base.sk = sk;
sock_hold(ep->base.sk); sock_hold(ep->base.sk);
/* This pointer is useful to access the default protocol parameter
* values.
*/
ep->proto = proto;
/* Create the lists of associations. */ /* Create the lists of associations. */
INIT_LIST_HEAD(&ep->asocs); INIT_LIST_HEAD(&ep->asocs);
/* Set up the base timeout information. */ /* Set up the base timeout information. */
ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
SCTP_DEFAULT_TIMEOUT_T1_COOKIE; SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
SCTP_DEFAULT_TIMEOUT_T1_INIT; SCTP_DEFAULT_TIMEOUT_T1_INIT;
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
sp->rtoinfo.srto_initial; sp->rtoinfo.srto_initial;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
...@@ -146,11 +139,11 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ...@@ -146,11 +139,11 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
= 5 * sp->rtoinfo.srto_max; = 5 * sp->rtoinfo.srto_max;
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
SCTP_DEFAULT_TIMEOUT_HEARTBEAT; SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
SCTP_DEFAULT_TIMEOUT_SACK; SCTP_DEFAULT_TIMEOUT_SACK;
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ; sp->autoclose * HZ;
/* Set up the default send/receive buffer space. */ /* Set up the default send/receive buffer space. */
...@@ -175,7 +168,8 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, ...@@ -175,7 +168,8 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
} }
/* Add an association to an endpoint. */ /* Add an association to an endpoint. */
void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
struct sctp_association *asoc)
{ {
struct sock *sk = ep->base.sk; struct sock *sk = ep->base.sk;
...@@ -183,22 +177,21 @@ void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) ...@@ -183,22 +177,21 @@ void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc)
list_add_tail(&asoc->asocs, &ep->asocs); list_add_tail(&asoc->asocs, &ep->asocs);
/* Increment the backlog value for a TCP-style listening socket. */ /* Increment the backlog value for a TCP-style listening socket. */
if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
(SCTP_SS_LISTENING == sk->state))
sk->ack_backlog++; sk->ack_backlog++;
} }
/* Free the endpoint structure. Delay cleanup until /* Free the endpoint structure. Delay cleanup until
* all users have released their reference count on this structure. * all users have released their reference count on this structure.
*/ */
void sctp_endpoint_free(sctp_endpoint_t *ep) void sctp_endpoint_free(struct sctp_endpoint *ep)
{ {
ep->base.dead = 1; ep->base.dead = 1;
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
} }
/* Final destructor for endpoint. */ /* Final destructor for endpoint. */
void sctp_endpoint_destroy(sctp_endpoint_t *ep) void sctp_endpoint_destroy(struct sctp_endpoint *ep)
{ {
SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
...@@ -207,9 +200,12 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) ...@@ -207,9 +200,12 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
/* Unlink this endpoint, so we can't find it again! */ /* Unlink this endpoint, so we can't find it again! */
sctp_unhash_endpoint(ep); sctp_unhash_endpoint(ep);
/* Cleanup the inqueue. */ /* Free up the HMAC transform. */
sctp_inq_free(&ep->base.inqueue); if (sctp_sk(ep->base.sk)->hmac)
sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
/* Cleanup. */
sctp_inq_free(&ep->base.inqueue);
sctp_bind_addr_free(&ep->base.bind_addr); sctp_bind_addr_free(&ep->base.bind_addr);
/* Remove and free the port */ /* Remove and free the port */
...@@ -228,7 +224,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) ...@@ -228,7 +224,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
} }
/* Hold a reference to an endpoint. */ /* Hold a reference to an endpoint. */
void sctp_endpoint_hold(sctp_endpoint_t *ep) void sctp_endpoint_hold(struct sctp_endpoint *ep)
{ {
atomic_inc(&ep->base.refcnt); atomic_inc(&ep->base.refcnt);
} }
...@@ -236,17 +232,17 @@ void sctp_endpoint_hold(sctp_endpoint_t *ep) ...@@ -236,17 +232,17 @@ void sctp_endpoint_hold(sctp_endpoint_t *ep)
/* Release a reference to an endpoint and clean up if there are /* Release a reference to an endpoint and clean up if there are
* no more references. * no more references.
*/ */
void sctp_endpoint_put(sctp_endpoint_t *ep) void sctp_endpoint_put(struct sctp_endpoint *ep)
{ {
if (atomic_dec_and_test(&ep->base.refcnt)) if (atomic_dec_and_test(&ep->base.refcnt))
sctp_endpoint_destroy(ep); sctp_endpoint_destroy(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, struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
const union sctp_addr *laddr) const union sctp_addr *laddr)
{ {
sctp_endpoint_t *retval; struct sctp_endpoint *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) {
...@@ -268,19 +264,19 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -268,19 +264,19 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
* We do a linear search of the associations for this endpoint. * We do a linear search of the associations for this endpoint.
* We return the matching transport address too. * We return the matching transport address too.
*/ */
sctp_association_t *__sctp_endpoint_lookup_assoc( struct sctp_association *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint, const struct sctp_endpoint *ep,
const union sctp_addr *paddr, const union sctp_addr *paddr,
struct sctp_transport **transport) struct sctp_transport **transport)
{ {
int rport; int rport;
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
rport = paddr->v4.sin_port; rport = paddr->v4.sin_port;
list_for_each(pos, &endpoint->asocs) { list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, sctp_association_t, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
if (rport == asoc->peer.port) { if (rport == asoc->peer.port) {
sctp_read_lock(&asoc->base.addr_lock); sctp_read_lock(&asoc->base.addr_lock);
*transport = sctp_assoc_lookup_paddr(asoc, paddr); *transport = sctp_assoc_lookup_paddr(asoc, paddr);
...@@ -296,12 +292,12 @@ sctp_association_t *__sctp_endpoint_lookup_assoc( ...@@ -296,12 +292,12 @@ 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( struct sctp_association *sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const union sctp_addr *paddr, const union sctp_addr *paddr,
struct sctp_transport **transport) struct sctp_transport **transport)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
sctp_local_bh_disable(); sctp_local_bh_disable();
asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport);
...@@ -313,12 +309,12 @@ sctp_association_t *sctp_endpoint_lookup_assoc( ...@@ -313,12 +309,12 @@ sctp_association_t *sctp_endpoint_lookup_assoc(
/* Look for any peeled off association from the endpoint that matches the /* Look for any peeled off association from the endpoint that matches the
* given peer address. * given peer address.
*/ */
int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
struct list_head *pos; struct list_head *pos;
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
sctp_read_lock(&ep->base.addr_lock); sctp_read_lock(&ep->base.addr_lock);
bp = &ep->base.bind_addr; bp = &ep->base.bind_addr;
...@@ -337,12 +333,12 @@ int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, ...@@ -337,12 +333,12 @@ int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep,
/* 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.
*/ */
static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct sock *sk; struct sock *sk;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sctp_inq *inqueue; struct sctp_inq *inqueue;
sctp_subtype_t subtype; sctp_subtype_t subtype;
sctp_state_t state; sctp_state_t state;
...@@ -355,7 +351,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -355,7 +351,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue = &ep->base.inqueue; inqueue = &ep->base.inqueue;
sk = ep->base.sk; sk = ep->base.sk;
while (NULL != (chunk = sctp_inq_pop(inqueue))) { while (NULL != (chunk = sctp_inq_pop(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
......
...@@ -63,11 +63,11 @@ ...@@ -63,11 +63,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, struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *laddr, const union sctp_addr *laddr,
const union sctp_addr *paddr, const union sctp_addr *paddr,
struct sctp_transport **transportp); struct sctp_transport **transportp);
sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
/* Calculate the SCTP checksum of an SCTP packet. */ /* Calculate the SCTP checksum of an SCTP packet. */
...@@ -102,11 +102,11 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb) ...@@ -102,11 +102,11 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
int sctp_rcv(struct sk_buff *skb) int sctp_rcv(struct sk_buff *skb)
{ {
struct sock *sk; struct sock *sk;
sctp_association_t *asoc; struct sctp_association *asoc;
sctp_endpoint_t *ep = NULL; struct sctp_endpoint *ep = NULL;
sctp_endpoint_common_t *rcvr; struct sctp_ep_common *rcvr;
struct sctp_transport *transport = NULL; struct sctp_transport *transport = NULL;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sctphdr *sh; struct sctphdr *sh;
union sctp_addr src; union sctp_addr src;
union sctp_addr dest; union sctp_addr dest;
...@@ -128,11 +128,11 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -128,11 +128,11 @@ 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));
family = ipver2af(skb->nh.iph->version); family = ipver2af(skb->nh.iph->version);
af = sctp_get_af_specific(family); af = sctp_get_af_specific(family);
if (unlikely(!af)) if (unlikely(!af))
goto bad_packet; goto bad_packet;
/* Initialize local addresses for lookups. */ /* Initialize local addresses for lookups. */
...@@ -224,9 +224,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -224,9 +224,7 @@ int sctp_rcv(struct sk_buff *skb)
return ret; return ret;
bad_packet: bad_packet:
#if 0 /* FIXME */ SCTP_INC_STATS(SctpChecksumErrors);
SCTP_INC_STATS(SctpInErrs);
#endif /* FIXME*/
discard_it: discard_it:
kfree_skb(skb); kfree_skb(skb);
...@@ -252,13 +250,13 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -252,13 +250,13 @@ int sctp_rcv(struct sk_buff *skb)
*/ */
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{ {
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sctp_inq *inqueue; struct sctp_inq *inqueue;
/* One day chunk will live inside the skb, but for /* One day chunk will live inside the skb, but for
* now this works. * now this works.
*/ */
chunk = (sctp_chunk_t *) skb; chunk = (struct sctp_chunk *) skb;
inqueue = &chunk->rcvr->inqueue; inqueue = &chunk->rcvr->inqueue;
sctp_inq_push(inqueue, chunk); sctp_inq_push(inqueue, chunk);
...@@ -286,8 +284,8 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, ...@@ -286,8 +284,8 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
/* Common lookup code for icmp/icmpv6 error handler. */ /* Common lookup code for icmp/icmpv6 error handler. */
struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
struct sctphdr *sctphdr, struct sctphdr *sctphdr,
struct sctp_endpoint **epp, struct sctp_endpoint **epp,
struct sctp_association **app, struct sctp_association **app,
struct sctp_transport **tpp) struct sctp_transport **tpp)
{ {
union sctp_addr saddr; union sctp_addr saddr;
...@@ -309,15 +307,15 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -309,15 +307,15 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
af->from_skb(&saddr, skb, 1); af->from_skb(&saddr, skb, 1);
af->from_skb(&daddr, skb, 0); af->from_skb(&daddr, skb, 0);
/* Look for an association that matches the incoming ICMP error /* Look for an association that matches the incoming ICMP error
* packet. * packet.
*/ */
asoc = __sctp_lookup_association(&saddr, &daddr, &transport); asoc = __sctp_lookup_association(&saddr, &daddr, &transport);
if (!asoc) { if (!asoc) {
/* If there is no matching association, see if it matches any /* If there is no matching association, see if it matches any
* endpoint. This may happen for an ICMP error generated in * endpoint. This may happen for an ICMP error generated in
* response to an INIT_ACK. * response to an INIT_ACK.
*/ */
ep = __sctp_rcv_lookup_endpoint(&daddr); ep = __sctp_rcv_lookup_endpoint(&daddr);
if (!ep) { if (!ep) {
return NULL; return NULL;
...@@ -345,25 +343,25 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, ...@@ -345,25 +343,25 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
*app = asoc; *app = asoc;
*tpp = transport; *tpp = transport;
return sk; return sk;
out: out:
sock_put(sk); sock_put(sk);
if (asoc) if (asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
if (ep) if (ep)
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
return NULL; return NULL;
} }
/* Common cleanup code for icmp/icmpv6 error handler. */ /* Common cleanup code for icmp/icmpv6 error handler. */
void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep,
struct sctp_association *asoc) struct sctp_association *asoc)
{ {
sctp_bh_unlock_sock(sk); sctp_bh_unlock_sock(sk);
sock_put(sk); sock_put(sk);
if (asoc) if (asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
if (ep) if (ep)
sctp_endpoint_put(ep); sctp_endpoint_put(ep);
} }
...@@ -389,8 +387,8 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -389,8 +387,8 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
int type = skb->h.icmph->type; int type = skb->h.icmph->type;
int code = skb->h.icmph->code; int code = skb->h.icmph->code;
struct sock *sk; struct sock *sk;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
struct inet_opt *inet; struct inet_opt *inet;
char *saveip, *savesctp; char *saveip, *savesctp;
...@@ -414,7 +412,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) ...@@ -414,7 +412,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
ICMP_INC_STATS_BH(IcmpInErrors); ICMP_INC_STATS_BH(IcmpInErrors);
return; return;
} }
/* Warning: The sock lock is held. Remember to call /* Warning: The sock lock is held. Remember to call
* sctp_err_finish! * sctp_err_finish!
*/ */
...@@ -520,10 +518,10 @@ int sctp_rcv_ootb(struct sk_buff *skb) ...@@ -520,10 +518,10 @@ int sctp_rcv_ootb(struct sk_buff *skb)
} }
/* Insert endpoint into the hash table. */ /* Insert endpoint into the hash table. */
void __sctp_hash_endpoint(sctp_endpoint_t *ep) void __sctp_hash_endpoint(struct sctp_endpoint *ep)
{ {
sctp_endpoint_common_t **epp; struct sctp_ep_common **epp;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
epb = &ep->base; epb = &ep->base;
...@@ -542,7 +540,7 @@ void __sctp_hash_endpoint(sctp_endpoint_t *ep) ...@@ -542,7 +540,7 @@ void __sctp_hash_endpoint(sctp_endpoint_t *ep)
} }
/* Add an endpoint to the hash. Local BH-safe. */ /* Add an endpoint to the hash. Local BH-safe. */
void sctp_hash_endpoint(sctp_endpoint_t *ep) void sctp_hash_endpoint(struct sctp_endpoint *ep)
{ {
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_hash_endpoint(ep); __sctp_hash_endpoint(ep);
...@@ -550,10 +548,10 @@ void sctp_hash_endpoint(sctp_endpoint_t *ep) ...@@ -550,10 +548,10 @@ void sctp_hash_endpoint(sctp_endpoint_t *ep)
} }
/* Remove endpoint from the hash table. */ /* Remove endpoint from the hash table. */
void __sctp_unhash_endpoint(sctp_endpoint_t *ep) void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
epb = &ep->base; epb = &ep->base;
...@@ -574,7 +572,7 @@ void __sctp_unhash_endpoint(sctp_endpoint_t *ep) ...@@ -574,7 +572,7 @@ void __sctp_unhash_endpoint(sctp_endpoint_t *ep)
} }
/* Remove endpoint from the hash. Local BH-safe. */ /* Remove endpoint from the hash. Local BH-safe. */
void sctp_unhash_endpoint(sctp_endpoint_t *ep) void sctp_unhash_endpoint(struct sctp_endpoint *ep)
{ {
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_unhash_endpoint(ep); __sctp_unhash_endpoint(ep);
...@@ -582,11 +580,11 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep) ...@@ -582,11 +580,11 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep)
} }
/* Look up an endpoint. */ /* Look up an endpoint. */
sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
int hash; int hash;
hash = sctp_ep_hashfn(laddr->v4.sin_port); hash = sctp_ep_hashfn(laddr->v4.sin_port);
...@@ -609,7 +607,7 @@ sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) ...@@ -609,7 +607,7 @@ sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
} }
/* Add an association to the hash. Local BH-safe. */ /* Add an association to the hash. Local BH-safe. */
void sctp_hash_established(sctp_association_t *asoc) void sctp_hash_established(struct sctp_association *asoc)
{ {
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_hash_established(asoc); __sctp_hash_established(asoc);
...@@ -617,10 +615,10 @@ void sctp_hash_established(sctp_association_t *asoc) ...@@ -617,10 +615,10 @@ void sctp_hash_established(sctp_association_t *asoc)
} }
/* Insert association into the hash table. */ /* Insert association into the hash table. */
void __sctp_hash_established(sctp_association_t *asoc) void __sctp_hash_established(struct sctp_association *asoc)
{ {
sctp_endpoint_common_t **epp; struct sctp_ep_common **epp;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
epb = &asoc->base; epb = &asoc->base;
...@@ -641,7 +639,7 @@ void __sctp_hash_established(sctp_association_t *asoc) ...@@ -641,7 +639,7 @@ void __sctp_hash_established(sctp_association_t *asoc)
} }
/* Remove association from the hash table. Local BH-safe. */ /* Remove association from the hash table. Local BH-safe. */
void sctp_unhash_established(sctp_association_t *asoc) void sctp_unhash_established(struct sctp_association *asoc)
{ {
sctp_local_bh_disable(); sctp_local_bh_disable();
__sctp_unhash_established(asoc); __sctp_unhash_established(asoc);
...@@ -649,10 +647,10 @@ void sctp_unhash_established(sctp_association_t *asoc) ...@@ -649,10 +647,10 @@ void sctp_unhash_established(sctp_association_t *asoc)
} }
/* Remove association from the hash table. */ /* Remove association from the hash table. */
void __sctp_unhash_established(sctp_association_t *asoc) void __sctp_unhash_established(struct sctp_association *asoc)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
epb = &asoc->base; epb = &asoc->base;
...@@ -674,13 +672,14 @@ void __sctp_unhash_established(sctp_association_t *asoc) ...@@ -674,13 +672,14 @@ void __sctp_unhash_established(sctp_association_t *asoc)
} }
/* Look up an association. */ /* Look up an association. */
sctp_association_t *__sctp_lookup_association(const union sctp_addr *local, struct sctp_association *__sctp_lookup_association(
const union sctp_addr *peer, const union sctp_addr *local,
struct sctp_transport **pt) const union sctp_addr *peer,
struct sctp_transport **pt)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; struct sctp_ep_common *epb;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
int hash; int hash;
...@@ -710,11 +709,11 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *local, ...@@ -710,11 +709,11 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *local,
} }
/* Look up an association. BH-safe. */ /* Look up an association. BH-safe. */
sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr, const union sctp_addr *paddr,
struct sctp_transport **transportp) struct sctp_transport **transportp)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
sctp_local_bh_disable(); sctp_local_bh_disable();
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
...@@ -727,7 +726,7 @@ sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, ...@@ -727,7 +726,7 @@ sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr,
int sctp_has_association(const union sctp_addr *laddr, int sctp_has_association(const union sctp_addr *laddr,
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
...@@ -757,10 +756,10 @@ int sctp_has_association(const union sctp_addr *laddr, ...@@ -757,10 +756,10 @@ int sctp_has_association(const union sctp_addr *laddr,
* in certain circumstances. * in certain circumstances.
* *
*/ */
static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
const union sctp_addr *laddr, struct sctp_transport **transportp) const union sctp_addr *laddr, struct sctp_transport **transportp)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
union sctp_addr addr; union sctp_addr addr;
union sctp_addr *paddr = &addr; union sctp_addr *paddr = &addr;
struct sctphdr *sh = (struct sctphdr *) skb->h.raw; struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
...@@ -815,12 +814,12 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -815,12 +814,12 @@ static sctp_association_t *__sctp_rcv_init_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, struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *paddr, const union sctp_addr *paddr,
const union sctp_addr *laddr, const union sctp_addr *laddr,
struct sctp_transport **transportp) struct sctp_transport **transportp)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
......
...@@ -75,17 +75,17 @@ struct sctp_inq *sctp_inq_new(void) ...@@ -75,17 +75,17 @@ struct sctp_inq *sctp_inq_new(void)
/* Release the memory associated with an SCTP inqueue. */ /* Release the memory associated with an SCTP inqueue. */
void sctp_inq_free(struct sctp_inq *queue) void sctp_inq_free(struct sctp_inq *queue)
{ {
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
/* Empty the queue. */ /* Empty the queue. */
while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL) while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)))
sctp_free_chunk(chunk); sctp_chunk_free(chunk);
/* If there is a packet which is currently being worked on, /* If there is a packet which is currently being worked on,
* free it as well. * free it as well.
*/ */
if (queue->in_progress) if (queue->in_progress)
sctp_free_chunk(queue->in_progress); sctp_chunk_free(queue->in_progress);
if (queue->malloced) { if (queue->malloced) {
/* Dump the master memory segment. */ /* Dump the master memory segment. */
...@@ -96,7 +96,7 @@ void sctp_inq_free(struct sctp_inq *queue) ...@@ -96,7 +96,7 @@ void sctp_inq_free(struct sctp_inq *queue)
/* Put a new packet in an SCTP inqueue. /* Put a new packet in an SCTP inqueue.
* We assume that packet->sctp_hdr is set and in host byte order. * We assume that packet->sctp_hdr is set and in host byte order.
*/ */
void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet) void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet)
{ {
/* Directly call the packet handling routine. */ /* Directly call the packet handling routine. */
...@@ -114,23 +114,23 @@ void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet) ...@@ -114,23 +114,23 @@ void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet)
* WARNING: If you need to put the chunk on another queue, you need to * WARNING: If you need to put the chunk on another queue, you need to
* make a shallow copy (clone) of it. * make a shallow copy (clone) of it.
*/ */
sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue) struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
{ {
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
sctp_chunkhdr_t *ch = NULL; sctp_chunkhdr_t *ch = NULL;
/* The assumption is that we are safe to process the chunks /* The assumption is that we are safe to process the chunks
* at this time. * at this time.
*/ */
if ((chunk = queue->in_progress) != NULL) { if ((chunk = queue->in_progress)) {
/* There is a packet that we have been working on. /* There is a packet that we have been working on.
* Any post processing work to do before we move on? * Any post processing work to do before we move on?
*/ */
if (chunk->singleton || if (chunk->singleton ||
chunk->end_of_packet || chunk->end_of_packet ||
chunk->pdiscard) { chunk->pdiscard) {
sctp_free_chunk(chunk); sctp_chunk_free(chunk);
chunk = queue->in_progress = NULL; chunk = queue->in_progress = NULL;
} else { } else {
/* Nothing to do. Next chunk in the packet, please. */ /* Nothing to do. Next chunk in the packet, please. */
...@@ -149,7 +149,7 @@ sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue) ...@@ -149,7 +149,7 @@ sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue)
return NULL; return NULL;
chunk = queue->in_progress = chunk = queue->in_progress =
(sctp_chunk_t *) skb_dequeue(&queue->in); (struct sctp_chunk *) skb_dequeue(&queue->in);
/* This is the first chunk in the packet. */ /* This is the first chunk in the packet. */
chunk->singleton = 1; chunk->singleton = 1;
......
...@@ -96,8 +96,8 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -96,8 +96,8 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
struct sock *sk; struct sock *sk;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
char *saveip, *savesctp; char *saveip, *savesctp;
...@@ -119,7 +119,7 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -119,7 +119,7 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
goto out; goto out;
} }
/* Warning: The sock lock is held. Remember to call /* Warning: The sock lock is held. Remember to call
* sctp_err_finish! * sctp_err_finish!
*/ */
...@@ -148,21 +148,19 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -148,21 +148,19 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} }
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ /* Based on tcp_v6_xmit() in tcp_ipv6.c. */
static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
int ipfragok) int ipfragok)
{ {
struct sock *sk = skb->sk; struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl; struct flowi fl;
struct dst_entry *dst = skb->dst;
struct rt6_info *rt6 = (struct rt6_info *)dst;
fl.proto = sk->protocol; fl.proto = sk->protocol;
/* Fill in the dest address from the route entry passed with the skb /* Fill in the dest address from the route entry passed with the skb
* and the source address from the transport. * and the source address from the transport.
*/ */
fl.fl6_dst = &rt6->rt6i_dst.addr; fl.fl6_dst = &transport->ipaddr.v6.sin6_addr;
fl.fl6_src = &transport->saddr.v6.sin6_addr; fl.fl6_src = &transport->saddr.v6.sin6_addr;
fl.fl6_flowlabel = np->flow_label; fl.fl6_flowlabel = np->flow_label;
...@@ -193,7 +191,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, ...@@ -193,7 +191,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
/* 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(sctp_association_t *asoc, struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr, union sctp_addr *daddr,
union sctp_addr *saddr) union sctp_addr *saddr)
{ {
...@@ -251,10 +249,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, ...@@ -251,10 +249,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
/* Fills in the source address(saddr) based on the destination address(daddr) /* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list. * and asoc's bind address list.
*/ */
void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst, void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
union sctp_addr *daddr, union sctp_addr *saddr) union sctp_addr *daddr, union sctp_addr *saddr)
{ {
sctp_bind_addr_t *bp; struct sctp_bind_addr *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;
...@@ -376,11 +374,17 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) ...@@ -376,11 +374,17 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
} }
/* Initialize sk->rcv_saddr from sctp_addr. */ /* Initialize sk->rcv_saddr from sctp_addr. */
static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk) static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
{ {
inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
} }
/* Initialize sk->daddr from sctp_addr. */
static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
{
inet6_sk(sk)->daddr = addr->v6.sin6_addr;
}
/* Initialize a sctp_addr from a dst_entry. */ /* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
unsigned short port) unsigned short port)
...@@ -391,7 +395,7 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, ...@@ -391,7 +395,7 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
} }
/* Compare addresses exactly. /* Compare addresses exactly.
* FIXME: v4-mapped-v6. * FIXME: v4-mapped-v6.
*/ */
static int sctp_v6_cmp_addr(const union sctp_addr *addr1, static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
...@@ -521,6 +525,7 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -521,6 +525,7 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
newsk->family = PF_INET6; newsk->family = PF_INET6;
newsk->protocol = IPPROTO_SCTP; newsk->protocol = IPPROTO_SCTP;
newsk->backlog_rcv = sk->prot->backlog_rcv; newsk->backlog_rcv = sk->prot->backlog_rcv;
newsk->shutdown = sk->shutdown;
newsctp6sk = (struct sctp6_sock *)newsk; newsctp6sk = (struct sctp6_sock *)newsk;
newsctp6sk->pinet6 = &newsctp6sk->inet6; newsctp6sk->pinet6 = &newsctp6sk->inet6;
...@@ -530,10 +535,28 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -530,10 +535,28 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
memcpy(newnp, np, sizeof(struct ipv6_pinfo)); memcpy(newnp, np, sizeof(struct ipv6_pinfo));
ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr); /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
* and getpeername().
*/
newinet->sport = inet->sport; newinet->sport = inet->sport;
newinet->dport = asoc->peer.port; newnp->saddr = np->saddr;
newnp->rcv_saddr = np->rcv_saddr;
newinet->dport = htons(asoc->peer.port);
newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr;
/* Init the ipv4 part of the socket since we can have sockets
* using v6 API for ipv4.
*/
newinet->ttl = sysctl_ip_default_ttl;
newinet->mc_loop = 1;
newinet->mc_ttl = 1;
newinet->mc_index = 0;
newinet->mc_list = NULL;
if (ipv4_config.no_pmtu_disc)
newinet->pmtudisc = IP_PMTUDISC_DONT;
else
newinet->pmtudisc = IP_PMTUDISC_WANT;
#ifdef INET_REFCNT_DEBUG #ifdef INET_REFCNT_DEBUG
atomic_inc(&inet6_sock_nr); atomic_inc(&inet6_sock_nr);
...@@ -556,6 +579,12 @@ static int sctp_v6_skb_iif(const struct sk_buff *skb) ...@@ -556,6 +579,12 @@ static int sctp_v6_skb_iif(const struct sk_buff *skb)
return opt->iif; return opt->iif;
} }
/* Was this packet marked by Explicit Congestion Notification? */
static int sctp_v6_is_ce(const struct sk_buff *skb)
{
return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20);
}
/* Initialize a PF_INET6 socket msg_name. */ /* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len) static void sctp_inet6_msgname(char *msgname, int *addr_len)
{ {
...@@ -569,7 +598,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) ...@@ -569,7 +598,7 @@ 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(struct sctp_ulpevent *event, static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
char *msgname, int *addrlen) char *msgname, int *addrlen)
{ {
struct sockaddr_in6 *sin6, *sin6from; struct sockaddr_in6 *sin6, *sin6from;
...@@ -596,7 +625,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, ...@@ -596,7 +625,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
sin6from = &event->asoc->peer.primary_addr.v6; sin6from = &event->asoc->peer.primary_addr.v6;
ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin6->sin6_scope_id = sin6from->sin6_scope_id; sin6->sin6_scope_id = sin6from->sin6_scope_id;
} }
} }
...@@ -696,7 +725,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -696,7 +725,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
if (addr->v6.sin6_scope_id) if (addr->v6.sin6_scope_id)
sk->bound_dev_if = addr->v6.sin6_scope_id; sk->bound_dev_if = addr->v6.sin6_scope_id;
if (!sk->bound_dev_if) if (!sk->bound_dev_if)
return 0; return 0;
} }
af = opt->pf->af; af = opt->pf->af;
} }
...@@ -726,11 +755,11 @@ static int sctp_inet6_send_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -726,11 +755,11 @@ static int sctp_inet6_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
if (addr->v6.sin6_scope_id) if (addr->v6.sin6_scope_id)
sk->bound_dev_if = addr->v6.sin6_scope_id; sk->bound_dev_if = addr->v6.sin6_scope_id;
if (!sk->bound_dev_if) if (!sk->bound_dev_if)
return 0; return 0;
} }
af = opt->pf->af; af = opt->pf->af;
} }
return af != NULL; return af != NULL;
} }
...@@ -807,7 +836,8 @@ static struct sctp_af sctp_ipv6_specific = { ...@@ -807,7 +836,8 @@ static struct sctp_af sctp_ipv6_specific = {
.copy_addrlist = sctp_v6_copy_addrlist, .copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb, .from_skb = sctp_v6_from_skb,
.from_sk = sctp_v6_from_sk, .from_sk = sctp_v6_from_sk,
.to_sk = sctp_v6_to_sk, .to_sk_saddr = sctp_v6_to_sk_saddr,
.to_sk_daddr = sctp_v6_to_sk_daddr,
.dst_saddr = sctp_v6_dst_saddr, .dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr, .cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope, .scope = sctp_v6_scope,
...@@ -816,6 +846,7 @@ static struct sctp_af sctp_ipv6_specific = { ...@@ -816,6 +846,7 @@ static struct sctp_af sctp_ipv6_specific = {
.is_any = sctp_v6_is_any, .is_any = sctp_v6_is_any,
.available = sctp_v6_available, .available = sctp_v6_available,
.skb_iif = sctp_v6_skb_iif, .skb_iif = sctp_v6_skb_iif,
.is_ce = sctp_v6_is_ce,
.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,
......
...@@ -55,6 +55,7 @@ SCTP_DBG_OBJCNT(bind_addr); ...@@ -55,6 +55,7 @@ SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap); SCTP_DBG_OBJCNT(ssnmap);
SCTP_DBG_OBJCNT(datamsg);
/* An array to make it easy to pretty print the debug information /* An array to make it easy to pretty print the debug information
* to the proc fs. * to the proc fs.
...@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { ...@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap), SCTP_DBG_OBJCNT_ENTRY(ssnmap),
SCTP_DBG_OBJCNT_ENTRY(datamsg),
}; };
/* Callback from procfs to read out objcount information. /* Callback from procfs to read out objcount information.
......
...@@ -114,7 +114,7 @@ void sctp_packet_free(struct sctp_packet *packet) ...@@ -114,7 +114,7 @@ void sctp_packet_free(struct sctp_packet *packet)
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
sctp_free_chunk(chunk); sctp_chunk_free(chunk);
if (packet->malloced) if (packet->malloced)
kfree(packet); kfree(packet);
...@@ -166,11 +166,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt, ...@@ -166,11 +166,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
/* If sending DATA and haven't aleady bundled a SACK, try to /* If sending DATA and haven't aleady bundled a SACK, try to
* bundle one in to the packet. * bundle one in to the packet.
*/ */
if (sctp_chunk_is_data(chunk) && !pkt->has_sack && if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
!pkt->has_cookie_echo) { !pkt->has_cookie_echo) {
struct sctp_association *asoc; struct sctp_association *asoc;
asoc = pkt->transport->asoc; asoc = pkt->transport->asoc;
if (asoc->a_rwnd > asoc->rwnd) { if (asoc->a_rwnd > asoc->rwnd) {
struct sctp_chunk *sack; struct sctp_chunk *sack;
asoc->a_rwnd = asoc->rwnd; asoc->a_rwnd = asoc->rwnd;
...@@ -205,7 +205,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -205,7 +205,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
if (retval != SCTP_XMIT_OK) if (retval != SCTP_XMIT_OK)
goto finish; goto finish;
pmtu = ((packet->transport->asoc) ? pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) : (packet->transport->asoc->pmtu) :
(packet->transport->pmtu)); (packet->transport->pmtu));
...@@ -219,21 +219,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -219,21 +219,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
/* Both control chunks and data chunks with TSNs are /* Both control chunks and data chunks with TSNs are
* non-fragmentable. * non-fragmentable.
*/ */
int fragmentable = sctp_chunk_is_data(chunk) &&
(!chunk->has_tsn);
if (packet_empty) { if (packet_empty) {
if (fragmentable) {
retval = SCTP_XMIT_MUST_FRAG; /* We no longer do refragmentation at all.
goto finish; * Just fragment at the IP layer, if we
} else { * actually hit this condition
/* The packet is too big but we can */
* not fragment it--we have to just
* transmit and rely on IP packet->ipfragok = 1;
* fragmentation. goto append;
*/
packet->ipfragok = 1;
goto append;
}
} else { /* !packet_empty */ } else { /* !packet_empty */
retval = SCTP_XMIT_PMTU_FULL; retval = SCTP_XMIT_PMTU_FULL;
goto finish; goto finish;
...@@ -259,7 +254,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -259,7 +254,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
goto finish; goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
packet->has_cookie_echo = 1; packet->has_cookie_echo = 1;
else if (SCTP_CID_SACK == chunk->chunk_hdr->type) else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
packet->has_sack = 1; packet->has_sack = 1;
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
...@@ -276,8 +271,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -276,8 +271,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
*/ */
int sctp_packet_transmit(struct sctp_packet *packet) int sctp_packet_transmit(struct sctp_packet *packet)
{ {
struct sctp_transport *transport = packet->transport; struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = transport->asoc; struct sctp_association *asoc = tp->asoc;
struct sctphdr *sh; struct sctphdr *sh;
__u32 crc32; __u32 crc32;
struct sk_buff *nskb; struct sk_buff *nskb;
...@@ -311,6 +306,31 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -311,6 +306,31 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
skb_set_owner_w(nskb, sk); skb_set_owner_w(nskb, sk);
/* Build the SCTP header. */
sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port);
/* From 6.8 Adler-32 Checksum Calculation:
* After the packet is constructed (containing the SCTP common
* header and one or more control or DATA chunks), the
* transmitter shall:
*
* 1) Fill in the proper Verification Tag in the SCTP common
* header and initialize the checksum field to 0's.
*/
sh->vtag = htonl(packet->vtag);
sh->checksum = 0;
/* 2) Calculate the Adler-32 checksum of the whole packet,
* including the SCTP common header and all the
* chunks.
*
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
/** /**
* 6.10 Bundling * 6.10 Bundling
* *
...@@ -332,10 +352,12 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -332,10 +352,12 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
chunk->num_times_sent++;
chunk->sent_at = jiffies;
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
sctp_chunk_assign_tsn(chunk);
if (!chunk->has_tsn) {
sctp_chunk_assign_ssn(chunk);
sctp_chunk_assign_tsn(chunk);
/* 6.3.1 C4) When data is in flight and when allowed /* 6.3.1 C4) When data is in flight and when allowed
* by rule C5, a new RTT measurement MUST be made each * by rule C5, a new RTT measurement MUST be made each
...@@ -343,19 +365,27 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -343,19 +365,27 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* SHOULD be made no more than once per round-trip * SHOULD be made no more than once per round-trip
* for a given destination transport address. * for a given destination transport address.
*/ */
if ((1 == chunk->num_times_sent) &&
(!transport->rto_pending)) { if (!tp->rto_pending) {
chunk->rtt_in_progress = 1; chunk->rtt_in_progress = 1;
transport->rto_pending = 1; tp->rto_pending = 1;
} }
} else
chunk->resent = 1;
chunk->sent_at = jiffies;
has_data = 1; has_data = 1;
} }
memcpy(skb_put(nskb, chunk->skb->len),
chunk->skb->data, chunk->skb->len);
padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len;
memset(skb_put(nskb, padding), 0, padding); if (padding)
SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " memset(skb_put(chunk->skb, padding), 0, padding);
"%s %d\n",
crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len),
chunk->skb->data,
chunk->skb->len, crc32);
SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
"*** Chunk", chunk, "*** Chunk", chunk,
sctp_cname(SCTP_ST_CHUNK( sctp_cname(SCTP_ST_CHUNK(
chunk->chunk_hdr->type)), chunk->chunk_hdr->type)),
...@@ -364,7 +394,6 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -364,7 +394,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
ntohl(chunk->subh.data_hdr->tsn) : 0, ntohl(chunk->subh.data_hdr->tsn) : 0,
"length", ntohs(chunk->chunk_hdr->length), "length", ntohs(chunk->chunk_hdr->length),
"chunk->skb->len", chunk->skb->len, "chunk->skb->len", chunk->skb->len,
"num_times_sent", chunk->num_times_sent,
"rtt_in_progress", chunk->rtt_in_progress); "rtt_in_progress", chunk->rtt_in_progress);
/* /*
...@@ -373,33 +402,10 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -373,33 +402,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* acknowledged or have failed. * acknowledged or have failed.
*/ */
if (!sctp_chunk_is_data(chunk)) if (!sctp_chunk_is_data(chunk))
sctp_free_chunk(chunk); sctp_chunk_free(chunk);
} }
/* Build the SCTP header. */ /* Perform final transformation on checksum. */
sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port);
/* From 6.8 Adler-32 Checksum Calculation:
* After the packet is constructed (containing the SCTP common
* header and one or more control or DATA chunks), the
* transmitter shall:
*
* 1) Fill in the proper Verification Tag in the SCTP common
* header and initialize the checksum field to 0's.
*/
sh->vtag = htonl(packet->vtag);
sh->checksum = 0;
/* 2) Calculate the Adler-32 checksum of the whole packet,
* including the SCTP common header and all the
* chunks.
*
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = sctp_start_cksum((__u8 *)sh, nskb->len);
crc32 = sctp_end_cksum(crc32); crc32 = sctp_end_cksum(crc32);
/* 3) Put the resultant value into the checksum field in the /* 3) Put the resultant value into the checksum field in the
...@@ -413,17 +419,13 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -413,17 +419,13 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* data sender to indicate that the end-points of the * data sender to indicate that the end-points of the
* transport protocol are ECN-capable." * transport protocol are ECN-capable."
* *
* If ECN capable && negotiated && it makes sense for * Now setting the ECT bit all the time, as it should not cause
* this packet to support it (e.g. post ECN negotiation) * any problems protocol-wise even if our peer ignores it.
* then lets set the ECT bit
* *
* FIXME: Need to do something else for IPv6 * Note: The works for IPv6 layer checks this bit too later
* in transmission. See IP6_ECN_flow_xmit().
*/ */
if (packet->ecn_capable) { INET_ECN_xmit(nskb->sk);
INET_ECN_xmit(nskb->sk);
} else {
INET_ECN_dontxmit(nskb->sk);
}
/* Set up the IP options. */ /* Set up the IP options. */
/* BUG: not implemented /* BUG: not implemented
...@@ -431,22 +433,21 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -431,22 +433,21 @@ int sctp_packet_transmit(struct sctp_packet *packet)
*/ */
/* Dump that on IP! */ /* Dump that on IP! */
if (asoc && asoc->peer.last_sent_to != transport) { if (asoc && asoc->peer.last_sent_to != tp) {
/* Considering the multiple CPU scenario, this is a /* Considering the multiple CPU scenario, this is a
* "correcter" place for last_sent_to. --xguo * "correcter" place for last_sent_to. --xguo
*/ */
asoc->peer.last_sent_to = transport; asoc->peer.last_sent_to = tp;
} }
if (has_data) { if (has_data) {
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
transport->last_time_used = jiffies; tp->last_time_used = jiffies;
/* Restart the AUTOCLOSE timer when sending data. */ /* Restart the AUTOCLOSE timer when sending data. */
if ((SCTP_STATE_ESTABLISHED == asoc->state) && if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {
(asoc->autoclose)) {
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
...@@ -455,21 +456,21 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -455,21 +456,21 @@ int sctp_packet_transmit(struct sctp_packet *packet)
} }
} }
dst = transport->dst; dst = tp->dst;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */ /* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if (!dst || (dst->obsolete > 1)) { if (!dst || (dst->obsolete > 1)) {
dst_release(dst); dst_release(dst);
sctp_transport_route(transport, NULL, sctp_sk(sk)); sctp_transport_route(tp, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
} }
nskb->dst = dst_clone(transport->dst); nskb->dst = dst_clone(tp->dst);
if (!nskb->dst) if (!nskb->dst)
goto no_route; 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);
(*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok); (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
out: out:
packet->size = SCTP_IP_OVERHEAD; packet->size = SCTP_IP_OVERHEAD;
return err; return err;
...@@ -596,8 +597,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -596,8 +597,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if any previously transmitted data on the connection remains * if any previously transmitted data on the connection remains
* unacknowledged. * unacknowledged.
*/ */
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
unsigned len = datasize + q->out_qlen; unsigned len = datasize + q->out_qlen;
/* Check whether this chunk and all the rest of pending /* Check whether this chunk and all the rest of pending
...@@ -623,6 +624,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -623,6 +624,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
rwnd = 0; rwnd = 0;
asoc->peer.rwnd = rwnd; asoc->peer.rwnd = rwnd;
/* Has been accepted for transmission. */
chunk->msg->can_expire = 0;
finish: finish:
return retval; return retval;
......
...@@ -55,13 +55,19 @@ ...@@ -55,13 +55,19 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
/* Declare internal functions here. */ /* Declare internal functions here. */
static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);
static void sctp_check_transmitted(struct sctp_outq *q, static void sctp_check_transmitted(struct sctp_outq *q,
struct list_head *transmitted_queue, struct list_head *transmitted_queue,
struct sctp_transport *transport, struct sctp_transport *transport,
sctp_sackhdr_t *sack, struct sctp_sackhdr *sack,
__u32 highest_new_tsn); __u32 highest_new_tsn);
static void sctp_mark_missing(struct sctp_outq *q,
struct list_head *transmitted_queue,
struct sctp_transport *transport,
__u32 highest_new_tsn,
int count_of_newacks);
/* Add data to the front of the queue. */ /* Add data to the front of the queue. */
static inline void sctp_outq_head_data(struct sctp_outq *q, static inline void sctp_outq_head_data(struct sctp_outq *q,
struct sctp_chunk *ch) struct sctp_chunk *ch)
...@@ -94,13 +100,105 @@ static inline void sctp_outq_insert_data(struct sctp_outq *q, ...@@ -94,13 +100,105 @@ static inline void sctp_outq_insert_data(struct sctp_outq *q,
struct sctp_chunk *ch, struct sctp_chunk *ch,
struct sctp_chunk *pos) struct sctp_chunk *pos)
{ {
__skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, __skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev,
(struct sk_buff *)pos, pos->list); (struct sk_buff *)pos, pos->list);
q->out_qlen += ch->skb->len; q->out_qlen += ch->skb->len;
} }
/*
* SFR-CACC algorithm:
* D) If count_of_newacks is greater than or equal to 2
* and t was not sent to the current primary then the
* sender MUST NOT increment missing report count for t.
*/
static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary,
struct sctp_transport *transport,
int count_of_newacks)
{
if (count_of_newacks >=2 && transport != primary)
return 1;
return 0;
}
/*
* SFR-CACC algorithm:
* F) If count_of_newacks is less than 2, let d be the
* destination to which t was sent. If cacc_saw_newack
* is 0 for destination d, then the sender MUST NOT
* increment missing report count for t.
*/
static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport,
int count_of_newacks)
{
if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack)
return 1;
return 0;
}
/*
* SFR-CACC algorithm:
* 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD
* execute steps C, D, F.
*
* C has been implemented in sctp_outq_sack
*/
static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,
struct sctp_transport *transport,
int count_of_newacks)
{
if (!primary->cacc.cycling_changeover) {
if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks))
return 1;
if (sctp_cacc_skip_3_1_f(transport, count_of_newacks));
return 1;
return 0;
}
return 0;
}
/*
* SFR-CACC algorithm:
* 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less
* than next_tsn_at_change of the current primary, then
* the sender MUST NOT increment missing report count
* for t.
*/
static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn)
{
if (primary->cacc.cycling_changeover &&
TSN_lt(tsn, primary->cacc.next_tsn_at_change))
return 1;
return 0;
}
/*
* SFR-CACC algorithm:
* 3) If the missing report count for TSN t is to be
* incremented according to [RFC2960] and
* [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set,
* then the sender MUST futher execute steps 3.1 and
* 3.2 to determine if the missing report count for
* TSN t SHOULD NOT be incremented.
*
* 3.3) If 3.1 and 3.2 do not dictate that the missing
* report count for t should not be incremented, then
* the sender SOULD increment missing report count for
* t (according to [RFC2960] and [SCTP_STEWART_2002]).
*/
static inline int sctp_cacc_skip(struct sctp_transport *primary,
struct sctp_transport *transport,
int count_of_newacks,
__u32 tsn)
{
if (primary->cacc.changeover_active &&
(sctp_cacc_skip_3_1(primary, transport, count_of_newacks)
|| sctp_cacc_skip_3_2(primary, tsn)))
return 1;
return 0;
}
/* Generate a new outqueue. */ /* Generate a new outqueue. */
struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) struct sctp_outq *sctp_outq_new(struct sctp_association *asoc)
{ {
struct sctp_outq *q; struct sctp_outq *q;
...@@ -116,7 +214,7 @@ struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) ...@@ -116,7 +214,7 @@ struct sctp_outq *sctp_outq_new(sctp_association_t *asoc)
* You still need to define handlers if you really want to DO * You still need to define handlers if you really want to DO
* something with this structure... * something with this structure...
*/ */
void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
{ {
q->asoc = asoc; q->asoc = asoc;
skb_queue_head_init(&q->out); skb_queue_head_init(&q->out);
...@@ -132,6 +230,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) ...@@ -132,6 +230,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
q->outstanding_bytes = 0; q->outstanding_bytes = 0;
q->empty = 1; q->empty = 1;
q->cork = 0;
q->malloced = 0; q->malloced = 0;
q->out_qlen = 0; q->out_qlen = 0;
...@@ -143,59 +242,51 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -143,59 +242,51 @@ void sctp_outq_teardown(struct sctp_outq *q)
{ {
struct sctp_transport *transport; struct sctp_transport *transport;
struct list_head *lchunk, *pos, *temp; struct list_head *lchunk, *pos, *temp;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sctp_ulpevent *ev;
/* Throw away unacknowledged chunks. */ /* Throw away unacknowledged chunks. */
list_for_each(pos, &q->asoc->peer.transport_addr_list) { list_for_each(pos, &q->asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports); transport = list_entry(pos, struct sctp_transport, transports);
while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { while ((lchunk = sctp_list_dequeue(&transport->transmitted))) {
chunk = list_entry(lchunk, sctp_chunk_t, chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list); transmitted_list);
/* Mark as part of a failed message. */
/* Generate a SEND FAILED event. */ sctp_datamsg_fail(chunk, q->error);
ev = sctp_ulpevent_make_send_failed(q->asoc, sctp_chunk_free(chunk);
chunk, SCTP_DATA_SENT,
q->error, GFP_ATOMIC);
if (ev)
sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
sctp_free_chunk(chunk);
} }
} }
/* Throw away chunks that have been gap ACKed. */ /* Throw away chunks that have been gap ACKed. */
list_for_each_safe(lchunk, temp, &q->sacked) { list_for_each_safe(lchunk, temp, &q->sacked) {
list_del(lchunk); list_del(lchunk);
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, struct sctp_chunk,
sctp_free_chunk(chunk); transmitted_list);
sctp_datamsg_fail(chunk, q->error);
sctp_chunk_free(chunk);
} }
/* Throw away any chunks in the retransmit queue. */ /* Throw away any chunks in the retransmit queue. */
list_for_each_safe(lchunk, temp, &q->retransmit) { list_for_each_safe(lchunk, temp, &q->retransmit) {
list_del(lchunk); list_del(lchunk);
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, struct sctp_chunk,
sctp_free_chunk(chunk); transmitted_list);
sctp_datamsg_fail(chunk, q->error);
sctp_chunk_free(chunk);
} }
/* Throw away any leftover data chunks. */ /* Throw away any leftover data chunks. */
while ((chunk = sctp_outq_dequeue_data(q))) { while ((chunk = sctp_outq_dequeue_data(q))) {
/* Generate a SEND FAILED event. */ /* Mark as send failure. */
ev = sctp_ulpevent_make_send_failed(q->asoc, sctp_datamsg_fail(chunk, q->error);
chunk, SCTP_DATA_UNSENT, sctp_chunk_free(chunk);
q->error, GFP_ATOMIC);
if (ev)
sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
sctp_free_chunk(chunk);
} }
q->error = 0; q->error = 0;
/* Throw away any leftover control chunks. */ /* Throw away any leftover control chunks. */
while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control))) while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)))
sctp_free_chunk(chunk); sctp_chunk_free(chunk);
} }
/* Free the outqueue structure and any related pending chunks. */ /* Free the outqueue structure and any related pending chunks. */
...@@ -210,7 +301,7 @@ void sctp_outq_free(struct sctp_outq *q) ...@@ -210,7 +301,7 @@ void sctp_outq_free(struct sctp_outq *q)
} }
/* Put a new chunk in an sctp_outq. */ /* Put a new chunk in an sctp_outq. */
int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
{ {
int error = 0; int error = 0;
...@@ -265,7 +356,8 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) ...@@ -265,7 +356,8 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
if (error < 0) if (error < 0)
return error; return error;
error = sctp_outq_flush(q, 0); if (!q->cork)
error = sctp_outq_flush(q, 0);
return error; return error;
} }
...@@ -276,15 +368,16 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) ...@@ -276,15 +368,16 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q)
{ {
struct list_head *rlchunk; struct list_head *rlchunk;
sctp_chunk_t *tchunk, *rchunk; struct sctp_chunk *tchunk, *rchunk;
__u32 ttsn, rtsn; __u32 ttsn, rtsn;
int done = 0; int done = 0;
tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list); tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list);
ttsn = ntohl(tchunk->subh.data_hdr->tsn); ttsn = ntohl(tchunk->subh.data_hdr->tsn);
list_for_each(rlchunk, &q->retransmit) { list_for_each(rlchunk, &q->retransmit) {
rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list); rchunk = list_entry(rlchunk, struct sctp_chunk,
transmitted_list);
rtsn = ntohl(rchunk->subh.data_hdr->tsn); rtsn = ntohl(rchunk->subh.data_hdr->tsn);
if (TSN_lt(ttsn, rtsn)) { if (TSN_lt(ttsn, rtsn)) {
list_add(tlchunk, rlchunk->prev); list_add(tlchunk, rlchunk->prev);
...@@ -303,11 +396,12 @@ void sctp_retransmit_mark(struct sctp_outq *q, ...@@ -303,11 +396,12 @@ void sctp_retransmit_mark(struct sctp_outq *q,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
struct list_head *lchunk, *ltemp; struct list_head *lchunk, *ltemp;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
/* Walk through the specified transmitted queue. */ /* Walk through the specified transmitted queue. */
list_for_each_safe(lchunk, ltemp, &transport->transmitted) { list_for_each_safe(lchunk, ltemp, &transport->transmitted) {
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list);
/* If we are doing retransmission due to a fast retransmit, /* If we are doing retransmission due to a fast retransmit,
* only the chunk's that are marked for fast retransmit * only the chunk's that are marked for fast retransmit
...@@ -416,8 +510,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -416,8 +510,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
struct list_head *lchunk; struct list_head *lchunk;
struct sctp_transport *transport = pkt->transport; struct sctp_transport *transport = pkt->transport;
sctp_xmit_t status; sctp_xmit_t status;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
sctp_association_t *asoc; struct sctp_association *asoc;
int error = 0; int error = 0;
asoc = q->asoc; asoc = q->asoc;
...@@ -442,7 +536,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -442,7 +536,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
lchunk = sctp_list_dequeue(lqueue); lchunk = sctp_list_dequeue(lqueue);
while (lchunk) { while (lchunk) {
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list);
/* Make sure that Gap Acked TSNs are not retransmitted. A /* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the * simple approach is just to move such TSNs out of the
...@@ -504,215 +599,19 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -504,215 +599,19 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
return error; return error;
} }
/* This routine either transmits the fragment or puts it on the output /* Cork the outqueue so queued chunks are really queued. */
* queue. 'pos' points to the next chunk in the output queue after the int sctp_outq_uncork(struct sctp_outq *q)
* chunk that is currently in the process of fragmentation.
*/
void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos,
struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn)
{ {
struct sctp_transport *transport = packet->transport; int error = 0;
struct sk_buff_head *queue = &q->out; if (q->cork) {
sctp_xmit_t status; q->cork = 0;
int error; error = sctp_outq_flush(q, 0);
frag->subh.data_hdr->tsn = htonl(tsn);
frag->has_tsn = 1;
/* An inner fragment may be smaller than the earlier one and may get
* in if we call q->build_output. This ensures that all the fragments
* are sent in order.
*/
if (!skb_queue_empty(queue)) {
SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. "
"adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn));
if (pos)
sctp_outq_insert_data(q, frag, pos);
else
sctp_outq_tail_data(q, frag);
return;
}
/* Add the chunk fragment to the packet. */
status = (*q->build_output)(packet, frag);
switch (status) {
case SCTP_XMIT_RWND_FULL:
/* RWND is full, so put the chunk in the output queue. */
SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. "
"adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn));
if (pos)
sctp_outq_insert_data(q, frag, pos);
else
sctp_outq_tail_data(q, frag);
break;
case SCTP_XMIT_OK:
error = (*q->force_output)(packet);
if (error < 0) {
/* Packet could not be transmitted, put the chunk in
* the output queue
*/
SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
"failed. adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn));
if (pos)
sctp_outq_insert_data(q, frag, pos);
else
sctp_outq_tail_data(q, frag);
} else {
SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
"success. 0x%x sent\n",
ntohl(frag->subh.data_hdr->tsn));
list_add_tail(&frag->transmitted_list,
&transport->transmitted);
sctp_transport_reset_timers(transport);
}
break;
default:
BUG();
};
}
/* This routine calls sctp_xmit_frag() for all the fragments of a message.
* The argument 'frag' point to the first fragment and it holds the list
* of all the other fragments in the 'frag_list' field.
*/
void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt,
sctp_chunk_t *frag)
{
sctp_association_t *asoc = frag->asoc;
struct list_head *lfrag, *frag_list;
__u32 tsn;
int nfrags = 1;
struct sctp_chunk *pos;
/* Count the number of fragments. */
frag_list = &frag->frag_list;
list_for_each(lfrag, frag_list) {
nfrags++;
}
/* Get a TSN block of nfrags TSNs. */
tsn = sctp_association_get_tsn_block(asoc, nfrags);
pos = (struct sctp_chunk *)skb_peek(&q->out);
/* Transmit the first fragment. */
sctp_xmit_frag(q, pos, pkt, frag, tsn++);
/* Transmit the rest of fragments. */
frag_list = &frag->frag_list;
list_for_each(lfrag, frag_list) {
frag = list_entry(lfrag, sctp_chunk_t, frag_list);
sctp_xmit_frag(q, pos, pkt, frag, tsn++);
}
}
/* This routine breaks the given chunk into 'max_frag_data_len' size
* fragments. It returns the first fragment with the frag_list field holding
* the remaining fragments.
*/
sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
size_t max_frag_data_len)
{
sctp_association_t *asoc = chunk->asoc;
void *data_ptr = chunk->subh.data_hdr;
struct sctp_sndrcvinfo *sinfo = &chunk->sinfo;
__u16 chunk_data_len = sctp_data_size(chunk);
__u16 ssn = ntohs(chunk->subh.data_hdr->ssn);
sctp_chunk_t *first_frag, *frag;
struct list_head *frag_list;
int nfrags;
__u8 old_flags, flags;
/* nfrags = no. of max size fragments + any smaller last fragment. */
nfrags = ((chunk_data_len / max_frag_data_len) +
((chunk_data_len % max_frag_data_len) ? 1 : 0));
/* Start of the data in the chunk. */
data_ptr += sizeof(sctp_datahdr_t);
/* Are we fragmenting an already fragmented large message? */
old_flags = chunk->chunk_hdr->flags;
if (old_flags & SCTP_DATA_FIRST_FRAG)
flags = SCTP_DATA_FIRST_FRAG;
else
flags = SCTP_DATA_MIDDLE_FRAG;
/* Make the first fragment. */
first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
data_ptr, flags, ssn);
if (!first_frag)
goto err;
first_frag->has_ssn = 1;
/* All the fragments are added to the frag_list of the first chunk. */
frag_list = &first_frag->frag_list;
chunk_data_len -= max_frag_data_len;
data_ptr += max_frag_data_len;
/* Make the middle fragments. */
while (chunk_data_len > max_frag_data_len) {
frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
data_ptr, SCTP_DATA_MIDDLE_FRAG,
ssn);
if (!frag)
goto err;
frag->has_ssn = 1;
/* Add the middle fragment to the first fragment's
* frag_list.
*/
list_add_tail(&frag->frag_list, frag_list);
chunk_data_len -= max_frag_data_len;
data_ptr += max_frag_data_len;
}
if (old_flags & SCTP_DATA_LAST_FRAG)
flags = SCTP_DATA_LAST_FRAG;
else
flags = SCTP_DATA_MIDDLE_FRAG;
/* Make the last fragment. */
frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr,
flags, ssn);
if (!frag)
goto err;
frag->has_ssn = 1;
/* Add the last fragment to the first fragment's frag_list. */
list_add_tail(&frag->frag_list, frag_list);
/* Free the original chunk. */
sctp_free_chunk(chunk);
return first_frag;
err:
/* Free any fragments that are created before the failure. */
if (first_frag) {
struct list_head *flist, *lfrag;
/* Free all the fragments off the first one. */
flist = &first_frag->frag_list;
while (NULL != (lfrag = sctp_list_dequeue(flist))) {
frag = list_entry(lfrag, sctp_chunk_t, frag_list);
sctp_free_chunk(frag);
}
/* Free the first fragment. */
sctp_free_chunk(first_frag);
} }
return error;
return NULL;
} }
/* /*
* sctp_outq_flush - Try to flush an outqueue. * Try to flush an outqueue.
* *
* Description: Send everything in q which we legally can, subject to * Description: Send everything in q which we legally can, subject to
* congestion limitations. * congestion limitations.
...@@ -724,7 +623,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -724,7 +623,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
{ {
struct sctp_packet *packet; struct sctp_packet *packet;
struct sctp_packet singleton; struct sctp_packet singleton;
sctp_association_t *asoc = q->asoc; struct sctp_association *asoc = q->asoc;
int ecn_capable = asoc->peer.ecn_capable; int ecn_capable = asoc->peer.ecn_capable;
__u16 sport = asoc->base.bind_addr.port; __u16 sport = asoc->base.bind_addr.port;
__u16 dport = asoc->peer.port; __u16 dport = asoc->peer.port;
...@@ -735,7 +634,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -735,7 +634,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
struct sk_buff_head *queue; struct sk_buff_head *queue;
struct sctp_transport *transport = NULL; struct sctp_transport *transport = NULL;
struct sctp_transport *new_transport; struct sctp_transport *new_transport;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
sctp_xmit_t status; sctp_xmit_t status;
int error = 0; int error = 0;
int start_timer = 0; int start_timer = 0;
...@@ -762,7 +661,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -762,7 +661,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
} }
queue = &q->control; queue = &q->control;
while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) { while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) {
/* Pick the right transport to use. */ /* Pick the right transport to use. */
new_transport = chunk->transport; new_transport = chunk->transport;
...@@ -902,32 +801,25 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -902,32 +801,25 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
*/ */
if (chunk->sinfo.sinfo_stream >= if (chunk->sinfo.sinfo_stream >=
asoc->c.sinit_num_ostreams) { asoc->c.sinit_num_ostreams) {
struct sctp_ulpevent *ev;
/* Generate a SEND FAILED event. */ /* Mark as s failed send. */
ev = sctp_ulpevent_make_send_failed(asoc, sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM);
chunk, SCTP_DATA_UNSENT, sctp_chunk_free(chunk);
SCTP_ERROR_INV_STRM, GFP_ATOMIC);
if (ev)
sctp_ulpq_tail_event(&asoc->ulpq, ev);
/* Free the chunk. */
sctp_free_chunk(chunk);
continue; continue;
} }
/* Now do delayed assignment of SSN. This will /* Has this chunk expired? */
* probably change again when we start supporting if (sctp_datamsg_expires(chunk)) {
* large (> approximately 2^16) size messages. sctp_datamsg_fail(chunk, 0);
*/ sctp_chunk_free(chunk);
sctp_chunk_assign_ssn(chunk); continue;
}
/* If there is a specified transport, use it. /* If there is a specified transport, use it.
* Otherwise, we want to use the active path. * Otherwise, we want to use the active path.
*/ */
new_transport = chunk->transport; new_transport = chunk->transport;
if (new_transport == NULL || if (!new_transport || !new_transport->active)
!new_transport->active)
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
/* Change packets if necessary. */ /* Change packets if necessary. */
...@@ -979,26 +871,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -979,26 +871,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
goto sctp_flush_out; goto sctp_flush_out;
break; break;
case SCTP_XMIT_MUST_FRAG: {
sctp_chunk_t *frag;
frag = sctp_fragment_chunk(chunk,
packet->transport->asoc->frag_point);
if (!frag) {
/* We could not fragment due to out of
* memory condition. Free the original
* chunk and return ENOMEM.
*/
sctp_free_chunk(chunk);
error = -ENOMEM;
return error;
}
sctp_xmit_fragmented_chunks(q, packet, frag);
goto sctp_flush_out;
break;
}
case SCTP_XMIT_OK: case SCTP_XMIT_OK:
break; break;
...@@ -1077,8 +949,8 @@ int sctp_outq_set_output_handlers(struct sctp_outq *q, ...@@ -1077,8 +949,8 @@ int sctp_outq_set_output_handlers(struct sctp_outq *q,
} }
/* Update unack_data based on the incoming SACK chunk */ /* Update unack_data based on the incoming SACK chunk */
static void sctp_sack_update_unack_data(sctp_association_t *assoc, static void sctp_sack_update_unack_data(struct sctp_association *assoc,
sctp_sackhdr_t *sack) struct sctp_sackhdr *sack)
{ {
sctp_sack_variable_t *frags; sctp_sack_variable_t *frags;
__u16 unack_data; __u16 unack_data;
...@@ -1096,12 +968,12 @@ static void sctp_sack_update_unack_data(sctp_association_t *assoc, ...@@ -1096,12 +968,12 @@ static void sctp_sack_update_unack_data(sctp_association_t *assoc,
} }
/* Return the highest new tsn that is acknowledged by the given SACK chunk. */ /* Return the highest new tsn that is acknowledged by the given SACK chunk. */
static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
struct list_head *ltransport, *lchunk; struct list_head *ltransport, *lchunk;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
__u32 highest_new_tsn, tsn; __u32 highest_new_tsn, tsn;
struct list_head *transport_list = &asoc->peer.transport_addr_list; struct list_head *transport_list = &asoc->peer.transport_addr_list;
...@@ -1111,7 +983,7 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, ...@@ -1111,7 +983,7 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
transport = list_entry(ltransport, struct sctp_transport, transport = list_entry(ltransport, struct sctp_transport,
transports); transports);
list_for_each(lchunk, &transport->transmitted) { list_for_each(lchunk, &transport->transmitted) {
chunk = list_entry(lchunk, sctp_chunk_t, chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list); transmitted_list);
tsn = ntohl(chunk->subh.data_hdr->tsn); tsn = ntohl(chunk->subh.data_hdr->tsn);
...@@ -1130,26 +1002,64 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, ...@@ -1130,26 +1002,64 @@ static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
* Process the SACK against the outqueue. Mostly, this just frees * Process the SACK against the outqueue. Mostly, this just frees
* things off the transmitted queue. * things off the transmitted queue.
*/ */
int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
{ {
sctp_association_t *asoc = q->asoc; struct sctp_association *asoc = q->asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_chunk_t *tchunk; struct sctp_chunk *tchunk;
struct list_head *lchunk, *transport_list, *pos; struct list_head *lchunk, *transport_list, *pos;
sctp_sack_variable_t *frags = sack->variable; sctp_sack_variable_t *frags = sack->variable;
__u32 sack_ctsn, ctsn, tsn; __u32 sack_ctsn, ctsn, tsn;
__u32 highest_tsn, highest_new_tsn; __u32 highest_tsn, highest_new_tsn;
__u32 sack_a_rwnd; __u32 sack_a_rwnd;
int outstanding; int outstanding;
struct sctp_transport *primary = asoc->peer.primary_path;
int count_of_newacks = 0;
/* Grab the association's destination address list. */ /* Grab the association's destination address list. */
transport_list = &asoc->peer.transport_addr_list; transport_list = &asoc->peer.transport_addr_list;
sack_ctsn = ntohl(sack->cum_tsn_ack); sack_ctsn = ntohl(sack->cum_tsn_ack);
/*
* SFR-CACC algorithm:
* On receipt of a SACK the sender SHOULD execute the
* following statements.
*
* 1) If the cumulative ack in the SACK passes next tsn_at_change
* on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be
* cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for
* all destinations.
*/
if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
primary->cacc.changeover_active = 0;
list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
transport->cacc.cycling_changeover = 0;
}
}
/*
* SFR-CACC algorithm:
* 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE
* is set the receiver of the SACK MUST take the following actions:
*
* A) Initialize the cacc_saw_newack to 0 for all destination
* addresses.
*/
if (sack->num_gap_ack_blocks > 0 &&
primary->cacc.changeover_active) {
list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
transport->cacc.cacc_saw_newack = 0;
}
}
/* Get the highest TSN in the sack. */ /* Get the highest TSN in the sack. */
highest_tsn = sack_ctsn + highest_tsn = sack_ctsn +
ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);
if (TSN_lt(asoc->highest_sacked, highest_tsn)) { if (TSN_lt(asoc->highest_sacked, highest_tsn)) {
highest_new_tsn = highest_tsn; highest_new_tsn = highest_tsn;
...@@ -1162,6 +1072,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1162,6 +1072,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
* and free those chunks that we can. * and free those chunks that we can.
*/ */
sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn); sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);
sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0);
/* Run through the transmitted queue. /* Run through the transmitted queue.
* Credit bytes received and free those chunks which we can. * Credit bytes received and free those chunks which we can.
...@@ -1173,6 +1084,20 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1173,6 +1084,20 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
transports); transports);
sctp_check_transmitted(q, &transport->transmitted, sctp_check_transmitted(q, &transport->transmitted,
transport, sack, highest_new_tsn); transport, sack, highest_new_tsn);
/*
* SFR-CACC algorithm:
* C) Let count_of_newacks be the number of
* destinations for which cacc_saw_newack is set.
*/
if (transport->cacc.cacc_saw_newack)
count_of_newacks ++;
}
list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
sctp_mark_missing(q, &transport->transmitted, transport,
highest_new_tsn, count_of_newacks);
} }
/* Move the Cumulative TSN Ack Point if appropriate. */ /* Move the Cumulative TSN Ack Point if appropriate. */
...@@ -1191,11 +1116,12 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1191,11 +1116,12 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
/* Throw away stuff rotting on the sack queue. */ /* Throw away stuff rotting on the sack queue. */
list_for_each(lchunk, &q->sacked) { list_for_each(lchunk, &q->sacked) {
tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); tchunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list);
tsn = ntohl(tchunk->subh.data_hdr->tsn); tsn = ntohl(tchunk->subh.data_hdr->tsn);
if (TSN_lte(tsn, ctsn)) { if (TSN_lte(tsn, ctsn)) {
lchunk = lchunk->prev; lchunk = lchunk->prev;
sctp_free_chunk(tchunk); sctp_chunk_free(tchunk);
} }
} }
...@@ -1244,12 +1170,9 @@ int sctp_outq_is_empty(const struct sctp_outq *q) ...@@ -1244,12 +1170,9 @@ int sctp_outq_is_empty(const struct sctp_outq *q)
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
/* Go through a transport's transmitted list or the assocication's retransmit /* Go through a transport's transmitted list or the association's retransmit
* list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked.
* The retransmit list will not have an associated transport. In case of a * The retransmit list will not have an associated transport.
* transmitted list with a transport, the transport's congestion, rto and fast
* retransmit parameters are also updated and if needed a fast retransmit
* process is started.
* *
* I added coherent debug information output. --xguo * I added coherent debug information output. --xguo
* *
...@@ -1260,17 +1183,16 @@ int sctp_outq_is_empty(const struct sctp_outq *q) ...@@ -1260,17 +1183,16 @@ int sctp_outq_is_empty(const struct sctp_outq *q)
static void sctp_check_transmitted(struct sctp_outq *q, static void sctp_check_transmitted(struct sctp_outq *q,
struct list_head *transmitted_queue, struct list_head *transmitted_queue,
struct sctp_transport *transport, struct sctp_transport *transport,
sctp_sackhdr_t *sack, struct sctp_sackhdr *sack,
__u32 highest_new_tsn_in_sack) __u32 highest_new_tsn_in_sack)
{ {
struct list_head *lchunk; struct list_head *lchunk;
sctp_chunk_t *tchunk; struct sctp_chunk *tchunk;
struct list_head tlist; struct list_head tlist;
__u32 tsn; __u32 tsn;
__u32 sack_ctsn; __u32 sack_ctsn;
__u32 rtt; __u32 rtt;
__u8 restart_timer = 0; __u8 restart_timer = 0;
__u8 do_fast_retransmit = 0;
int bytes_acked = 0; int bytes_acked = 0;
/* These state variables are for coherent debug output. --xguo */ /* These state variables are for coherent debug output. --xguo */
...@@ -1294,7 +1216,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1294,7 +1216,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
/* The while loop will skip empty transmitted queues. */ /* The while loop will skip empty transmitted queues. */
while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) {
tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); tchunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list);
tsn = ntohl(tchunk->subh.data_hdr->tsn); tsn = ntohl(tchunk->subh.data_hdr->tsn);
if (sctp_acked(sack, tsn)) { if (sctp_acked(sack, tsn)) {
...@@ -1315,9 +1238,9 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1315,9 +1238,9 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* first instance of the packet or a later * first instance of the packet or a later
* instance). * instance).
*/ */
if ((!tchunk->tsn_gap_acked) && if (!tchunk->tsn_gap_acked &&
(1 == tchunk->num_times_sent) && !tchunk->resent &&
(tchunk->rtt_in_progress)) { tchunk->rtt_in_progress) {
rtt = jiffies - tchunk->sent_at; rtt = jiffies - tchunk->sent_at;
sctp_transport_update_rto(transport, sctp_transport_update_rto(transport,
rtt); rtt);
...@@ -1338,6 +1261,25 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1338,6 +1261,25 @@ static void sctp_check_transmitted(struct sctp_outq *q,
if (!tchunk->tsn_gap_acked) { if (!tchunk->tsn_gap_acked) {
tchunk->tsn_gap_acked = 1; tchunk->tsn_gap_acked = 1;
bytes_acked += sctp_data_size(tchunk); bytes_acked += sctp_data_size(tchunk);
/*
* SFR-CACC algorithm:
* 2) If the SACK contains gap acks
* and the flag CHANGEOVER_ACTIVE is
* set the receiver of the SACK MUST
* take the following action:
*
* B) For each TSN t being acked that
* has not been acked in any SACK so
* far, set cacc_saw_newack to 1 for
* the destination that the TSN was
* sent to.
*/
if (transport &&
sack->num_gap_ack_blocks &&
q->asoc->peer.primary_path->cacc.
changeover_active)
transport->cacc.cacc_saw_newack
= 1;
} }
list_add_tail(&tchunk->transmitted_list, list_add_tail(&tchunk->transmitted_list,
...@@ -1524,8 +1466,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1524,8 +1466,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* receiver's advertised window is zero, and there is * receiver's advertised window is zero, and there is
* only one data chunk in flight to the receiver. * only one data chunk in flight to the receiver.
*/ */
if ((0 == q->asoc->peer.rwnd) && if (!q->asoc->peer.rwnd &&
(!list_empty(&tlist)) && !list_empty(&tlist) &&
(sack_ctsn+2 == q->asoc->next_tsn)) { (sack_ctsn+2 == q->asoc->next_tsn)) {
SCTP_DEBUG_PRINTK("%s: SACK received for zero " SCTP_DEBUG_PRINTK("%s: SACK received for zero "
"window probe: %u\n", "window probe: %u\n",
...@@ -1553,12 +1495,26 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1553,12 +1495,26 @@ static void sctp_check_transmitted(struct sctp_outq *q,
} }
} }
/* Reconstruct the transmitted list with chunks that are not yet list_splice(&tlist, transmitted_queue);
* acked by the Cumulative TSN Ack. }
*/
while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { /* Mark chunks as missing and consequently may get retransmitted. */
tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); static void sctp_mark_missing(struct sctp_outq *q,
tsn = ntohl(tchunk->subh.data_hdr->tsn); struct list_head *transmitted_queue,
struct sctp_transport *transport,
__u32 highest_new_tsn_in_sack,
int count_of_newacks)
{
struct sctp_chunk *chunk;
struct list_head *pos;
__u32 tsn;
char do_fast_retransmit = 0;
struct sctp_transport *primary = q->asoc->peer.primary_path;
list_for_each(pos, transmitted_queue) {
chunk = list_entry(pos, struct sctp_chunk, transmitted_list);
tsn = ntohl(chunk->subh.data_hdr->tsn);
/* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all
* 'Unacknowledged TSN's', if the TSN number of an * 'Unacknowledged TSN's', if the TSN number of an
...@@ -1566,26 +1522,35 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1566,26 +1522,35 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* value, increment the 'TSN.Missing.Report' count on that * value, increment the 'TSN.Missing.Report' count on that
* chunk if it has NOT been fast retransmitted or marked for * chunk if it has NOT been fast retransmitted or marked for
* fast retransmit already. * fast retransmit already.
* */
if (!chunk->fast_retransmit &&
!chunk->tsn_gap_acked &&
TSN_lt(tsn, highest_new_tsn_in_sack)) {
/* SFR-CACC may require us to skip marking
* this chunk as missing.
*/
if (!transport || !sctp_cacc_skip(primary, transport,
count_of_newacks, tsn)) {
chunk->tsn_missing_report++;
SCTP_DEBUG_PRINTK(
"%s: TSN 0x%x missing counter: %d\n",
__FUNCTION__, tsn,
chunk->tsn_missing_report);
}
}
/*
* M4) If any DATA chunk is found to have a * M4) If any DATA chunk is found to have a
* 'TSN.Missing.Report' * 'TSN.Missing.Report'
* value larger than or equal to 4, mark that chunk for * value larger than or equal to 4, mark that chunk for
* retransmission and start the fast retransmit procedure. * retransmission and start the fast retransmit procedure.
*/ */
if ((!tchunk->fast_retransmit) &&
(!tchunk->tsn_gap_acked) && if (chunk->tsn_missing_report >= 4) {
(TSN_lt(tsn, highest_new_tsn_in_sack))) { chunk->fast_retransmit = 1;
tchunk->tsn_missing_report++;
SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n",
__FUNCTION__, tsn,
tchunk->tsn_missing_report);
}
if (tchunk->tsn_missing_report >= 4) {
tchunk->fast_retransmit = 1;
do_fast_retransmit = 1; do_fast_retransmit = 1;
} }
list_add_tail(lchunk, transmitted_queue);
} }
if (transport) { if (transport) {
...@@ -1601,7 +1566,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1601,7 +1566,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
} }
/* Is the given TSN acked by this packet? */ /* Is the given TSN acked by this packet? */
static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn)
{ {
int i; int i;
sctp_sack_variable_t *frags; sctp_sack_variable_t *frags;
......
...@@ -55,12 +55,12 @@ ...@@ -55,12 +55,12 @@
#define DECLARE_PRIMITIVE(name) \ #define DECLARE_PRIMITIVE(name) \
/* This is called in the code as sctp_primitive_ ## name. */ \ /* This is called in the code as sctp_primitive_ ## name. */ \
int sctp_primitive_ ## name(sctp_association_t *asoc, \ int sctp_primitive_ ## name(struct sctp_association *asoc, \
void *arg) { \ void *arg) { \
int error = 0; \ int error = 0; \
sctp_event_t event_type; sctp_subtype_t subtype; \ sctp_event_t event_type; sctp_subtype_t subtype; \
sctp_state_t state; \ sctp_state_t state; \
sctp_endpoint_t *ep; \ struct sctp_endpoint *ep; \
\ \
event_type = SCTP_EVENT_T_PRIMITIVE; \ event_type = SCTP_EVENT_T_PRIMITIVE; \
subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/inet_common.h> #include <net/inet_common.h>
#include <net/inet_ecn.h>
/* Global data structures. */ /* Global data structures. */
struct sctp_protocol sctp_proto; struct sctp_protocol sctp_proto;
...@@ -203,7 +204,7 @@ static void sctp_free_local_addr_list(struct sctp_protocol *proto) ...@@ -203,7 +204,7 @@ static void sctp_free_local_addr_list(struct sctp_protocol *proto)
/* Copy the local addresses which are valid for 'scope' into 'bp'. */ /* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct sctp_protocol *proto, int sctp_copy_local_addr_list(struct sctp_protocol *proto,
struct sctp_bind_addr *bp, sctp_scope_t scope, struct sctp_bind_addr *bp, sctp_scope_t scope,
int priority, int copy_flags) int gfp, int copy_flags)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
int error = 0; int error = 0;
...@@ -223,8 +224,8 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto, ...@@ -223,8 +224,8 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
(((AF_INET6 == addr->a.sa.sa_family) && (((AF_INET6 == addr->a.sa.sa_family) &&
(copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_ALLOWED) &&
(copy_flags & SCTP_ADDR6_PEERSUPP)))) { (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
error = sctp_add_bind_addr(bp, &addr->a, error = sctp_add_bind_addr(bp, &addr->a,
priority); GFP_ATOMIC);
if (error) if (error)
goto end_copy; goto end_copy;
} }
...@@ -267,11 +268,16 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk) ...@@ -267,11 +268,16 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk)
} }
/* Initialize sk->rcv_saddr from sctp_addr. */ /* Initialize sk->rcv_saddr from sctp_addr. */
static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk) static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
{ {
inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr;
} }
/* Initialize sk->daddr from sctp_addr. */
static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
{
inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr;
}
/* Initialize a sctp_addr from a dst_entry. */ /* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
...@@ -388,7 +394,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, ...@@ -388,7 +394,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
{ {
struct rtable *rt; struct rtable *rt;
struct flowi fl; struct flowi fl;
sctp_bind_addr_t *bp; struct sctp_bind_addr *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;
...@@ -471,21 +477,33 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, ...@@ -471,21 +477,33 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* For v4, the source address is cached in the route entry(dst). So no need /* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine. * to cache it separately and hence this is an empty routine.
*/ */
void sctp_v4_get_saddr(sctp_association_t *asoc, void sctp_v4_get_saddr(struct sctp_association *asoc,
struct dst_entry *dst, struct dst_entry *dst,
union sctp_addr *daddr, union sctp_addr *daddr,
union sctp_addr *saddr) union sctp_addr *saddr)
{ {
struct rtable *rt = (struct rtable *)dst;
if (rt) {
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = asoc->base.bind_addr.port;
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
} }
/* What interface did this skb arrive on? */ /* What interface did this skb arrive on? */
int sctp_v4_skb_iif(const struct sk_buff *skb) static int sctp_v4_skb_iif(const struct sk_buff *skb)
{
return ((struct rtable *)skb->dst)->rt_iif;
}
/* Was this packet marked by Explicit Congestion Notification? */
static int sctp_v4_is_ce(const struct sk_buff *skb)
{ {
return ((struct rtable *)skb->dst)->rt_iif; return INET_ECN_is_ce(skb->nh.iph->tos);
} }
/* Create and initialize a new sk for the socket returned by accept(). */ /* Create and initialize a new sk for the socket returned by accept(). */
struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sock *sctp_v4_create_accept_sk(struct sock *sk,
struct sctp_association *asoc) struct sctp_association *asoc)
{ {
...@@ -506,22 +524,27 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk, ...@@ -506,22 +524,27 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
newsk->prot = sk->prot; newsk->prot = sk->prot;
newsk->no_check = sk->no_check; newsk->no_check = sk->no_check;
newsk->reuse = sk->reuse; newsk->reuse = sk->reuse;
newsk->shutdown = sk->shutdown;
newsk->destruct = inet_sock_destruct; newsk->destruct = inet_sock_destruct;
newsk->zapped = 0; newsk->zapped = 0;
newsk->family = PF_INET; newsk->family = PF_INET;
newsk->protocol = IPPROTO_SCTP; newsk->protocol = IPPROTO_SCTP;
newsk->backlog_rcv = sk->prot->backlog_rcv; newsk->backlog_rcv = sk->prot->backlog_rcv;
newinet = inet_sk(newsk); newinet = inet_sk(newsk);
/* Initialize sk's sport, dport, rcv_saddr and daddr for
* getsockname() and getpeername()
*/
newinet->sport = inet->sport; newinet->sport = inet->sport;
newinet->saddr = inet->saddr; newinet->saddr = inet->saddr;
newinet->rcv_saddr = inet->saddr; newinet->rcv_saddr = inet->rcv_saddr;
newinet->dport = asoc->peer.port; newinet->dport = htons(asoc->peer.port);
newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
newinet->pmtudisc = inet->pmtudisc; newinet->pmtudisc = inet->pmtudisc;
newinet->id = 0; newinet->id = 0;
newinet->ttl = sysctl_ip_default_ttl; newinet->ttl = sysctl_ip_default_ttl;
newinet->mc_loop = 1; newinet->mc_loop = 1;
newinet->mc_ttl = 1; newinet->mc_ttl = 1;
...@@ -568,7 +591,7 @@ int sctp_ctl_sock_init(void) ...@@ -568,7 +591,7 @@ int sctp_ctl_sock_init(void)
if (sctp_get_pf_specific(PF_INET6)) if (sctp_get_pf_specific(PF_INET6))
family = PF_INET6; family = PF_INET6;
else else
family = PF_INET; family = PF_INET;
err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP,
...@@ -695,7 +718,7 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -695,7 +718,7 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return sctp_v4_available(addr); return sctp_v4_available(addr);
} }
/* Verify that sockaddr looks sendable. Common verification has already /* Verify that sockaddr looks sendable. Common verification has already
* been taken care of. * been taken care of.
*/ */
static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr) static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
...@@ -706,7 +729,7 @@ static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -706,7 +729,7 @@ static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
/* Fill in Supported Address Type information for INIT and INIT-ACK /* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Returns number of addresses supported. * chunks. Returns number of addresses supported.
*/ */
static int sctp_inet_supported_addrs(const struct sctp_opt *opt, static int sctp_inet_supported_addrs(const struct sctp_opt *opt,
__u16 *types) __u16 *types)
{ {
types[0] = SCTP_PARAM_IPV4_ADDRESS; types[0] = SCTP_PARAM_IPV4_ADDRESS;
...@@ -805,7 +828,8 @@ struct sctp_af sctp_ipv4_specific = { ...@@ -805,7 +828,8 @@ struct sctp_af sctp_ipv4_specific = {
.copy_addrlist = sctp_v4_copy_addrlist, .copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb, .from_skb = sctp_v4_from_skb,
.from_sk = sctp_v4_from_sk, .from_sk = sctp_v4_from_sk,
.to_sk = sctp_v4_to_sk, .to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr,
.dst_saddr = sctp_v4_dst_saddr, .dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr, .cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid, .addr_valid = sctp_v4_addr_valid,
...@@ -814,6 +838,7 @@ struct sctp_af sctp_ipv4_specific = { ...@@ -814,6 +838,7 @@ struct sctp_af sctp_ipv4_specific = {
.available = sctp_v4_available, .available = sctp_v4_available,
.scope = sctp_v4_scope, .scope = sctp_v4_scope,
.skb_iif = sctp_v4_skb_iif, .skb_iif = sctp_v4_skb_iif,
.is_ce = sctp_v4_is_ce,
.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,
......
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <asm/scatterlist.h>
#include <linux/crypto.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -95,7 +97,7 @@ static const sctp_ecn_capable_param_t ecap_param = { ...@@ -95,7 +97,7 @@ static const sctp_ecn_capable_param_t ecap_param = {
* provided chunk, as most cause codes will be embedded inside an * provided chunk, as most cause codes will be embedded inside an
* abort chunk. * abort chunk.
*/ */
void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, void sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
const void *payload, size_t paylen) const void *payload, size_t paylen)
{ {
sctp_errhdr_t err; sctp_errhdr_t err;
...@@ -156,14 +158,14 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, ...@@ -156,14 +158,14 @@ void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
* Host Name Address (Note 3) Optional 11 * Host Name Address (Note 3) Optional 11
* Supported Address Types (Note 4) Optional 12 * Supported Address Types (Note 4) Optional 12
*/ */
sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
const sctp_bind_addr_t *bp, const struct sctp_bind_addr *bp,
int gfp, int vparam_len) int gfp, int vparam_len)
{ {
sctp_inithdr_t init; sctp_inithdr_t init;
union sctp_params addrs; union sctp_params addrs;
size_t chunksize; size_t chunksize;
sctp_chunk_t *retval = NULL; struct sctp_chunk *retval = NULL;
int num_types, addrs_len = 0; int num_types, addrs_len = 0;
struct sctp_opt *sp; struct sctp_opt *sp;
sctp_supported_addrs_param_t sat; sctp_supported_addrs_param_t sat;
...@@ -175,12 +177,9 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -175,12 +177,9 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
* can be IPv4 and/or IPv6 in any combination. * can be IPv4 and/or IPv6 in any combination.
*/ */
retval = NULL; retval = NULL;
addrs.v = NULL;
/* Convert the provided bind address list to raw format */ /* Convert the provided bind address list to raw format. */
addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp); addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
if (!addrs.v)
goto nodata;
init.init_tag = htonl(asoc->c.my_vtag); init.init_tag = htonl(asoc->c.my_vtag);
init.a_rwnd = htonl(asoc->rwnd); init.a_rwnd = htonl(asoc->rwnd);
...@@ -236,12 +235,12 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -236,12 +235,12 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
return retval; return retval;
} }
sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
int gfp, int unkparam_len) int gfp, int unkparam_len)
{ {
sctp_inithdr_t initack; sctp_inithdr_t initack;
sctp_chunk_t *retval; struct sctp_chunk *retval;
union sctp_params addrs; union sctp_params addrs;
int addrs_len; int addrs_len;
sctp_cookie_param_t *cookie; sctp_cookie_param_t *cookie;
...@@ -250,9 +249,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -250,9 +249,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
retval = NULL; retval = NULL;
/* Note: there may be no addresses to embed. */
addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp); addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
if (!addrs.v)
goto nomem_rawaddr;
initack.init_tag = htonl(asoc->c.my_vtag); initack.init_tag = htonl(asoc->c.my_vtag);
initack.a_rwnd = htonl(asoc->rwnd); initack.a_rwnd = htonl(asoc->rwnd);
...@@ -294,7 +292,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -294,7 +292,7 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
/* We need to remove the const qualifier at this point. */ /* We need to remove the const qualifier at this point. */
retval->asoc = (sctp_association_t *) asoc; retval->asoc = (struct sctp_association *) asoc;
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
...@@ -311,8 +309,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -311,8 +309,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
nomem_chunk: nomem_chunk:
kfree(cookie); kfree(cookie);
nomem_cookie: nomem_cookie:
kfree(addrs.v); if (addrs.v)
nomem_rawaddr: kfree(addrs.v);
return retval; return retval;
} }
...@@ -350,10 +348,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -350,10 +348,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
* An implementation SHOULD make the cookie as small as possible * An implementation SHOULD make the cookie as small as possible
* to insure interoperability. * to insure interoperability.
*/ */
sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
const sctp_chunk_t *chunk) const struct sctp_chunk *chunk)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
void *cookie; void *cookie;
int cookie_len; int cookie_len;
...@@ -401,10 +399,10 @@ sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, ...@@ -401,10 +399,10 @@ sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc,
* *
* Set to zero on transmit and ignored on receipt. * Set to zero on transmit and ignored on receipt.
*/ */
sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
const sctp_chunk_t *chunk) const struct sctp_chunk *chunk)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0);
...@@ -446,11 +444,11 @@ sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, ...@@ -446,11 +444,11 @@ sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc,
* *
* Note: The CWR is considered a Control chunk. * Note: The CWR is considered a Control chunk.
*/ */
sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
const __u32 lowest_tsn, const __u32 lowest_tsn,
const sctp_chunk_t *chunk) const struct sctp_chunk *chunk)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_cwrhdr_t cwr; sctp_cwrhdr_t cwr;
cwr.lowest_tsn = htonl(lowest_tsn); cwr.lowest_tsn = htonl(lowest_tsn);
...@@ -481,10 +479,10 @@ sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, ...@@ -481,10 +479,10 @@ sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc,
} }
/* Make an ECNE chunk. This is a congestion experienced report. */ /* Make an ECNE chunk. This is a congestion experienced report. */
sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
const __u32 lowest_tsn) const __u32 lowest_tsn)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_ecnehdr_t ecne; sctp_ecnehdr_t ecne;
ecne.lowest_tsn = htonl(lowest_tsn); ecne.lowest_tsn = htonl(lowest_tsn);
...@@ -502,25 +500,27 @@ sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, ...@@ -502,25 +500,27 @@ sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc,
/* Make a DATA chunk for the given association from the provided /* Make a DATA chunk for the given association from the provided
* parameters. However, do not populate the data payload. * parameters. However, do not populate the data payload.
*/ */
sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len, __u8 flags, __u16 ssn) int data_len, __u8 flags, __u16 ssn)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_datahdr_t dp; struct sctp_datahdr dp;
int chunk_len; int chunk_len;
/* We assign the TSN as LATE as possible, not here when /* We assign the TSN as LATE as possible, not here when
* creating the chunk. * creating the chunk.
*/ */
dp.tsn= 1000000; /* This marker is a debugging aid. */ dp.tsn = 0;
dp.stream = htons(sinfo->sinfo_stream); dp.stream = htons(sinfo->sinfo_stream);
dp.ppid = htonl(sinfo->sinfo_ppid); dp.ppid = htonl(sinfo->sinfo_ppid);
dp.ssn = htons(ssn);
/* Set the flags for an unordered send. */ /* Set the flags for an unordered send. */
if (sinfo->sinfo_flags & MSG_UNORDERED) if (sinfo->sinfo_flags & MSG_UNORDERED) {
flags |= SCTP_DATA_UNORDERED; flags |= SCTP_DATA_UNORDERED;
dp.ssn = 0;
} else
dp.ssn = htons(ssn);
chunk_len = sizeof(dp) + data_len; chunk_len = sizeof(dp) + data_len;
retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len);
...@@ -537,12 +537,12 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, ...@@ -537,12 +537,12 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
/* Make a DATA chunk for the given association. Populate the data /* Make a DATA chunk for the given association. Populate the data
* payload. * payload.
*/ */
sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len, const __u8 *data, int data_len, const __u8 *data,
__u8 flags, __u16 ssn) __u8 flags, __u16 ssn)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
if (retval) if (retval)
...@@ -554,11 +554,11 @@ sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, ...@@ -554,11 +554,11 @@ sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc,
/* Make a DATA chunk for the given association to ride on stream id /* Make a DATA chunk for the given association to ride on stream id
* 'stream', with a payload id of 'payload', and a body of 'data'. * 'stream', with a payload id of 'payload', and a body of 'data'.
*/ */
sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len, const __u8 *data) int data_len, const __u8 *data)
{ {
sctp_chunk_t *retval = NULL; struct sctp_chunk *retval = NULL;
retval = sctp_make_data_empty(asoc, sinfo, data_len); retval = sctp_make_data_empty(asoc, sinfo, data_len);
if (retval) if (retval)
...@@ -571,7 +571,7 @@ sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, ...@@ -571,7 +571,7 @@ sctp_chunk_t *sctp_make_data(sctp_association_t *asoc,
* hold 'data_len' octets of data. We use this version when we need * hold 'data_len' octets of data. We use this version when we need
* to build the message AFTER allocating memory. * to build the message AFTER allocating memory.
*/ */
sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len) int data_len)
{ {
...@@ -584,9 +584,9 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, ...@@ -584,9 +584,9 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc,
* association. This reports on which TSN's we've seen to date, * association. This reports on which TSN's we've seen to date,
* including duplicates and gaps. * including duplicates and gaps.
*/ */
sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_sackhdr_t sack; sctp_sackhdr_t sack;
sctp_gap_ack_block_t gab; sctp_gap_ack_block_t gab;
int length; int length;
...@@ -599,11 +599,13 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -599,11 +599,13 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
/* Count the number of Gap Ack Blocks. */ /* Count the number of Gap Ack Blocks. */
sctp_tsnmap_iter_init(map, &iter); num_gabs = 0;
for (num_gabs = 0;
sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); if (sctp_tsnmap_has_gap(map)) {
num_gabs++) { sctp_tsnmap_iter_init(map, &iter);
/* Do nothing. */ while (sctp_tsnmap_next_gap_ack(map, &iter,
&gab.start, &gab.end))
num_gabs++;
} }
num_dup_tsns = sctp_tsnmap_num_dups(map); num_dup_tsns = sctp_tsnmap_num_dups(map);
...@@ -659,11 +661,15 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -659,11 +661,15 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
sctp_addto_chunk(retval, sizeof(sack), &sack); sctp_addto_chunk(retval, sizeof(sack), &sack);
/* Put the Gap Ack Blocks into the chunk. */ /* Put the Gap Ack Blocks into the chunk. */
sctp_tsnmap_iter_init(map, &iter); if (num_gabs) {
while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { sctp_tsnmap_iter_init(map, &iter);
gab.start = htons(gab.start); while(sctp_tsnmap_next_gap_ack(map, &iter,
gab.end = htons(gab.end); &gab.start, &gab.end)) {
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab); gab.start = htons(gab.start);
gab.end = htons(gab.end);
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t),
&gab);
}
} }
/* Register the duplicates. */ /* Register the duplicates. */
...@@ -675,9 +681,9 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -675,9 +681,9 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
} }
/* Make a SHUTDOWN chunk. */ /* Make a SHUTDOWN chunk. */
sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_shutdownhdr_t shut; sctp_shutdownhdr_t shut;
__u32 ctsn; __u32 ctsn;
...@@ -695,10 +701,10 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) ...@@ -695,10 +701,10 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
return retval; return retval;
} }
sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
const sctp_chunk_t *chunk) const struct sctp_chunk *chunk)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);
...@@ -717,10 +723,11 @@ sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, ...@@ -717,10 +723,11 @@ sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc,
return retval; return retval;
} }
sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_shutdown_complete(
const sctp_chunk_t *chunk) const struct sctp_association *asoc,
const struct sctp_chunk *chunk)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
__u8 flags = 0; __u8 flags = 0;
/* Maybe set the T-bit if we have no association. */ /* Maybe set the T-bit if we have no association. */
...@@ -747,11 +754,11 @@ sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, ...@@ -747,11 +754,11 @@ sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc,
/* Create an ABORT. Note that we set the T bit if we have no /* Create an ABORT. Note that we set the T bit if we have no
* association. * association.
*/ */
sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
const size_t hint) const size_t hint)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
__u8 flags = 0; __u8 flags = 0;
/* Maybe set the T-bit if we have no association. */ /* Maybe set the T-bit if we have no association. */
...@@ -775,10 +782,11 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, ...@@ -775,10 +782,11 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc,
} }
/* Helper to create ABORT with a NO_USER_DATA error. */ /* Helper to create ABORT with a NO_USER_DATA error. */
sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_abort_no_data(
const sctp_chunk_t *chunk, __u32 tsn) const struct sctp_association *asoc,
const struct sctp_chunk *chunk, __u32 tsn)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
__u32 payload; __u32 payload;
retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t)
...@@ -809,17 +817,22 @@ sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, ...@@ -809,17 +817,22 @@ sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc,
} }
/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */
sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
const struct msghdr *msg) const struct msghdr *msg)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
void *payload = NULL, *payoff; void *payload = NULL, *payoff;
size_t paylen; size_t paylen = 0;
struct iovec *iov = msg->msg_iov; struct iovec *iov = NULL;
int iovlen = msg->msg_iovlen; int iovlen = 0;
if (msg) {
iov = msg->msg_iov;
iovlen = msg->msg_iovlen;
paylen = get_user_iov_size(iov, iovlen);
}
paylen = get_user_iov_size(iov, iovlen);
retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen); retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen);
if (!retval) if (!retval)
goto err_chunk; goto err_chunk;
...@@ -832,7 +845,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, ...@@ -832,7 +845,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
payoff = payload; payoff = payload;
for (; iovlen > 0; --iovlen) { for (; iovlen > 0; --iovlen) {
if (copy_from_user(payoff, iov->iov_base, iov->iov_len)) if (copy_from_user(payoff, iov->iov_base,iov->iov_len))
goto err_copy; goto err_copy;
payoff += iov->iov_len; payoff += iov->iov_len;
iov++; iov++;
...@@ -849,18 +862,18 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, ...@@ -849,18 +862,18 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
err_copy: err_copy:
kfree(payload); kfree(payload);
err_payload: err_payload:
sctp_free_chunk(retval); sctp_chunk_free(retval);
retval = NULL; retval = NULL;
err_chunk: err_chunk:
return retval; return retval;
} }
/* Make a HEARTBEAT chunk. */ /* Make a HEARTBEAT chunk. */
sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport, const struct sctp_transport *transport,
const void *payload, const size_t paylen) const void *payload, const size_t paylen)
{ {
sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,
0, paylen); 0, paylen);
if (!retval) if (!retval)
...@@ -876,15 +889,16 @@ sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, ...@@ -876,15 +889,16 @@ sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
return retval; return retval;
} }
sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
const void *payload, const size_t paylen) const void *payload, const size_t paylen)
{ {
sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, struct sctp_chunk *retval;
0, paylen);
retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);
if (!retval) if (!retval)
goto nodata; goto nodata;
retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
...@@ -906,11 +920,12 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, ...@@ -906,11 +920,12 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc,
/* Create an Operation Error chunk with the specified space reserved. /* Create an Operation Error chunk with the specified space reserved.
* This routine can be used for containing multiple causes in the chunk. * This routine can be used for containing multiple causes in the chunk.
*/ */
sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_op_error_space(
const sctp_chunk_t *chunk, const struct sctp_association *asoc,
size_t size) const struct sctp_chunk *chunk,
size_t size)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0,
sizeof(sctp_errhdr_t) + size); sizeof(sctp_errhdr_t) + size);
...@@ -933,13 +948,14 @@ sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, ...@@ -933,13 +948,14 @@ sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc,
} }
/* Create an Operation Error chunk. */ /* Create an Operation Error chunk. */
sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
__u16 cause_code, const void *payload, __u16 cause_code, const void *payload,
size_t paylen) size_t paylen)
{ {
sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen); struct sctp_chunk *retval;
retval = sctp_make_op_error_space(asoc, chunk, paylen);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -956,26 +972,27 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, ...@@ -956,26 +972,27 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc,
/* Turn an skb into a chunk. /* Turn an skb into a chunk.
* FIXME: Eventually move the structure directly inside the skb->cb[]. * FIXME: Eventually move the structure directly inside the skb->cb[].
*/ */
sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
const struct sctp_association *asoc,
struct sock *sk) struct sock *sk)
{ {
sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); struct sctp_chunk *retval = t_new(struct sctp_chunk, GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
memset(retval, 0, sizeof(sctp_chunk_t)); memset(retval, 0, sizeof(struct sctp_chunk));
if (!sk) { if (!sk) {
SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
} }
retval->skb = skb; retval->skb = skb;
retval->asoc = (sctp_association_t *) asoc; retval->asoc = (struct sctp_association *)asoc;
retval->num_times_sent = 0; retval->resent = 0;
retval->has_tsn = 0; retval->has_tsn = 0;
retval->has_ssn = 0; retval->has_ssn = 0;
retval->rtt_in_progress = 0; retval->rtt_in_progress = 0;
retval->sent_at = jiffies; retval->sent_at = 0;
retval->singleton = 1; retval->singleton = 1;
retval->end_of_packet = 0; retval->end_of_packet = 0;
retval->ecn_ce_done = 0; retval->ecn_ce_done = 0;
...@@ -991,17 +1008,24 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, ...@@ -991,17 +1008,24 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
retval->tsn_gap_acked = 0; retval->tsn_gap_acked = 0;
retval->fast_retransmit = 0; retval->fast_retransmit = 0;
/* If this is a fragmented message, track all fragments
* of the message (for SEND_FAILED).
*/
retval->msg = NULL;
/* Polish the bead hole. */ /* Polish the bead hole. */
INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->transmitted_list);
INIT_LIST_HEAD(&retval->frag_list); INIT_LIST_HEAD(&retval->frag_list);
SCTP_DBG_OBJCNT_INC(chunk); SCTP_DBG_OBJCNT_INC(chunk);
atomic_set(&retval->refcnt, 1);
nodata: nodata:
return retval; return retval;
} }
/* 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, union sctp_addr *src, void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src,
union sctp_addr *dest) union sctp_addr *dest)
{ {
memcpy(&chunk->source, src, sizeof(union sctp_addr)); memcpy(&chunk->source, src, sizeof(union sctp_addr));
...@@ -1009,7 +1033,7 @@ void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src, ...@@ -1009,7 +1033,7 @@ void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src,
} }
/* Extract the source address from a chunk. */ /* Extract the source address from a chunk. */
const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
{ {
/* If we have a known transport, use that. */ /* If we have a known transport, use that. */
if (chunk->transport) { if (chunk->transport) {
...@@ -1023,16 +1047,16 @@ const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) ...@@ -1023,16 +1047,16 @@ const union sctp_addr *sctp_source(const sctp_chunk_t *chunk)
/* Create a new chunk, setting the type and flags headers from the /* Create a new chunk, setting the type and flags headers from the
* arguments, reserving enough space for a 'paylen' byte payload. * arguments, reserving enough space for a 'paylen' byte payload.
*/ */
sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen) __u8 type, __u8 flags, int paylen)
{ {
sctp_chunk_t *retval; struct sctp_chunk *retval;
sctp_chunkhdr_t *chunk_hdr; sctp_chunkhdr_t *chunk_hdr;
struct sk_buff *skb; struct sk_buff *skb;
struct sock *sk; struct sock *sk;
/* No need to allocate LL here, as this is only a chunk. */ /* No need to allocate LL here, as this is only a chunk. */
skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),
GFP_ATOMIC); GFP_ATOMIC);
if (!skb) if (!skb)
goto nodata; goto nodata;
...@@ -1046,7 +1070,7 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, ...@@ -1046,7 +1070,7 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
sk = asoc ? asoc->base.sk : NULL; sk = asoc ? asoc->base.sk : NULL;
retval = sctp_chunkify(skb, asoc, sk); retval = sctp_chunkify(skb, asoc, sk);
if (!retval) { if (!retval) {
dev_kfree_skb(skb); kfree_skb(skb);
goto nodata; goto nodata;
} }
...@@ -1062,12 +1086,10 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, ...@@ -1062,12 +1086,10 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
return NULL; return NULL;
} }
/* Release the memory occupied by a chunk. */ /* Release the memory occupied by a chunk. */
void sctp_free_chunk(sctp_chunk_t *chunk) static void sctp_chunk_destroy(struct sctp_chunk *chunk)
{ {
/* Make sure that we are not on any list. */
skb_unlink((struct sk_buff *) chunk);
list_del(&chunk->transmitted_list);
/* Free the chunk skb data and the SCTP_chunk stub itself. */ /* Free the chunk skb data and the SCTP_chunk stub itself. */
dev_kfree_skb(chunk->skb); dev_kfree_skb(chunk->skb);
...@@ -1076,11 +1098,37 @@ void sctp_free_chunk(sctp_chunk_t *chunk) ...@@ -1076,11 +1098,37 @@ void sctp_free_chunk(sctp_chunk_t *chunk)
SCTP_DBG_OBJCNT_DEC(chunk); SCTP_DBG_OBJCNT_DEC(chunk);
} }
/* Possibly, free the chunk. */
void sctp_chunk_free(struct sctp_chunk *chunk)
{
/* Make sure that we are not on any list. */
skb_unlink((struct sk_buff *) chunk);
list_del(&chunk->transmitted_list);
/* Release our reference on the message tracker. */
if (chunk->msg)
sctp_datamsg_put(chunk->msg);
sctp_chunk_put(chunk);
}
/* Grab a reference to the chunk. */
void sctp_chunk_hold(struct sctp_chunk *ch)
{
atomic_inc(&ch->refcnt);
}
/* Release a reference to the chunk. */
void sctp_chunk_put(struct sctp_chunk *ch)
{
if (atomic_dec_and_test(&ch->refcnt))
sctp_chunk_destroy(ch);
}
/* Append bytes to the end of a chunk. Will panic if chunk is not big /* Append bytes to the end of a chunk. Will panic if chunk is not big
* enough. * enough.
*/ */
void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
{ {
void *target; void *target;
void *padding; void *padding;
...@@ -1104,8 +1152,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) ...@@ -1104,8 +1152,8 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data)
* chunk is not big enough. * chunk is not big enough.
* Returns a kernel err value. * Returns a kernel err value.
*/ */
static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len, int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
struct iovec *data) struct iovec *data)
{ {
__u8 *target; __u8 *target;
int err = 0; int err = 0;
...@@ -1126,132 +1174,10 @@ static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len, ...@@ -1126,132 +1174,10 @@ static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len,
return err; return err;
} }
/* A data chunk can have a maximum payload of (2^16 - 20). Break
* down any such message into smaller chunks. Opportunistically, fragment
* the chunks down to the current MTU constraints. We may get refragmented
* later if the PMTU changes, but it is _much better_ to fragment immediately
* with a reasonable guess than always doing our fragmentation on the
* soft-interrupt.
*/
int sctp_datachunks_from_user(sctp_association_t *asoc,
const struct sctp_sndrcvinfo *sinfo,
struct msghdr *msg, int msg_len,
struct sk_buff_head *chunks)
{
int max, whole, i, offset, over, err;
int len, first_len;
sctp_chunk_t *chunk;
__u8 frag;
/* What is a reasonable fragmentation point right now? */
max = asoc->pmtu;
if (max < SCTP_MIN_PMTU)
max = SCTP_MIN_PMTU;
max -= SCTP_IP_OVERHEAD;
/* Make sure not beyond maximum chunk size. */
if (max > SCTP_MAX_CHUNK_LEN)
max = SCTP_MAX_CHUNK_LEN;
/* Subtract out the overhead of a data chunk header. */
max -= sizeof(struct sctp_data_chunk);
whole = 0;
first_len = max;
/* Encourage Cookie-ECHO bundling. */
if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
/* Account for the DATA to be bundled with the COOKIE-ECHO. */
if (whole) {
first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
msg_len -= first_len;
whole = 1;
}
}
/* How many full sized? How many bytes leftover? */
whole += msg_len / max;
over = msg_len % max;
offset = 0;
if (whole && over)
SCTP_INC_STATS_USER(SctpFragUsrMsgs);
/* Create chunks for all the full sized DATA chunks. */
for (i=0, len=first_len; i < whole; i++) {
frag = SCTP_DATA_MIDDLE_FRAG;
if (0 == i)
frag |= SCTP_DATA_FIRST_FRAG;
if ((i == (whole - 1)) && !over)
frag |= SCTP_DATA_LAST_FRAG;
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
if (!chunk)
goto nomem;
err = sctp_user_addto_chunk(chunk, offset, len, msg->msg_iov);
if (err < 0)
goto errout;
offset += len;
/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
__skb_queue_tail(chunks, (struct sk_buff *)chunk);
/* The first chunk, the first chunk was likely short
* to allow bundling, so reset to full size.
*/
if (0 == i)
len = max;
}
/* .. now the leftover bytes. */
if (over) {
if (!whole)
frag = SCTP_DATA_NOT_FRAG;
else
frag = SCTP_DATA_LAST_FRAG;
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
if (!chunk)
goto nomem;
err = sctp_user_addto_chunk(chunk, offset, over, msg->msg_iov);
/* Put the chunk->skb back into the form expected by send. */
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
if (err < 0)
goto errout;
__skb_queue_tail(chunks, (struct sk_buff *)chunk);
}
err = 0;
goto out;
nomem:
err = -ENOMEM;
errout:
while ((chunk = (sctp_chunk_t *)__skb_dequeue(chunks)))
sctp_free_chunk(chunk);
out:
return err;
}
/* Helper function to assign a TSN if needed. This assumes that both /* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned. * the data_hdr and association have already been assigned.
*/ */
void sctp_chunk_assign_ssn(sctp_chunk_t *chunk) void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
{ {
__u16 ssn; __u16 ssn;
__u16 sid; __u16 sid;
...@@ -1278,7 +1204,7 @@ void sctp_chunk_assign_ssn(sctp_chunk_t *chunk) ...@@ -1278,7 +1204,7 @@ void sctp_chunk_assign_ssn(sctp_chunk_t *chunk)
/* Helper function to assign a TSN if needed. This assumes that both /* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned. * the data_hdr and association have already been assigned.
*/ */
void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) void sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
{ {
if (!chunk->has_tsn) { if (!chunk->has_tsn) {
/* This is the last possible instant to /* This is the last possible instant to
...@@ -1291,10 +1217,10 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) ...@@ -1291,10 +1217,10 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
} }
/* Create a CLOSED association to use with an incoming packet. */ /* Create a CLOSED association to use with an incoming packet. */
sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk, int gfp) struct sctp_chunk *chunk, int gfp)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct sk_buff *skb; struct sk_buff *skb;
sctp_scope_t scope; sctp_scope_t scope;
...@@ -1303,6 +1229,7 @@ sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, ...@@ -1303,6 +1229,7 @@ sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
asoc = sctp_association_new(ep, ep->base.sk, scope, gfp); asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
if (!asoc) if (!asoc)
goto nodata; goto nodata;
asoc->temp = 1;
skb = chunk->skb; skb = chunk->skb;
/* Create an entry for the source address of the packet. */ /* Create an entry for the source address of the packet. */
/* FIXME: Use the af specific helpers. */ /* FIXME: Use the af specific helpers. */
...@@ -1339,15 +1266,18 @@ sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, ...@@ -1339,15 +1266,18 @@ sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
/* Build a cookie representing asoc. /* Build a cookie representing asoc.
* This INCLUDES the param header needed to put the cookie in the INIT ACK. * This INCLUDES the param header needed to put the cookie in the INIT ACK.
*/ */
sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_chunk_t *init_chunk, const struct sctp_chunk *init_chunk,
int *cookie_len, int *cookie_len,
const __u8 *raw_addrs, int addrs_len) const __u8 *raw_addrs, int addrs_len)
{ {
sctp_cookie_param_t *retval; sctp_cookie_param_t *retval;
sctp_signed_cookie_t *cookie; sctp_signed_cookie_t *cookie;
struct scatterlist sg;
int headersize, bodysize; int headersize, bodysize;
unsigned int keylen;
char *key;
headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;
bodysize = sizeof(sctp_cookie_t) bodysize = sizeof(sctp_cookie_t)
...@@ -1361,8 +1291,8 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, ...@@ -1361,8 +1291,8 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
- (bodysize % SCTP_COOKIE_MULTIPLE); - (bodysize % SCTP_COOKIE_MULTIPLE);
*cookie_len = headersize + bodysize; *cookie_len = headersize + bodysize;
retval = (sctp_cookie_param_t *) retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC);
kmalloc(*cookie_len, GFP_ATOMIC);
if (!retval) { if (!retval) {
*cookie_len = 0; *cookie_len = 0;
goto nodata; goto nodata;
...@@ -1393,30 +1323,39 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, ...@@ -1393,30 +1323,39 @@ sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
/* Copy the raw local address list of the association. */ /* Copy the raw local address list of the association. */
memcpy((__u8 *)&cookie->c.peer_init[0] + memcpy((__u8 *)&cookie->c.peer_init[0] +
ntohs(init_chunk->chunk_hdr->length), raw_addrs, ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
addrs_len);
if (sctp_sk(ep->base.sk)->hmac) {
/* Sign the message. */ /* Sign the message. */
sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, sg.page = virt_to_page(&cookie->c);
(__u8 *) &cookie->c, bodysize, cookie->signature); sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
sg.length = bodysize;
keylen = SCTP_SECRET_SIZE;
key = (char *)ep->secret_key[ep->current_key];
sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
&sg, 1, cookie->signature);
}
nodata: nodata:
return retval; return retval;
} }
/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */
sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, struct sctp_association *sctp_unpack_cookie(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
sctp_chunk_t *chunk, int gfp, const struct sctp_association *asoc,
int *error, sctp_chunk_t **err_chk_p) struct sctp_chunk *chunk, int gfp,
int *error, struct sctp_chunk **errp)
{ {
sctp_association_t *retval = NULL; struct sctp_association *retval = NULL;
sctp_signed_cookie_t *cookie; sctp_signed_cookie_t *cookie;
sctp_cookie_t *bear_cookie; sctp_cookie_t *bear_cookie;
int headersize, bodysize; int headersize, bodysize, fixed_size;
int fixed_size; __u8 digest[SCTP_SIGNATURE_SIZE];
__u8 digest_buf[SCTP_SIGNATURE_SIZE]; struct scatterlist sg;
int secret; unsigned int keylen;
char *key;
sctp_scope_t scope; sctp_scope_t scope;
struct sk_buff *skb = chunk->skb; struct sk_buff *skb = chunk->skb;
...@@ -1440,23 +1379,35 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1440,23 +1379,35 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
cookie = chunk->subh.cookie_hdr; cookie = chunk->subh.cookie_hdr;
bear_cookie = &cookie->c; bear_cookie = &cookie->c;
if (!sctp_sk(ep->base.sk)->hmac)
goto no_hmac;
/* Check the signature. */ /* Check the signature. */
secret = ep->current_key; keylen = SCTP_SECRET_SIZE;
sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, sg.page = virt_to_page(bear_cookie);
(__u8 *) bear_cookie, bodysize, sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
digest_buf); sg.length = bodysize;
if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { key = (char *)ep->secret_key[ep->current_key];
memset(digest, 0x00, sizeof(digest));
sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg,
1, digest);
if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
/* Try the previous key. */ /* Try the previous key. */
secret = ep->last_key; key = (char *)ep->secret_key[ep->last_key];
sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, memset(digest, 0x00, sizeof(digest));
(__u8 *) bear_cookie, bodysize, digest_buf); sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { &sg, 1, digest);
if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
/* Yikes! Still bad signature! */ /* Yikes! Still bad signature! */
*error = -SCTP_IERROR_BAD_SIG; *error = -SCTP_IERROR_BAD_SIG;
goto fail; goto fail;
} }
} }
no_hmac:
/* Check to see if the cookie is stale. If there is already /* Check to see if the cookie is stale. If there is already
* an association, there is no need to check cookie's expiration * an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK. * for init collision case of lost COOKIE ACK.
...@@ -1472,15 +1423,15 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1472,15 +1423,15 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
* Cookie that has expired. * Cookie that has expired.
*/ */
len = ntohs(chunk->chunk_hdr->length); len = ntohs(chunk->chunk_hdr->length);
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len); *errp = sctp_make_op_error_space(asoc, chunk, len);
if (*err_chk_p) { if (*errp) {
suseconds_t usecs = (skb->stamp.tv_sec - suseconds_t usecs = (skb->stamp.tv_sec -
bear_cookie->expiration.tv_sec) * 1000000L + bear_cookie->expiration.tv_sec) * 1000000L +
skb->stamp.tv_usec - skb->stamp.tv_usec -
bear_cookie->expiration.tv_usec; bear_cookie->expiration.tv_usec;
usecs = htonl(usecs); usecs = htonl(usecs);
sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE, sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
&usecs, sizeof(usecs)); &usecs, sizeof(usecs));
*error = -SCTP_IERROR_STALE_COOKIE; *error = -SCTP_IERROR_STALE_COOKIE;
} else } else
...@@ -1509,6 +1460,12 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, ...@@ -1509,6 +1460,12 @@ sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
goto fail; goto fail;
} }
/* Also, add the destination address. */
if (list_empty(&retval->base.bind_addr.address_list)) {
sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
GFP_ATOMIC);
}
retval->next_tsn = retval->c.initial_tsn; retval->next_tsn = retval->c.initial_tsn;
retval->ctsn_ack_point = retval->next_tsn - 1; retval->ctsn_ack_point = retval->next_tsn - 1;
...@@ -1541,10 +1498,10 @@ struct __sctp_missing { ...@@ -1541,10 +1498,10 @@ struct __sctp_missing {
/* /*
* Report a missing mandatory parameter. * Report a missing mandatory parameter.
*/ */
static int sctp_process_missing_param(const sctp_association_t *asoc, static int sctp_process_missing_param(const struct sctp_association *asoc,
sctp_param_t paramtype, sctp_param_t paramtype,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chk_p) struct sctp_chunk **errp)
{ {
struct __sctp_missing report; struct __sctp_missing report;
__u16 len; __u16 len;
...@@ -1554,13 +1511,13 @@ static int sctp_process_missing_param(const sctp_association_t *asoc, ...@@ -1554,13 +1511,13 @@ static int sctp_process_missing_param(const sctp_association_t *asoc,
/* Make an ERROR chunk, preparing enough room for /* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters. * returning multiple unknown parameters.
*/ */
if (!*err_chk_p) if (!*errp)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len); *errp = sctp_make_op_error_space(asoc, chunk, len);
if (*err_chk_p) { if (*errp) {
report.num_missing = htonl(1); report.num_missing = htonl(1);
report.type = paramtype; report.type = paramtype;
sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM,
&report, sizeof(report)); &report, sizeof(report));
} }
...@@ -1569,17 +1526,17 @@ static int sctp_process_missing_param(const sctp_association_t *asoc, ...@@ -1569,17 +1526,17 @@ static int sctp_process_missing_param(const sctp_association_t *asoc,
} }
/* Report an Invalid Mandatory Parameter. */ /* Report an Invalid Mandatory Parameter. */
static int sctp_process_inv_mandatory(const sctp_association_t *asoc, static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chk_p) struct sctp_chunk **errp)
{ {
/* Invalid Mandatory Parameter Error has no payload. */ /* Invalid Mandatory Parameter Error has no payload. */
if (!*err_chk_p) if (!*errp)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, 0); *errp = sctp_make_op_error_space(asoc, chunk, 0);
if (*err_chk_p) if (*errp)
sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0); sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0);
/* Stop processing this chunk. */ /* Stop processing this chunk. */
return 0; return 0;
...@@ -1588,19 +1545,19 @@ static int sctp_process_inv_mandatory(const sctp_association_t *asoc, ...@@ -1588,19 +1545,19 @@ static int sctp_process_inv_mandatory(const sctp_association_t *asoc,
/* Do not attempt to handle the HOST_NAME parm. However, do /* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer. * send back an indicator to the peer.
*/ */
static int sctp_process_hn_param(const sctp_association_t *asoc, static int sctp_process_hn_param(const struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chk_p) struct sctp_chunk **errp)
{ {
__u16 len = ntohs(param.p->length); __u16 len = ntohs(param.p->length);
/* Make an ERROR chunk. */ /* Make an ERROR chunk. */
if (!*err_chk_p) if (!*errp)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, len); *errp = sctp_make_op_error_space(asoc, chunk, len);
if (*err_chk_p) if (*errp)
sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED, sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED,
param.v, len); param.v, len);
/* Stop processing this chunk. */ /* Stop processing this chunk. */
...@@ -1633,10 +1590,10 @@ static int sctp_process_hn_param(const sctp_association_t *asoc, ...@@ -1633,10 +1590,10 @@ static int sctp_process_hn_param(const sctp_association_t *asoc,
* 0 - discard the chunk * 0 - discard the chunk
* 1 - continue with the chunk * 1 - continue with the chunk
*/ */
static int sctp_process_unk_param(const sctp_association_t *asoc, static int sctp_process_unk_param(const struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chk_p) struct sctp_chunk **errp)
{ {
int retval = 1; int retval = 1;
...@@ -1649,12 +1606,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1649,12 +1606,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc,
/* Make an ERROR chunk, preparing enough room for /* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters. * returning multiple unknown parameters.
*/ */
if (NULL == *err_chk_p) if (NULL == *errp)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, *errp = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length)); ntohs(chunk->chunk_hdr->length));
if (*err_chk_p) if (*errp)
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
param.v, param.v,
WORD_ROUND(ntohs(param.p->length))); WORD_ROUND(ntohs(param.p->length)));
...@@ -1665,12 +1622,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1665,12 +1622,12 @@ static int sctp_process_unk_param(const sctp_association_t *asoc,
/* Make an ERROR chunk, preparing enough room for /* Make an ERROR chunk, preparing enough room for
* returning multiple unknown parameters. * returning multiple unknown parameters.
*/ */
if (NULL == *err_chk_p) if (NULL == *errp)
*err_chk_p = sctp_make_op_error_space(asoc, chunk, *errp = sctp_make_op_error_space(asoc, chunk,
ntohs(chunk->chunk_hdr->length)); ntohs(chunk->chunk_hdr->length));
if (*err_chk_p) { if (*errp) {
sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
param.v, param.v,
WORD_ROUND(ntohs(param.p->length))); WORD_ROUND(ntohs(param.p->length)));
} else { } else {
...@@ -1695,11 +1652,11 @@ static int sctp_process_unk_param(const sctp_association_t *asoc, ...@@ -1695,11 +1652,11 @@ static int sctp_process_unk_param(const sctp_association_t *asoc,
* 0 - discard the chunk * 0 - discard the chunk
* 1 - continue with the chunk * 1 - continue with the chunk
*/ */
static int sctp_verify_param(const sctp_association_t *asoc, static int sctp_verify_param(const struct sctp_association *asoc,
union sctp_params param, union sctp_params param,
sctp_cid_t cid, sctp_cid_t cid,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chunk) struct sctp_chunk **err_chunk)
{ {
int retval = 1; int retval = 1;
...@@ -1733,11 +1690,11 @@ static int sctp_verify_param(const sctp_association_t *asoc, ...@@ -1733,11 +1690,11 @@ static int sctp_verify_param(const sctp_association_t *asoc,
} }
/* Verify the INIT packet before we process it. */ /* Verify the INIT packet before we process it. */
int sctp_verify_init(const sctp_association_t *asoc, int sctp_verify_init(const struct sctp_association *asoc,
sctp_cid_t cid, sctp_cid_t cid,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_chunk_t **err_chk_p) struct sctp_chunk **errp)
{ {
union sctp_params param; union sctp_params param;
int has_cookie = 0; int has_cookie = 0;
...@@ -1746,7 +1703,7 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1746,7 +1703,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
if ((0 == peer_init->init_hdr.num_outbound_streams) || if ((0 == peer_init->init_hdr.num_outbound_streams) ||
(0 == peer_init->init_hdr.num_inbound_streams)) { (0 == peer_init->init_hdr.num_inbound_streams)) {
sctp_process_inv_mandatory(asoc, chunk, err_chk_p); sctp_process_inv_mandatory(asoc, chunk, errp);
return 0; return 0;
} }
...@@ -1762,9 +1719,8 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1762,9 +1719,8 @@ int sctp_verify_init(const sctp_association_t *asoc,
* the state cookie for an INIT-ACK chunk. * the state cookie for an INIT-ACK chunk.
*/ */
if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) {
sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
chunk, err_chk_p); chunk, errp);
return 0; return 0;
} }
...@@ -1772,7 +1728,7 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1772,7 +1728,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
sctp_walk_params(param, peer_init, init_hdr.params) { sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) if (!sctp_verify_param(asoc, param, cid, chunk, errp))
return 0; return 0;
} /* for (loop through all parameters) */ } /* for (loop through all parameters) */
...@@ -1784,7 +1740,7 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1784,7 +1740,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
* Returns 0 on failure, else success. * Returns 0 on failure, else success.
* FIXME: This is an association method. * FIXME: This is an association method.
*/ */
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
const union sctp_addr *peer_addr, const union sctp_addr *peer_addr,
sctp_init_chunk_t *peer_init, int gfp) sctp_init_chunk_t *peer_init, int gfp)
{ {
...@@ -1923,7 +1879,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1923,7 +1879,7 @@ int 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, union sctp_params param, int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
const union sctp_addr *peer_addr, int gfp) const union sctp_addr *peer_addr, int gfp)
{ {
union sctp_addr addr; union sctp_addr addr;
...@@ -2032,7 +1988,7 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param, ...@@ -2032,7 +1988,7 @@ int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
} }
/* Select a new verification tag. */ /* Select a new verification tag. */
__u32 sctp_generate_tag(const sctp_endpoint_t *ep) __u32 sctp_generate_tag(const struct sctp_endpoint *ep)
{ {
/* I believe that this random number generator complies with RFC1750. /* I believe that this random number generator complies with RFC1750.
* A tag of 0 is reserved for special cases (e.g. INIT). * A tag of 0 is reserved for special cases (e.g. INIT).
...@@ -2047,7 +2003,7 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *ep) ...@@ -2047,7 +2003,7 @@ __u32 sctp_generate_tag(const sctp_endpoint_t *ep)
} }
/* Select an initial TSN to send during startup. */ /* Select an initial TSN to send during startup. */
__u32 sctp_generate_tsn(const sctp_endpoint_t *ep) __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
{ {
__u32 retval; __u32 retval;
......
...@@ -60,7 +60,8 @@ ...@@ -60,7 +60,8 @@
********************************************************************/ ********************************************************************/
/* A helper function for delayed processing of INET ECN CE bit. */ /* A helper function for delayed processing of INET ECN CE bit. */
static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) static void sctp_do_ecn_ce_work(struct sctp_association *asoc,
__u32 lowest_tsn)
{ {
/* Save the TSN away for comparison when we receive CWR */ /* Save the TSN away for comparison when we receive CWR */
...@@ -80,11 +81,11 @@ static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) ...@@ -80,11 +81,11 @@ static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
* This element represents the lowest TSN number in the datagram * This element represents the lowest TSN number in the datagram
* that was originally marked with the CE bit. * that was originally marked with the CE bit.
*/ */
static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc,
__u32 lowest_tsn, __u32 lowest_tsn,
sctp_chunk_t *chunk) struct sctp_chunk *chunk)
{ {
sctp_chunk_t *repl; struct sctp_chunk *repl;
/* Our previously transmitted packet ran into some congestion /* Our previously transmitted packet ran into some congestion
* so we should take action by reducing cwnd and ssthresh * so we should take action by reducing cwnd and ssthresh
...@@ -123,7 +124,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, ...@@ -123,7 +124,7 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
} }
/* Helper function to do delayed processing of ECN CWR chunk. */ /* Helper function to do delayed processing of ECN CWR chunk. */
static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, static void sctp_do_ecn_cwr_work(struct sctp_association *asoc,
__u32 lowest_tsn) __u32 lowest_tsn)
{ {
/* Turn off ECNE getting auto-prepended to every outgoing /* Turn off ECNE getting auto-prepended to every outgoing
...@@ -200,7 +201,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer) ...@@ -200,7 +201,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
{ {
int error; int error;
struct sctp_transport *transport = (struct sctp_transport *) peer; struct sctp_transport *transport = (struct sctp_transport *) peer;
sctp_association_t *asoc = transport->asoc; struct sctp_association *asoc = transport->asoc;
/* Check whether a task is in the sock. */ /* Check whether a task is in the sock. */
...@@ -238,7 +239,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer) ...@@ -238,7 +239,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
/* This is a sa interface for producing timeout events. It works /* This is a sa interface for producing timeout events. It works
* for timeouts which use the association as their parameter. * for timeouts which use the association as their parameter.
*/ */
static void sctp_generate_timeout_event(sctp_association_t *asoc, static void sctp_generate_timeout_event(struct sctp_association *asoc,
sctp_event_timeout_t timeout_type) sctp_event_timeout_t timeout_type)
{ {
int error = 0; int error = 0;
...@@ -265,8 +266,7 @@ static void sctp_generate_timeout_event(sctp_association_t *asoc, ...@@ -265,8 +266,7 @@ static void sctp_generate_timeout_event(sctp_association_t *asoc,
error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
SCTP_ST_TIMEOUT(timeout_type), SCTP_ST_TIMEOUT(timeout_type),
asoc->state, asoc->ep, asoc, asoc->state, asoc->ep, asoc,
(void *)timeout_type, (void *)timeout_type, GFP_ATOMIC);
GFP_ATOMIC);
if (error) if (error)
asoc->base.sk->err = -error; asoc->base.sk->err = -error;
...@@ -278,25 +278,25 @@ static void sctp_generate_timeout_event(sctp_association_t *asoc, ...@@ -278,25 +278,25 @@ static void sctp_generate_timeout_event(sctp_association_t *asoc,
void sctp_generate_t1_cookie_event(unsigned long data) void sctp_generate_t1_cookie_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
} }
void sctp_generate_t1_init_event(unsigned long data) void sctp_generate_t1_init_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
} }
void sctp_generate_t2_shutdown_event(unsigned long data) void sctp_generate_t2_shutdown_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
} }
void sctp_generate_t5_shutdown_guard_event(unsigned long data) void sctp_generate_t5_shutdown_guard_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *)data; struct sctp_association *asoc = (struct sctp_association *)data;
sctp_generate_timeout_event(asoc, sctp_generate_timeout_event(asoc,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD); SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
...@@ -304,7 +304,7 @@ void sctp_generate_t5_shutdown_guard_event(unsigned long data) ...@@ -304,7 +304,7 @@ void sctp_generate_t5_shutdown_guard_event(unsigned long data)
void sctp_generate_autoclose_event(unsigned long data) void sctp_generate_autoclose_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
} }
...@@ -315,7 +315,7 @@ void sctp_generate_heartbeat_event(unsigned long data) ...@@ -315,7 +315,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
{ {
int error = 0; int error = 0;
struct sctp_transport *transport = (struct sctp_transport *) data; struct sctp_transport *transport = (struct sctp_transport *) data;
sctp_association_t *asoc = transport->asoc; struct sctp_association *asoc = transport->asoc;
sctp_bh_lock_sock(asoc->base.sk); sctp_bh_lock_sock(asoc->base.sk);
if (sock_owned_by_user(asoc->base.sk)) { if (sock_owned_by_user(asoc->base.sk)) {
...@@ -335,8 +335,7 @@ void sctp_generate_heartbeat_event(unsigned long data) ...@@ -335,8 +335,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
asoc->state, asoc->state, asoc->ep, asoc,
asoc->ep, asoc,
transport, GFP_ATOMIC); transport, GFP_ATOMIC);
if (error) if (error)
...@@ -350,7 +349,7 @@ void sctp_generate_heartbeat_event(unsigned long data) ...@@ -350,7 +349,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
/* Inject a SACK Timeout event into the state machine. */ /* Inject a SACK Timeout event into the state machine. */
void sctp_generate_sack_event(unsigned long data) void sctp_generate_sack_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
} }
...@@ -382,7 +381,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { ...@@ -382,7 +381,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
* notification SHOULD be sent to the upper layer. * notification SHOULD be sent to the upper layer.
* *
*/ */
static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
struct sctp_transport *transport) struct sctp_transport *transport)
{ {
/* The check for association's overall error counter exceeding the /* The check for association's overall error counter exceeding the
...@@ -410,7 +409,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, ...@@ -410,7 +409,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
/* Worker routine to handle INIT command failure. */ /* Worker routine to handle INIT command failure. */
static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
sctp_association_t *asoc, struct sctp_association *asoc,
unsigned error) unsigned error)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
...@@ -483,7 +482,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, ...@@ -483,7 +482,7 @@ static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
/* Helper function to break out starting up of heartbeat timers. */ /* Helper function to break out starting up of heartbeat timers. */
static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
struct sctp_transport *t; struct sctp_transport *t;
struct list_head *pos; struct list_head *pos;
...@@ -501,7 +500,7 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, ...@@ -501,7 +500,7 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
} }
static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
struct sctp_transport *t; struct sctp_transport *t;
struct list_head *pos; struct list_head *pos;
...@@ -517,7 +516,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, ...@@ -517,7 +516,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
/* Helper function to update the heartbeat timer. */ /* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc, struct sctp_association *asoc,
struct sctp_transport *t) struct sctp_transport *t)
{ {
/* Update the heartbeat timer. */ /* Update the heartbeat timer. */
...@@ -527,9 +526,9 @@ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, ...@@ -527,9 +526,9 @@ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
/* Helper function to handle the reception of an HEARTBEAT ACK. */ /* Helper function to handle the reception of an HEARTBEAT ACK. */
static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc, struct sctp_association *asoc,
struct sctp_transport *t, struct sctp_transport *t,
sctp_chunk_t *chunk) struct sctp_chunk *chunk)
{ {
sctp_sender_hb_info_t *hbinfo; sctp_sender_hb_info_t *hbinfo;
...@@ -560,7 +559,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, ...@@ -560,7 +559,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
* timer. * timer.
*/ */
static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc, struct sctp_association *asoc,
struct sctp_transport *t) struct sctp_transport *t)
{ {
sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
...@@ -571,7 +570,7 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, ...@@ -571,7 +570,7 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
/* Helper function to process the process SACK command. */ /* Helper function to process the process SACK command. */
static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc, struct sctp_association *asoc,
sctp_sackhdr_t *sackh) sctp_sackhdr_t *sackh)
{ {
int err; int err;
...@@ -595,8 +594,9 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, ...@@ -595,8 +594,9 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
* the transport for a shutdown chunk. * the transport for a shutdown chunk.
*/ */
static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
sctp_chunk_t *chunk) struct sctp_association *asoc,
struct sctp_chunk *chunk)
{ {
struct sctp_transport *t; struct sctp_transport *t;
...@@ -607,18 +607,30 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, ...@@ -607,18 +607,30 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
} }
/* Helper function to change the state of an association. */ /* Helper function to change the state of an association. */
static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc,
sctp_state_t state) sctp_state_t state)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct sctp_opt *sp = sctp_sk(sk);
asoc->state = state; asoc->state = state;
asoc->state_timestamp = jiffies; asoc->state_timestamp = jiffies;
if ((SCTP_STATE_ESTABLISHED == asoc->state) || if (sctp_style(sk, TCP)) {
(SCTP_STATE_CLOSED == asoc->state)) { /* Change the sk->state of a TCP-style socket that has
* sucessfully completed a connect() call.
*/
if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
sk->state = SCTP_SS_ESTABLISHED;
/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
sctp_sstate(sk, ESTABLISHED))
sk->shutdown |= RCV_SHUTDOWN;
}
if (sctp_state(asoc, ESTABLISHED) ||
sctp_state(asoc, CLOSED) ||
sctp_state(asoc, SHUTDOWN_RECEIVED)) {
/* Wake up any processes waiting in the asoc's wait queue in /* Wake up any processes waiting in the asoc's wait queue in
* sctp_wait_for_connect() or sctp_wait_for_sndbuf(). * sctp_wait_for_connect() or sctp_wait_for_sndbuf().
*/ */
...@@ -631,16 +643,26 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, ...@@ -631,16 +643,26 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
* For a UDP-style socket, the waiters are woken up by the * For a UDP-style socket, the waiters are woken up by the
* notifications. * notifications.
*/ */
if (SCTP_SOCKET_UDP != sp->type) if (!sctp_style(sk, UDP))
sk->state_change(sk); sk->state_change(sk);
} }
}
/* Change the sk->state of a TCP-style socket that has successfully /* Helper function to delete an association. */
* completed a connect() call. static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
*/ struct sctp_association *asoc)
if ((SCTP_STATE_ESTABLISHED == asoc->state) && {
(SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state)) struct sock *sk = asoc->base.sk;
sk->state = SCTP_SS_ESTABLISHED;
/* If it is a non-temporary association belonging to a TCP-style
* listening socket, do not free it so that accept() can pick it
* up later.
*/
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp))
return;
sctp_unhash_established(asoc);
sctp_association_free(asoc);
} }
/* 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
...@@ -673,10 +695,10 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, ...@@ -673,10 +695,10 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
*/ */
int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_state_t state,
sctp_endpoint_t *ep, struct sctp_endpoint *ep,
sctp_association_t *asoc, struct sctp_association *asoc,
void *event_arg, void *event_arg,
int priority) int gfp)
{ {
sctp_cmd_seq_t commands; sctp_cmd_seq_t commands;
sctp_sm_table_entry_t *state_fn; sctp_sm_table_entry_t *state_fn;
...@@ -701,9 +723,8 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -701,9 +723,8 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
DEBUG_POST; DEBUG_POST;
error = sctp_side_effects(event_type, subtype, state, error = sctp_side_effects(event_type, subtype, state,
ep, asoc, event_arg, ep, asoc, event_arg, status,
status, &commands, &commands, gfp);
priority);
DEBUG_POST_SFX; DEBUG_POST_SFX;
return error; return error;
...@@ -717,12 +738,12 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -717,12 +738,12 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
*****************************************************************/ *****************************************************************/
int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_state_t state,
sctp_endpoint_t *ep, struct sctp_endpoint *ep,
sctp_association_t *asoc, struct sctp_association *asoc,
void *event_arg, void *event_arg,
sctp_disposition_t status, sctp_disposition_t status,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
int priority) int gfp)
{ {
int error; int error;
...@@ -735,7 +756,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -735,7 +756,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
ep, asoc, ep, asoc,
event_arg, status, event_arg, status,
commands, priority))) commands, gfp)))
goto bail; goto bail;
switch (status) { switch (status) {
...@@ -803,25 +824,26 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -803,25 +824,26 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
/* This is the side-effect interpreter. */ /* This is the side-effect interpreter. */
int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, sctp_endpoint_t *ep, sctp_state_t state, struct sctp_endpoint *ep,
sctp_association_t *asoc, void *event_arg, struct sctp_association *asoc, void *event_arg,
sctp_disposition_t status, sctp_cmd_seq_t *commands, sctp_disposition_t status, sctp_cmd_seq_t *commands,
int priority) int gfp)
{ {
int error = 0; int error = 0;
int force; int force;
sctp_cmd_t *cmd; sctp_cmd_t *cmd;
sctp_chunk_t *new_obj; struct sctp_chunk *new_obj;
sctp_chunk_t *chunk = NULL; struct sctp_chunk *chunk = NULL;
struct sctp_packet *packet; struct sctp_packet *packet;
struct list_head *pos; struct list_head *pos;
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
struct sctp_transport *t; struct sctp_transport *t;
sctp_sackhdr_t sackh; sctp_sackhdr_t sackh;
int local_cork = 0;
if(SCTP_EVENT_T_TIMEOUT != event_type) if (SCTP_EVENT_T_TIMEOUT != event_type)
chunk = (sctp_chunk_t *) event_arg; chunk = (struct sctp_chunk *) event_arg;
/* Note: This whole file is a huge candidate for rework. /* Note: This whole file is a huge candidate for rework.
* For example, each command could either have its own handler, so * For example, each command could either have its own handler, so
...@@ -838,6 +860,10 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -838,6 +860,10 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_NEW_ASOC: case SCTP_CMD_NEW_ASOC:
/* Register a new association. */ /* Register a new association. */
if (local_cork) {
sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
}
asoc = cmd->obj.ptr; asoc = cmd->obj.ptr;
/* Register with the endpoint. */ /* Register with the endpoint. */
sctp_endpoint_add_asoc(ep, asoc); sctp_endpoint_add_asoc(ep, asoc);
...@@ -852,10 +878,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -852,10 +878,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_outq_teardown(&asoc->outqueue); sctp_outq_teardown(&asoc->outqueue);
break; break;
case SCTP_CMD_DELETE_TCB: case SCTP_CMD_DELETE_TCB:
if (local_cork) {
sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
}
/* Delete the current association. */ /* Delete the current association. */
sctp_unhash_established(asoc); sctp_cmd_delete_tcb(commands, asoc);
sctp_association_free(asoc);
asoc = NULL; asoc = NULL;
break; break;
...@@ -903,7 +932,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -903,7 +932,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
* layer which will bail. * layer which will bail.
*/ */
error = sctp_cmd_process_init(commands, asoc, chunk, error = sctp_cmd_process_init(commands, asoc, chunk,
cmd->obj.ptr, priority); cmd->obj.ptr, gfp);
break; break;
case SCTP_CMD_GEN_COOKIE_ECHO: case SCTP_CMD_GEN_COOKIE_ECHO:
...@@ -911,7 +940,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -911,7 +940,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
new_obj = sctp_make_cookie_echo(asoc, chunk); new_obj = sctp_make_cookie_echo(asoc, chunk);
if (!new_obj) { if (!new_obj) {
if (cmd->obj.ptr) if (cmd->obj.ptr)
sctp_free_chunk(cmd->obj.ptr); sctp_chunk_free(cmd->obj.ptr);
goto nomem; goto nomem;
} }
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
...@@ -957,9 +986,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -957,9 +986,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_REPLY: case SCTP_CMD_REPLY:
/* If an caller has not already corked, do cork. */
if (!asoc->outqueue.cork) {
sctp_outq_cork(&asoc->outqueue);
local_cork = 1;
}
/* Send a chunk to our peer. */ /* Send a chunk to our peer. */
error = sctp_outq_tail(&asoc->outqueue, error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
cmd->obj.ptr);
break; break;
case SCTP_CMD_SEND_PKT: case SCTP_CMD_SEND_PKT:
...@@ -977,7 +1010,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -977,7 +1010,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_TRANSMIT: case SCTP_CMD_TRANSMIT:
/* Kick start transmission. */ /* Kick start transmission. */
error = sctp_outq_flush(&asoc->outqueue, 0); error = sctp_outq_uncork(&asoc->outqueue);
local_cork = 0;
break; break;
case SCTP_CMD_ECN_CE: case SCTP_CMD_ECN_CE:
...@@ -1148,13 +1182,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -1148,13 +1182,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
}; };
if (error) if (error)
return error; break;
} }
out:
if (local_cork)
sctp_outq_uncork(&asoc->outqueue);
return error; return error;
nomem: nomem:
error = -ENOMEM; error = -ENOMEM;
return error; goto out;
} }
...@@ -95,13 +95,13 @@ ...@@ -95,13 +95,13 @@
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
/* RFC 2960 6.10 Bundling /* RFC 2960 6.10 Bundling
...@@ -179,16 +179,16 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, ...@@ -179,16 +179,16 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *repl; struct sctp_chunk *repl;
sctp_association_t *new_asoc; struct sctp_association *new_asoc;
sctp_chunk_t *err_chunk; struct sctp_chunk *err_chunk;
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param; sctp_unrecognized_param_t *unk_param;
struct sock *sk; struct sock *sk;
...@@ -212,9 +212,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -212,9 +212,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
* on the TCP-style socket exceed the max backlog, respond with an * on the TCP-style socket exceed the max backlog, respond with an
* ABORT. * ABORT.
*/ */
if ((SCTP_SS_LISTENING != sk->state) || if (!sctp_sstate(sk, LISTENING) ||
((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && (sctp_style(sk, TCP) && (sk->ack_backlog >= sk->max_ack_backlog)))
(sk->ack_backlog >= sk->max_ack_backlog)))
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* Verify the INIT chunk before processing it. */ /* Verify the INIT chunk before processing it. */
...@@ -232,7 +231,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -232,7 +231,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
ntohs(err_chunk->chunk_hdr->length) - ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t)); sizeof(sctp_chunkhdr_t));
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
if (packet) { if (packet) {
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
...@@ -260,8 +259,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -260,8 +259,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
/* The call, sctp_process_init(), can fail on memory allocation. */ /* The call, sctp_process_init(), can fail on memory allocation. */
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), sctp_source(chunk),
(sctp_init_chunk_t *)chunk->chunk_hdr, (sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC)) GFP_ATOMIC))
goto nomem_init; goto nomem_init;
...@@ -303,7 +302,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -303,7 +302,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
* parameter type. * parameter type.
*/ */
sctp_addto_chunk(repl, len, unk_param); sctp_addto_chunk(repl, len, unk_param);
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
} }
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
...@@ -320,7 +319,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -320,7 +319,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
nomem_ack: nomem_ack:
if (err_chunk) if (err_chunk)
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
nomem_init: nomem_init:
sctp_association_free(new_asoc); sctp_association_free(new_asoc);
nomem: nomem:
...@@ -355,16 +354,16 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -355,16 +354,16 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_init_chunk_t *initchunk; sctp_init_chunk_t *initchunk;
__u32 init_tag; __u32 init_tag;
sctp_chunk_t *err_chunk; struct sctp_chunk *err_chunk;
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_disposition_t ret; sctp_disposition_t ret;
...@@ -386,7 +385,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, ...@@ -386,7 +385,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
* error and close the association by transmitting an ABORT. * error and close the association by transmitting an ABORT.
*/ */
if (!init_tag) { if (!init_tag) {
sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0);
if (!reply) if (!reply)
goto nomem; goto nomem;
...@@ -416,7 +415,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, ...@@ -416,7 +415,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
ntohs(err_chunk->chunk_hdr->length) - ntohs(err_chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t)); sizeof(sctp_chunkhdr_t));
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
if (packet) { if (packet) {
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
...@@ -514,18 +513,18 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, ...@@ -514,18 +513,18 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, void *arg, const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_association_t *new_asoc; struct sctp_association *new_asoc;
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
sctp_chunk_t *repl; struct sctp_chunk *repl;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
int error = 0; int error = 0;
sctp_chunk_t *err_chk_p; struct sctp_chunk *err_chk_p;
/* If the packet is an OOTB packet which is temporarily on the /* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT. * control endpoint, respond with an ABORT.
...@@ -623,7 +622,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -623,7 +622,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
nomem_ev: nomem_ev:
sctp_free_chunk(repl); sctp_chunk_free(repl);
nomem_repl: nomem_repl:
nomem_init: nomem_init:
sctp_association_free(new_asoc); sctp_association_free(new_asoc);
...@@ -652,8 +651,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -652,8 +651,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, void *arg, const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
...@@ -697,14 +696,14 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, ...@@ -697,14 +696,14 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
} }
/* Generate and sendout a heartbeat packet. */ /* Generate and sendout a heartbeat packet. */
sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_transport *transport = (struct sctp_transport *) arg; struct sctp_transport *transport = (struct sctp_transport *) arg;
sctp_chunk_t *reply; struct sctp_chunk *reply;
sctp_sender_hb_info_t hbinfo; sctp_sender_hb_info_t hbinfo;
size_t paylen = 0; size_t paylen = 0;
...@@ -730,8 +729,8 @@ sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, ...@@ -730,8 +729,8 @@ sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep,
} }
/* 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 struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -740,7 +739,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, ...@@ -740,7 +739,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
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. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
...@@ -795,14 +794,14 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, ...@@ -795,14 +794,14 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *reply; struct sctp_chunk *reply;
size_t paylen = 0; size_t paylen = 0;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
...@@ -862,13 +861,13 @@ sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, ...@@ -862,13 +861,13 @@ sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
union sctp_addr from_addr; union sctp_addr from_addr;
struct sctp_transport *link; struct sctp_transport *link;
sctp_sender_hb_info_t *hbinfo; sctp_sender_hb_info_t *hbinfo;
...@@ -919,14 +918,14 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, ...@@ -919,14 +918,14 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
* condition. * condition.
*/ */
static int sctp_sf_send_restart_abort(union sctp_addr *ssa, static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
sctp_chunk_t *init, struct sctp_chunk *init,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
int len; int len;
struct sctp_packet *pkt; struct sctp_packet *pkt;
sctp_addr_param_t *addrparm; sctp_addr_param_t *addrparm;
sctp_errhdr_t *errhdr; sctp_errhdr_t *errhdr;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)];
/* Build the error on the stack. We are way to malloc crazy /* Build the error on the stack. We are way to malloc crazy
...@@ -969,9 +968,9 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, ...@@ -969,9 +968,9 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
/* A restart is occurring, check to make sure no new addresses /* A restart is occurring, check to make sure no new addresses
* are being added as we may be under a takeover attack. * are being added as we may be under a takeover attack.
*/ */
static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *init, struct sctp_chunk *init,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_transport *new_addr, *addr; struct sctp_transport *new_addr, *addr;
...@@ -1022,8 +1021,8 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, ...@@ -1022,8 +1021,8 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
* *
* Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state.
*/ */
static void sctp_tietags_populate(sctp_association_t *new_asoc, static void sctp_tietags_populate(struct sctp_association *new_asoc,
const sctp_association_t *asoc) const struct sctp_association *asoc)
{ {
switch (asoc->state) { switch (asoc->state) {
...@@ -1069,8 +1068,8 @@ static void sctp_tietags_populate(sctp_association_t *new_asoc, ...@@ -1069,8 +1068,8 @@ static void sctp_tietags_populate(sctp_association_t *new_asoc,
* Returns value representing action to be taken. These action values * Returns value representing action to be taken. These action values
* correspond to Action/Description values in RFC 2960, Table 2. * correspond to Action/Description values in RFC 2960, Table 2.
*/ */
static char sctp_tietags_compare(sctp_association_t *new_asoc, static char sctp_tietags_compare(struct sctp_association *new_asoc,
const sctp_association_t *asoc) const struct sctp_association *asoc)
{ {
/* In this case, the peer may have restarted. */ /* In this case, the peer may have restarted. */
if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&
...@@ -1106,16 +1105,16 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc, ...@@ -1106,16 +1105,16 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
* chunk handling. * chunk handling.
*/ */
static sctp_disposition_t sctp_sf_do_unexpected_init( static sctp_disposition_t sctp_sf_do_unexpected_init(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands) void *arg, sctp_cmd_seq_t *commands)
{ {
sctp_disposition_t retval; sctp_disposition_t retval;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *repl; struct sctp_chunk *repl;
sctp_association_t *new_asoc; struct sctp_association *new_asoc;
sctp_chunk_t *err_chunk; struct sctp_chunk *err_chunk;
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param; sctp_unrecognized_param_t *unk_param;
int len; int len;
...@@ -1191,7 +1190,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1191,7 +1190,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* since there are no peer addresses to check against. * since there are no peer addresses to check against.
* Upon return an ABORT will have been sent if needed. * Upon return an ABORT will have been sent if needed.
*/ */
if (asoc->state != SCTP_STATE_COOKIE_WAIT) { if (!sctp_state(asoc, COOKIE_WAIT)) {
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
commands)) { commands)) {
retval = SCTP_DISPOSITION_CONSUME; retval = SCTP_DISPOSITION_CONSUME;
...@@ -1238,7 +1237,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1238,7 +1237,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* parameter type. * parameter type.
*/ */
sctp_addto_chunk(repl, len, unk_param); sctp_addto_chunk(repl, len, unk_param);
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
} }
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));
...@@ -1254,7 +1253,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1254,7 +1253,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
cleanup: cleanup:
if (err_chunk) if (err_chunk)
sctp_free_chunk(err_chunk); sctp_chunk_free(err_chunk);
return retval; return retval;
nomem: nomem:
retval = SCTP_DISPOSITION_NOMEM; retval = SCTP_DISPOSITION_NOMEM;
...@@ -1303,11 +1302,11 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1303,11 +1302,11 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
/* Call helper to do the real work for both simulataneous and /* Call helper to do the real work for both simulataneous and
* duplicate INIT chunk handling. * duplicate INIT chunk handling.
...@@ -1356,11 +1355,11 @@ sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, ...@@ -1356,11 +1355,11 @@ sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
/* Call helper to do the real work for both simulataneous and /* Call helper to do the real work for both simulataneous and
* duplicate INIT chunk handling. * duplicate INIT chunk handling.
...@@ -1375,15 +1374,15 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, ...@@ -1375,15 +1374,15 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
* Section 5.2.4 * Section 5.2.4
* A) In this case, the peer may have restarted. * A) In this case, the peer may have restarted.
*/ */
static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc) struct sctp_association *new_asoc)
{ {
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
sctp_chunk_t *repl; struct sctp_chunk *repl;
/* new_asoc is a brand-new association, so these are not yet /* new_asoc is a brand-new association, so these are not yet
* side effects--it is safe to run them here. * side effects--it is safe to run them here.
...@@ -1391,7 +1390,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -1391,7 +1390,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, sctp_source(chunk), peer_init,
GFP_ATOMIC)) GFP_ATOMIC))
goto nomem; goto nomem;
...@@ -1429,7 +1428,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -1429,7 +1428,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
nomem_ev: nomem_ev:
sctp_free_chunk(repl); sctp_chunk_free(repl);
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
...@@ -1442,22 +1441,22 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -1442,22 +1441,22 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
* after responding to the local endpoint's INIT * after responding to the local endpoint's INIT
*/ */
/* This case represents an initialization collision. */ /* This case represents an initialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc) struct sctp_association *new_asoc)
{ {
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
sctp_chunk_t *repl; struct sctp_chunk *repl;
/* new_asoc is a brand-new association, so these are not yet /* new_asoc is a brand-new association, so these are not yet
* 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];
if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
sctp_source(chunk), peer_init, sctp_source(chunk), peer_init,
GFP_ATOMIC)) GFP_ATOMIC))
goto nomem; goto nomem;
...@@ -1492,7 +1491,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, ...@@ -1492,7 +1491,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
nomem_ev: nomem_ev:
sctp_free_chunk(repl); sctp_chunk_free(repl);
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
...@@ -1506,11 +1505,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, ...@@ -1506,11 +1505,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
* but a new tag of its own. * but a new tag of its own.
*/ */
/* This case represents an initialization collision. */ /* This case represents an initialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc) struct sctp_association *new_asoc)
{ {
/* The cookie should be silently discarded. /* The cookie should be silently discarded.
* The endpoint SHOULD NOT change states and should leave * The endpoint SHOULD NOT change states and should leave
...@@ -1527,14 +1526,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, ...@@ -1527,14 +1526,14 @@ static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep,
* enter the ESTABLISHED state, if it has not already done so. * enter the ESTABLISHED state, if it has not already done so.
*/ */
/* This case represents an initialization collision. */ /* This case represents an initialization collision. */
static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc) struct sctp_association *new_asoc)
{ {
struct sctp_ulpevent *ev = NULL; struct sctp_ulpevent *ev = NULL;
sctp_chunk_t *repl; struct sctp_chunk *repl;
/* Clarification from Implementor's Guide: /* Clarification from Implementor's Guide:
* D) When both local and remote tags match the endpoint should * D) When both local and remote tags match the endpoint should
...@@ -1603,18 +1602,18 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, ...@@ -1603,18 +1602,18 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_disposition_t retval; sctp_disposition_t retval;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_association_t *new_asoc; struct sctp_association *new_asoc;
int error = 0; int error = 0;
char action; char action;
sctp_chunk_t *err_chk_p; struct sctp_chunk *err_chk_p;
/* "Decode" the chunk. We have no optional parameters so we /* "Decode" the chunk. We have no optional parameters so we
* are in good shape. * are in good shape.
...@@ -1701,13 +1700,14 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1701,13 +1700,14 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
* *
* See sctp_sf_do_9_1_abort(). * See sctp_sf_do_9_1_abort().
*/ */
sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_shutdown_pending_abort(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
if (!sctp_vtag_verify_either(chunk, asoc)) if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
...@@ -1724,13 +1724,13 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep, ...@@ -1724,13 +1724,13 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep,
* *
* See sctp_sf_do_9_1_abort(). * See sctp_sf_do_9_1_abort().
*/ */
sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
if (!sctp_vtag_verify_either(chunk, asoc)) if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
...@@ -1751,11 +1751,12 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep, ...@@ -1751,11 +1751,12 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep,
* *
* See sctp_sf_do_9_1_abort(). * See sctp_sf_do_9_1_abort().
*/ */
sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
/* The same T2 timer, so we should be able to use /* The same T2 timer, so we should be able to use
* common function with the SHUTDOWN-SENT state. * common function with the SHUTDOWN-SENT state.
...@@ -1777,13 +1778,13 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, ...@@ -1777,13 +1778,13 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_errhdr_t *err; sctp_errhdr_t *err;
err = (sctp_errhdr_t *)(chunk->skb->data); err = (sctp_errhdr_t *)(chunk->skb->data);
...@@ -1792,7 +1793,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, ...@@ -1792,7 +1793,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] > if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
asoc->max_init_attempts) { asoc->max_init_attempts) {
/* INIT_FAILED will issue an ulpevent. */ /* INIT_FAILED will issue an ulpevent. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(err->cause)); SCTP_U32(err->cause));
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
} }
...@@ -1831,26 +1832,26 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, ...@@ -1831,26 +1832,26 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
time_t stale; time_t stale;
sctp_cookie_preserve_param_t bht; sctp_cookie_preserve_param_t bht;
sctp_errhdr_t *err; sctp_errhdr_t *err;
struct list_head *pos; struct list_head *pos;
struct sctp_transport *t; struct sctp_transport *t;
sctp_chunk_t *reply; struct sctp_chunk *reply;
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
int attempts; int attempts;
attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
if (attempts >= asoc->max_init_attempts) { if (attempts >= asoc->max_init_attempts) {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(SCTP_ERROR_STALE_COOKIE)); SCTP_U32(SCTP_ERROR_STALE_COOKIE));
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
} }
...@@ -1879,7 +1880,7 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, ...@@ -1879,7 +1880,7 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
bht.lifespan_increment = htonl(stale); bht.lifespan_increment = htonl(stale);
/* Build that new INIT chunk. */ /* Build that new INIT chunk. */
bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht)); reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht));
if (!reply) if (!reply)
goto nomem; goto nomem;
...@@ -1946,20 +1947,20 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, ...@@ -1946,20 +1947,20 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
__u16 error = SCTP_ERROR_NO_ERROR; __u16 error = SCTP_ERROR_NO_ERROR;
if (!sctp_vtag_verify_either(chunk, asoc)) if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
if (chunk && (ntohs(chunk->chunk_hdr->length) >= if (chunk && (ntohs(chunk->chunk_hdr->length) >=
(sizeof(struct sctp_chunkhdr) + (sizeof(struct sctp_chunkhdr) +
sizeof(struct sctp_errhdr)))) sizeof(struct sctp_errhdr))))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause; error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
...@@ -1977,13 +1978,13 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, ...@@ -1977,13 +1978,13 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
* *
* See sctp_sf_do_9_1_abort() above. * See sctp_sf_do_9_1_abort() above.
*/ */
sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
__u16 error = SCTP_ERROR_NO_ERROR; __u16 error = SCTP_ERROR_NO_ERROR;
if (!sctp_vtag_verify_either(chunk, asoc)) if (!sctp_vtag_verify_either(chunk, asoc))
...@@ -1996,7 +1997,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, ...@@ -1996,7 +1997,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
if (chunk && (ntohs(chunk->chunk_hdr->length) >= if (chunk && (ntohs(chunk->chunk_hdr->length) >=
(sizeof(struct sctp_chunkhdr) + (sizeof(struct sctp_chunkhdr) +
sizeof(struct sctp_errhdr)))) sizeof(struct sctp_errhdr))))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause; error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
...@@ -2011,8 +2012,8 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, ...@@ -2011,8 +2012,8 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
* *
* See sctp_sf_do_9_1_abort() above. * See sctp_sf_do_9_1_abort() above.
*/ */
sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -2056,13 +2057,13 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, ...@@ -2056,13 +2057,13 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_shutdownhdr_t *sdh; sctp_shutdownhdr_t *sdh;
sctp_disposition_t disposition; sctp_disposition_t disposition;
...@@ -2111,14 +2112,14 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, ...@@ -2111,14 +2112,14 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
* that belong to this association, it should discard the INIT chunk and * that belong to this association, it should discard the INIT chunk and
* retransmit the SHUTDOWN ACK chunk. * retransmit the SHUTDOWN ACK chunk.
*/ */
sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = (sctp_chunk_t *) arg; struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
sctp_chunk_t *reply; struct sctp_chunk *reply;
reply = sctp_make_shutdown_ack(asoc, chunk); reply = sctp_make_shutdown_ack(asoc, chunk);
if (NULL == reply) if (NULL == reply)
...@@ -2165,14 +2166,14 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep, ...@@ -2165,14 +2166,14 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_cwrhdr_t *cwr; sctp_cwrhdr_t *cwr;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the * that the value in the Verification Tag field of the
...@@ -2221,14 +2222,14 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, ...@@ -2221,14 +2222,14 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_ecnehdr_t *ecne; sctp_ecnehdr_t *ecne;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the * that the value in the Verification Tag field of the
...@@ -2279,15 +2280,15 @@ sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, ...@@ -2279,15 +2280,15 @@ sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_datahdr_t *data_hdr; sctp_datahdr_t *data_hdr;
sctp_chunk_t *err; struct sctp_chunk *err;
size_t datalen; size_t datalen;
sctp_verb_t deliver; sctp_verb_t deliver;
int tmp; int tmp;
...@@ -2309,9 +2310,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2309,9 +2310,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
tsn = ntohl(data_hdr->tsn); tsn = ntohl(data_hdr->tsn);
SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head);
/* ASSERT: Now skb->data is really the user data. */ /* ASSERT: Now skb->data is really the user data. */
...@@ -2326,11 +2325,15 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2326,11 +2325,15 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
*/ */
if (!chunk->ecn_ce_done) { if (!chunk->ecn_ce_done) {
struct sctp_af *af;
chunk->ecn_ce_done = 1; chunk->ecn_ce_done = 1;
if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
asoc->peer.ecn_capable) { af = sctp_get_af_specific(
ipver2af(chunk->skb->nh.iph->version));
if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
/* Do real work as sideffect. */ /* Do real work as sideffect. */
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
SCTP_U32(tsn)); SCTP_U32(tsn));
} }
} }
...@@ -2371,7 +2374,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2371,7 +2374,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* PMTU. In cases, such as loopback, this might be a rather * PMTU. In cases, such as loopback, this might be a rather
* large spill over. * large spill over.
*/ */
if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { if (!asoc->rwnd || asoc->rwnd_over ||
(datalen > asoc->rwnd + asoc->frag_point)) {
/* If this is the next TSN, consider reneging to make /* If this is the next TSN, consider reneging to make
* room. Note: Playing nice with a confused sender. A * room. Note: Playing nice with a confused sender. A
...@@ -2409,7 +2413,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2409,7 +2413,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet. * processing the rest of the chunks in the packet.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_U32(SCTP_ERROR_NO_DATA));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
...@@ -2537,15 +2541,15 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2537,15 +2541,15 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_datahdr_t *data_hdr; sctp_datahdr_t *data_hdr;
sctp_chunk_t *err; struct sctp_chunk *err;
size_t datalen; size_t datalen;
int tmp; int tmp;
__u32 tsn; __u32 tsn;
...@@ -2581,11 +2585,15 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, ...@@ -2581,11 +2585,15 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* chunk later. * chunk later.
*/ */
if (!chunk->ecn_ce_done) { if (!chunk->ecn_ce_done) {
struct sctp_af *af;
chunk->ecn_ce_done = 1; chunk->ecn_ce_done = 1;
if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
asoc->peer.ecn_capable) { af = sctp_get_af_specific(
ipver2af(chunk->skb->nh.iph->version));
if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
/* Do real work as sideffect. */ /* Do real work as sideffect. */
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
SCTP_U32(tsn)); SCTP_U32(tsn));
} }
} }
...@@ -2625,7 +2633,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, ...@@ -2625,7 +2633,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet. * processing the rest of the chunks in the packet.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_U32(SCTP_ERROR_NO_DATA));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
...@@ -2712,13 +2720,13 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, ...@@ -2712,13 +2720,13 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_sackhdr_t *sackh; sctp_sackhdr_t *sackh;
__u32 ctsn; __u32 ctsn;
...@@ -2773,15 +2781,15 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, ...@@ -2773,15 +2781,15 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_packet *packet = NULL; struct sctp_packet *packet = NULL;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *abort; struct sctp_chunk *abort;
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
...@@ -2819,13 +2827,13 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, ...@@ -2819,13 +2827,13 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
while (chunk->chunk_end > chunk->skb->data) { while (chunk->chunk_end > chunk->skb->data) {
...@@ -2856,14 +2864,14 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, ...@@ -2856,14 +2864,14 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *reply; struct sctp_chunk *reply;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
/* 10.2 H) SHUTDOWN COMPLETE notification /* 10.2 H) SHUTDOWN COMPLETE notification
...@@ -2924,13 +2932,13 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, ...@@ -2924,13 +2932,13 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
* TCB was found. After sending this ABORT, the receiver of the OOTB * TCB was found. After sending this ABORT, the receiver of the OOTB
* packet shall discard the OOTB packet and take no further action. * packet shall discard the OOTB packet and take no further action.
*/ */
sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
struct sk_buff *skb = chunk->skb; struct sk_buff *skb = chunk->skb;
sctp_chunkhdr_t *ch; sctp_chunkhdr_t *ch;
__u8 *ch_end; __u8 *ch_end;
...@@ -2975,15 +2983,15 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, ...@@ -2975,15 +2983,15 @@ sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_packet *packet = NULL; struct sctp_packet *packet = NULL;
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_chunk_t *shut; struct sctp_chunk *shut;
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
...@@ -3024,8 +3032,8 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, ...@@ -3024,8 +3032,8 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
* chunks. --piggy ] * chunks. --piggy ]
* *
*/ */
sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3061,14 +3069,14 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep, ...@@ -3061,14 +3069,14 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *unk_chunk = arg; struct sctp_chunk *unk_chunk = arg;
sctp_chunk_t *err_chunk; struct sctp_chunk *err_chunk;
sctp_chunkhdr_t *hdr; sctp_chunkhdr_t *hdr;
SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk); SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk);
...@@ -3140,8 +3148,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep, ...@@ -3140,8 +3148,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3169,8 +3177,8 @@ sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, ...@@ -3169,8 +3177,8 @@ sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3198,13 +3206,13 @@ sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, ...@@ -3198,13 +3206,13 @@ sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t lucky(const sctp_endpoint_t *ep, sctp_disposition_t lucky(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the * that the value in the Verification Tag field of the
...@@ -3235,13 +3243,13 @@ sctp_disposition_t lucky(const sctp_endpoint_t *ep, ...@@ -3235,13 +3243,13 @@ sctp_disposition_t lucky(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, sctp_disposition_t other_stupid(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the * that the value in the Verification Tag field of the
...@@ -3271,8 +3279,8 @@ sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, ...@@ -3271,8 +3279,8 @@ sctp_disposition_t other_stupid(const sctp_endpoint_t *ep,
* We simply tag the chunk as a violation. The state machine will log * We simply tag the chunk as a violation. The state machine will log
* the violation and continue. * the violation and continue.
*/ */
sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3309,7 +3317,7 @@ sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, ...@@ -3309,7 +3317,7 @@ sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep,
* will be returned on successful establishment of the association. If * will be returned on successful establishment of the association. If
* SCTP is not able to open an SCTP association with the peer endpoint, * SCTP is not able to open an SCTP association with the peer endpoint,
* an error is returned. * an error is returned.
* [In the kernel implementation, the sctp_association_t needs to * [In the kernel implementation, the struct sctp_association needs to
* be created BEFORE causing this primitive to run.] * be created BEFORE causing this primitive to run.]
* *
* Other association parameters may be returned, including the * Other association parameters may be returned, including the
...@@ -3340,13 +3348,13 @@ sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, ...@@ -3340,13 +3348,13 @@ sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep,
* *
* The return value is a disposition. * The return value is a disposition.
*/ */
sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *repl; struct sctp_chunk *repl;
/* The comment below says that we enter COOKIE-WAIT AFTER /* The comment below says that we enter COOKIE-WAIT AFTER
* sending the INIT, but that doesn't actually work in our * sending the INIT, but that doesn't actually work in our
...@@ -3371,7 +3379,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, ...@@ -3371,7 +3379,7 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
* rerun it through as a sideffect. * rerun it through as a sideffect.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC,
SCTP_ASOC((sctp_association_t *) asoc)); SCTP_ASOC((struct sctp_association *) asoc));
/* After sending the INIT, "A" starts the T1-init timer and /* After sending the INIT, "A" starts the T1-init timer and
* enters the COOKIE-WAIT state. * enters the COOKIE-WAIT state.
...@@ -3446,13 +3454,13 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, ...@@ -3446,13 +3454,13 @@ sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
...@@ -3484,11 +3492,12 @@ sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, ...@@ -3484,11 +3492,12 @@ sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
int disposition; int disposition;
...@@ -3545,11 +3554,12 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, ...@@ -3545,11 +3554,12 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_1_prm_abort(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
/* From 9.1 Abort of an Association /* From 9.1 Abort of an Association
* Upon receipt of the ABORT primitive from its upper * Upon receipt of the ABORT primitive from its upper
...@@ -3560,7 +3570,7 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, ...@@ -3560,7 +3570,7 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
* if necessary to fill gaps. * if necessary to fill gaps.
*/ */
struct msghdr *msg = arg; struct msghdr *msg = arg;
sctp_chunk_t *abort; struct sctp_chunk *abort;
sctp_disposition_t retval; sctp_disposition_t retval;
retval = SCTP_DISPOSITION_CONSUME; retval = SCTP_DISPOSITION_CONSUME;
...@@ -3577,7 +3587,7 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, ...@@ -3577,7 +3587,7 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
*/ */
/* Delete the established association. */ /* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_USER_ABORT)); SCTP_U32(SCTP_ERROR_USER_ABORT));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
...@@ -3587,8 +3597,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, ...@@ -3587,8 +3597,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
} }
/* We tried an illegal operation on an association which is closed. */ /* We tried an illegal operation on an association which is closed. */
sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3600,8 +3610,8 @@ sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, ...@@ -3600,8 +3610,8 @@ sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep,
/* We tried an illegal operation on an association which is shutting /* We tried an illegal operation on an association which is shutting
* down. * down.
*/ */
sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3626,8 +3636,8 @@ sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, ...@@ -3626,8 +3636,8 @@ sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep,
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown( sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3660,8 +3670,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown( ...@@ -3660,8 +3670,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands) void *arg, sctp_cmd_seq_t *commands)
{ {
...@@ -3685,14 +3695,15 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( ...@@ -3685,14 +3695,15 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
* Outputs * Outputs
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
struct msghdr *msg = arg; struct msghdr *msg = arg;
sctp_chunk_t *abort; struct sctp_chunk *abort;
sctp_disposition_t retval; sctp_disposition_t retval;
/* Stop T1-init timer */ /* Stop T1-init timer */
...@@ -3717,7 +3728,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, ...@@ -3717,7 +3728,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
*/ */
/* Delete the established association. */ /* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(SCTP_ERROR_USER_ABORT)); SCTP_U32(SCTP_ERROR_USER_ABORT));
return retval; return retval;
...@@ -3737,11 +3748,12 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, ...@@ -3737,11 +3748,12 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
* Outputs * Outputs
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
/* There is a single T1 timer, so we should be able to use /* There is a single T1 timer, so we should be able to use
* common function with the COOKIE-WAIT state. * common function with the COOKIE-WAIT state.
...@@ -3762,8 +3774,8 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, ...@@ -3762,8 +3774,8 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep,
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_shutdown_pending_prm_abort( sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3788,8 +3800,8 @@ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort( ...@@ -3788,8 +3800,8 @@ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_shutdown_sent_prm_abort( sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3818,8 +3830,8 @@ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort( ...@@ -3818,8 +3830,8 @@ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3853,8 +3865,8 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( ...@@ -3853,8 +3865,8 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
* association on which a heartbeat should be issued. * association on which a heartbeat should be issued.
*/ */
sctp_disposition_t sctp_sf_do_prm_requestheartbeat( sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
const sctp_endpoint_t *ep, const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -3868,11 +3880,12 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat( ...@@ -3868,11 +3880,12 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
* *
* The return value is the disposition of the primitive. * The return value is the disposition of the primitive.
*/ */
sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_ignore_primitive(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive);
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
...@@ -3895,13 +3908,14 @@ sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, ...@@ -3895,13 +3908,14 @@ sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_start_shutdown(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *reply; struct sctp_chunk *reply;
/* Once all its outstanding data has been acknowledged, the /* Once all its outstanding data has been acknowledged, the
* endpoint shall send a SHUTDOWN chunk to its peer including * endpoint shall send a SHUTDOWN chunk to its peer including
...@@ -3956,14 +3970,15 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, ...@@ -3956,14 +3970,15 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep,
* *
* The return value is the disposition. * The return value is the disposition.
*/ */
sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = (sctp_chunk_t *) arg; struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
sctp_chunk_t *reply; struct sctp_chunk *reply;
/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
* shall send a SHUTDOWN ACK ... * shall send a SHUTDOWN ACK ...
...@@ -4009,8 +4024,8 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, ...@@ -4009,8 +4024,8 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the event. * The return value is the disposition of the event.
*/ */
sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4034,8 +4049,8 @@ sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, ...@@ -4034,8 +4049,8 @@ sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4044,7 +4059,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, ...@@ -4044,7 +4059,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
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. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
...@@ -4102,8 +4117,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, ...@@ -4102,8 +4117,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
* allow. However, an SCTP transmitter MUST NOT be more aggressive than * allow. However, an SCTP transmitter MUST NOT be more aggressive than
* the following algorithms allow. * the following algorithms allow.
*/ */
sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4137,14 +4152,14 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, ...@@ -4137,14 +4152,14 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep,
* (timers, events) * (timers, events)
* *
*/ */
sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *repl; struct sctp_chunk *repl;
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; sctp_event_timeout_t timer = (sctp_event_timeout_t) arg;
int timeout; int timeout;
int attempts; int attempts;
...@@ -4159,7 +4174,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, ...@@ -4159,7 +4174,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
(attempts < asoc->max_init_attempts)) { (attempts < asoc->max_init_attempts)) {
switch (timer) { switch (timer) {
case SCTP_EVENT_TIMEOUT_T1_INIT: case SCTP_EVENT_TIMEOUT_T1_INIT:
bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
break; break;
...@@ -4180,7 +4195,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, ...@@ -4180,7 +4195,7 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
SCTP_TO(timer)); SCTP_TO(timer));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
} else { } else {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
} }
...@@ -4204,18 +4219,18 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, ...@@ -4204,18 +4219,18 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
* the T2-Shutdown timer, giving its peer ample opportunity to transmit * the T2-Shutdown timer, giving its peer ample opportunity to transmit
* all of its queued DATA chunks that have not yet been sent. * all of its queued DATA chunks that have not yet been sent.
*/ */
sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *reply = NULL; struct sctp_chunk *reply = NULL;
SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
if (asoc->overall_error_count >= asoc->overall_error_threshold) { if (asoc->overall_error_count >= asoc->overall_error_threshold) {
/* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
...@@ -4264,13 +4279,13 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, ...@@ -4264,13 +4279,13 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
* At the expiration of this timer the sender SHOULD abort the association * At the expiration of this timer the sender SHOULD abort the association
* by sending an ABORT chunk. * by sending an ABORT chunk.
*/ */
sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *reply = NULL; struct sctp_chunk *reply = NULL;
SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
...@@ -4279,7 +4294,7 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep, ...@@ -4279,7 +4294,7 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
...@@ -4292,11 +4307,12 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep, ...@@ -4292,11 +4307,12 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
* The work that needs to be done is same as when SHUTDOWN is initiated by * The work that needs to be done is same as when SHUTDOWN is initiated by
* the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown().
*/ */
sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_autoclose_timer_expire(
const sctp_association_t *asoc, const struct sctp_endpoint *ep,
const sctp_subtype_t type, const struct sctp_association *asoc,
void *arg, const sctp_subtype_t type,
sctp_cmd_seq_t *commands) void *arg,
sctp_cmd_seq_t *commands)
{ {
int disposition; int disposition;
...@@ -4337,8 +4353,8 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, ...@@ -4337,8 +4353,8 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4354,8 +4370,8 @@ sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, ...@@ -4354,8 +4370,8 @@ sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4374,8 +4390,8 @@ sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, ...@@ -4374,8 +4390,8 @@ sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
...@@ -4389,7 +4405,7 @@ sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, ...@@ -4389,7 +4405,7 @@ sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep,
********************************************************************/ ********************************************************************/
/* Pull the SACK chunk based on the SACK header. */ /* Pull the SACK chunk based on the SACK header. */
sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *chunk)
{ {
sctp_sackhdr_t *sack; sctp_sackhdr_t *sack;
__u16 num_blocks; __u16 num_blocks;
...@@ -4411,14 +4427,14 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) ...@@ -4411,14 +4427,14 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
/* Create an ABORT packet to be sent as a response, with the specified /* Create an ABORT packet to be sent as a response, with the specified
* error causes. * error causes.
*/ */
struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep, struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
const void *payload, const void *payload,
size_t paylen) size_t paylen)
{ {
struct sctp_packet *packet; struct sctp_packet *packet;
sctp_chunk_t *abort; struct sctp_chunk *abort;
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
...@@ -4447,8 +4463,8 @@ struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep, ...@@ -4447,8 +4463,8 @@ struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
} }
/* Allocate a packet for responding in the OOTB conditions. */ /* Allocate a packet for responding in the OOTB conditions. */
struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc, struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
const sctp_chunk_t *chunk) const struct sctp_chunk *chunk)
{ {
struct sctp_packet *packet; struct sctp_packet *packet;
struct sctp_transport *transport; struct sctp_transport *transport;
...@@ -4512,11 +4528,11 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet) ...@@ -4512,11 +4528,11 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet)
} }
/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */
void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const sctp_association_t *asoc, const struct sctp_association *asoc,
const sctp_chunk_t *chunk, const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_chunk_t *err_chunk) struct sctp_chunk *err_chunk)
{ {
struct sctp_packet *packet; struct sctp_packet *packet;
...@@ -4530,6 +4546,6 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, ...@@ -4530,6 +4546,6 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
SCTP_PACKET(packet)); SCTP_PACKET(packet));
SCTP_INC_STATS(SctpOutCtrlChunks); SCTP_INC_STATS(SctpOutCtrlChunks);
} else } else
sctp_free_chunk (err_chunk); sctp_chunk_free (err_chunk);
} }
} }
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/compiler.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/time.h> #include <linux/time.h>
...@@ -63,6 +62,7 @@ ...@@ -63,6 +62,7 @@
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/crypto.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/icmp.h> #include <net/icmp.h>
...@@ -82,13 +82,14 @@ ...@@ -82,13 +82,14 @@
/* Forward declarations for internal helper functions. */ /* Forward declarations for internal helper functions. */
static int sctp_writeable(struct sock *sk); static int sctp_writeable(struct sock *sk);
static inline int sctp_wspace(struct sctp_association *asoc); static inline int sctp_wspace(struct sctp_association *asoc);
static inline void sctp_set_owner_w(sctp_chunk_t *chunk); static inline void sctp_set_owner_w(struct sctp_chunk *chunk);
static void sctp_wfree(struct sk_buff *skb); static void sctp_wfree(struct sk_buff *skb);
static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, static int sctp_wait_for_sndbuf(struct sctp_association *, 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(struct sctp_association *, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
static int sctp_wait_for_accept(struct sock *sk, long timeo); static int sctp_wait_for_accept(struct sock *sk, long timeo);
static void sctp_wait_for_close(struct sock *sk, long timeo);
static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, 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);
...@@ -96,31 +97,33 @@ static int sctp_do_bind(struct sock *, union sctp_addr *, int); ...@@ -96,31 +97,33 @@ 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);
static void sctp_sock_migrate(struct sock *, struct sock *, static void sctp_sock_migrate(struct sock *, struct sock *,
struct sctp_association *, sctp_socket_type_t); struct sctp_association *, sctp_socket_type_t);
static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
/* Look up the association by its id. If this is not a UDP-style /* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored. * socket, the ID field is always ignored.
*/ */
sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
{ {
sctp_association_t *asoc = NULL; struct sctp_association *asoc = NULL;
/* If this is not a UDP-style socket, assoc id should be /* If this is not a UDP-style socket, assoc id should be
* ignored. * ignored.
*/ */
if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { if (!sctp_style(sk, UDP)) {
if (!list_empty(&sctp_sk(sk)->ep->asocs)) if (!list_empty(&sctp_sk(sk)->ep->asocs))
asoc = list_entry(sctp_sk(sk)->ep->asocs.next, asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
sctp_association_t, asocs); struct sctp_association, asocs);
return asoc; return asoc;
} }
/* First, verify that this is a kernel address. */ /* First, verify that this is a kernel address. */
if (sctp_is_valid_kaddr((unsigned long) id)) { if (sctp_is_valid_kaddr((unsigned long) id)) {
sctp_association_t *temp = (sctp_association_t *) id; struct sctp_association *temp;
/* Verify that this _is_ an sctp_association_t /* Verify that this _is_ an sctp_association
* data structure and if so, that the socket matches. * data structure and if so, that the socket matches.
*/ */
temp = (struct sctp_association *)id;
if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
(temp->base.sk == sk)) (temp->base.sk == sk))
asoc = temp; asoc = temp;
...@@ -188,13 +191,12 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, ...@@ -188,13 +191,12 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
return af; return af;
} }
/* 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, union sctp_addr *addr, int len) SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
sctp_bind_addr_t *bp = &ep->base.bind_addr; struct sctp_bind_addr *bp = &ep->base.bind_addr;
struct sctp_af *af; struct sctp_af *af;
unsigned short snum; unsigned short snum;
int ret = 0; int ret = 0;
...@@ -260,7 +262,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) ...@@ -260,7 +262,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
/* Copy back into socket for getsockname() use. */ /* Copy back into socket for getsockname() use. */
if (!ret) { if (!ret) {
inet_sk(sk)->sport = htons(inet_sk(sk)->num); inet_sk(sk)->sport = htons(inet_sk(sk)->num);
af->to_sk(addr, sk); af->to_sk_saddr(addr, sk);
} }
return ret; return ret;
...@@ -450,12 +452,12 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -450,12 +452,12 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
/* Add these addresses to all associations on this endpoint. */ /* Add these addresses to all associations on this endpoint. */
if (retval >= 0) { if (retval >= 0) {
struct list_head *pos; struct list_head *pos;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
list_for_each(pos, &ep->asocs) { list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, sctp_association_t, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
sctp_addip_addr_config(asoc, sctp_addip_addr_config(asoc,
SCTP_PARAM_ADD_IP, SCTP_PARAM_ADD_IP,
...@@ -485,9 +487,9 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -485,9 +487,9 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
int cnt; int cnt;
sctp_bind_addr_t *bp = &ep->base.bind_addr; struct sctp_bind_addr *bp = &ep->base.bind_addr;
int retval = 0; int retval = 0;
union sctp_addr saveaddr; union sctp_addr saveaddr;
...@@ -570,12 +572,12 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -570,12 +572,12 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
/* Remove these addresses from all associations on this endpoint. */ /* Remove these addresses from all associations on this endpoint. */
if (retval >= 0) { if (retval >= 0) {
struct list_head *pos; struct list_head *pos;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
list_for_each(pos, &ep->asocs) { list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, sctp_association_t, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP,
addrs, addrcnt); addrs, addrcnt);
} }
...@@ -637,7 +639,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, ...@@ -637,7 +639,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
/* Alloc space for the address array in kernel memory. */ /* Alloc space for the address array in kernel memory. */
kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL);
if (unlikely(NULL == kaddrs)) if (unlikely(!kaddrs))
return -ENOMEM; return -ENOMEM;
if (copy_from_user(kaddrs, addrs, addrssize)) { if (copy_from_user(kaddrs, addrs, addrssize)) {
...@@ -670,14 +672,45 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, ...@@ -670,14 +672,45 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
* *
* If sd in the close() call is a branched-off socket representing only * If sd in the close() call is a branched-off socket representing only
* one association, the shutdown is performed on that association only. * one association, the shutdown is performed on that association only.
*
* 4.1.6 close() - TCP Style Syntax
*
* Applications use close() to gracefully close down an association.
*
* The syntax is:
*
* int close(int sd);
*
* sd - the socket descriptor of the association to be closed.
*
* After an application calls close() on a socket descriptor, no further
* socket operations will succeed on that descriptor.
*
* API 7.1.4 SO_LINGER
*
* An application using the TCP-style socket can use this option to
* perform the SCTP ABORT primitive. The linger option structure is:
*
* struct linger {
* int l_onoff; // option on/off
* int l_linger; // linger time
* };
*
* To enable the option, set l_onoff to 1. If the l_linger value is set
* to 0, calling close() is the same as the ABORT primitive. If the
* value is set to a negative value, the setsockopt() call will return
* an error. If the value is set to a positive value linger_time, the
* close() can be blocked for at most linger_time ms. If the graceful
* shutdown phase does not finish during this period, close() will
* return but the graceful shutdown phase continues in the system.
*/ */
SCTP_STATIC void sctp_close(struct sock *sk, long timeout) SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos, *temp; struct list_head *pos, *temp;
SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
sctp_lock_sock(sk); sctp_lock_sock(sk);
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
...@@ -686,14 +719,35 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -686,14 +719,35 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Walk all associations on a socket, not on an endpoint. */ /* Walk all associations on a socket, not on an endpoint. */
list_for_each_safe(pos, temp, &ep->asocs) { list_for_each_safe(pos, temp, &ep->asocs) {
asoc = list_entry(pos, sctp_association_t, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
sctp_primitive_SHUTDOWN(asoc, NULL);
if (sctp_style(sk, TCP)) {
/* A closed association can still be in the list if
* it belongs to a TCP-style listening socket that is
* not yet accepted. If so, free it. If not, send an
* ABORT or SHUTDOWN based on the linger options.
*/
if (sctp_state(asoc, CLOSED)) {
sctp_unhash_established(asoc);
sctp_association_free(asoc);
} else if (test_bit(SOCK_LINGER, &sk->flags) &&
!sk->lingertime)
sctp_primitive_ABORT(asoc, NULL);
else
sctp_primitive_SHUTDOWN(asoc, NULL);
} else
sctp_primitive_SHUTDOWN(asoc, NULL);
} }
/* Clean up any skbs sitting on the receive queue. */ /* Clean up any skbs sitting on the receive queue. */
skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sctp_sk(sk)->pd_lobby); skb_queue_purge(&sctp_sk(sk)->pd_lobby);
/* On a TCP-style socket, block for at most linger_time if set. */
if (sctp_style(sk, TCP) && timeout)
sctp_wait_for_close(sk, timeout);
/* This will run the backlog queue. */ /* This will run the backlog queue. */
sctp_release_sock(sk); sctp_release_sock(sk);
...@@ -717,6 +771,16 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -717,6 +771,16 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
SCTP_DBG_OBJCNT_DEC(sock); SCTP_DBG_OBJCNT_DEC(sock);
} }
/* Handle EPIPE error. */
static int sctp_error(struct sock *sk, int flags, int err)
{
if (err == -EPIPE)
err = sock_error(sk) ? : -EPIPE;
if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
send_sig(SIGPIPE, current, 0);
return err;
}
/* API 3.1.3 sendmsg() - UDP Style Syntax /* API 3.1.3 sendmsg() - UDP Style Syntax
* *
* An application uses sendmsg() and recvmsg() calls to transmit data to * An application uses sendmsg() and recvmsg() calls to transmit data to
...@@ -746,10 +810,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -746,10 +810,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, int msg_len) struct msghdr *msg, int msg_len)
{ {
struct sctp_opt *sp; struct sctp_opt *sp;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *new_asoc=NULL, *asoc=NULL; struct sctp_association *new_asoc=NULL, *asoc=NULL;
struct sctp_transport *transport; struct sctp_transport *transport, *chunk_tp;
sctp_chunk_t *chunk = NULL; struct sctp_chunk *chunk;
union sctp_addr 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 };
...@@ -761,7 +825,9 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -761,7 +825,9 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sctp_scope_t scope; sctp_scope_t scope;
long timeo; long timeo;
__u16 sinfo_flags = 0; __u16 sinfo_flags = 0;
struct sk_buff_head chunks; struct sctp_datamsg *datamsg;
struct list_head *pos;
int msg_flags = msg->msg_flags;
SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n",
sk, msg, msg_len); sk, msg, msg_len);
...@@ -772,6 +838,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -772,6 +838,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);
/* We cannot send a message over a TCP-style listening socket. */
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) {
err = -EPIPE;
goto out_nounlock;
}
/* Parse out the SCTP CMSGs. */ /* Parse out the SCTP CMSGs. */
err = sctp_msghdr_parse(msg, &cmsgs); err = sctp_msghdr_parse(msg, &cmsgs);
...@@ -785,7 +857,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -785,7 +857,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* the address we will send to. * the address we will send to.
* 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_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) {
int msg_namelen = msg->msg_namelen; int msg_namelen = msg->msg_namelen;
err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name,
...@@ -816,6 +888,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -816,6 +888,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
msg_len, sinfo_flags); msg_len, sinfo_flags);
/* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */
if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) {
err = -EINVAL;
goto out_nounlock;
}
/* If MSG_EOF is set, no data can be sent. Disallow sending zero /* If MSG_EOF is set, no data can be sent. Disallow sending zero
* length messages when MSG_EOF|MSG_ABORT is not set. * length messages when MSG_EOF|MSG_ABORT is not set.
* If MSG_ABORT is set, the message length could be non zero with * If MSG_ABORT is set, the message length could be non zero with
...@@ -827,22 +905,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -827,22 +905,33 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_nounlock; goto out_nounlock;
} }
sctp_lock_sock(sk); /* If MSG_ADDR_OVER is set, there must be an address
* specified in msg_name.
*/
if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) {
err = -EINVAL;
goto out_nounlock;
}
transport = NULL; transport = NULL;
SCTP_DEBUG_PRINTK("About to look up association.\n"); SCTP_DEBUG_PRINTK("About to look up association.\n");
sctp_lock_sock(sk);
/* If a msg_name has been specified, assume this is to be used. */ /* If a msg_name has been specified, assume this is to be used. */
if (msg_name) { if (msg_name) {
/* 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) {
/* If we could not find a matching association on the /* If we could not find a matching association on the
* endpoint, make sure that there is no peeled-off * endpoint, make sure that it is not a TCP-style
* association on another socket. * socket that already has an association or there is
* no peeled-off association on another socket.
*/ */
if (sctp_endpoint_is_peeled_off(ep, &to)) { if ((sctp_style(sk, TCP) &&
sctp_sstate(sk, ESTABLISHED)) ||
sctp_endpoint_is_peeled_off(ep, &to)) {
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
goto out_unlock; goto out_unlock;
} }
...@@ -850,14 +939,24 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -850,14 +939,24 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} else { } else {
asoc = sctp_id2assoc(sk, associd); asoc = sctp_id2assoc(sk, associd);
if (!asoc) { if (!asoc) {
err = -EINVAL; err = -EPIPE;
goto out_unlock; goto out_unlock;
} }
} }
if (asoc) { if (asoc) {
SCTP_DEBUG_PRINTK("Just looked up association: " SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);
"%s. \n", asoc->debug_name);
/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED
* socket that has an association in CLOSED state. This can
* happen when an accepted socket has an association that is
* already CLOSED.
*/
if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) {
err = -EPIPE;
goto out_unlock;
}
if (sinfo_flags & MSG_EOF) { if (sinfo_flags & MSG_EOF) {
SCTP_DEBUG_PRINTK("Shutting down association: %p\n", SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
asoc); asoc);
...@@ -1004,69 +1103,76 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1004,69 +1103,76 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_free; goto out_free;
} }
/* Break the message into multiple chunks of maximum size. */ /* If an address is passed with the sendto/sendmsg call, it is used
skb_queue_head_init(&chunks); * to override the primary destination address in the TCP model, or
err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks); * when MSG_ADDR_OVER flag is set in the UDP model.
if (err) */
goto out_free; if ((sctp_style(sk, TCP) && msg_name) ||
(sinfo_flags & MSG_ADDR_OVER)) {
chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
if (!chunk_tp) {
err = -EINVAL;
goto out_free;
}
} else
chunk_tp = NULL;
/* Auto-connect, if we aren't connected already. */ /* Auto-connect, if we aren't connected already. */
if (SCTP_STATE_CLOSED == asoc->state) { if (sctp_state(asoc, CLOSED)) {
err = sctp_primitive_ASSOCIATE(asoc, NULL); err = sctp_primitive_ASSOCIATE(asoc, NULL);
if (err < 0) if (err < 0)
goto out_free; goto out_free;
SCTP_DEBUG_PRINTK("We associated primitively.\n"); SCTP_DEBUG_PRINTK("We associated primitively.\n");
} }
/* Break the message into multiple chunks of maximum size. */
datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len);
if (!datamsg) {
err = -ENOMEM;
goto out_free;
}
/* Now send the (possibly) fragmented message. */ /* Now send the (possibly) fragmented message. */
while ((chunk = (sctp_chunk_t *)__skb_dequeue(&chunks))) { list_for_each(pos, &datamsg->chunks) {
chunk = list_entry(pos, struct sctp_chunk, frag_list);
sctp_datamsg_track(chunk);
/* Do accounting for the write space. */ /* Do accounting for the write space. */
sctp_set_owner_w(chunk); sctp_set_owner_w(chunk);
/* This flag, in the UDP model, requests the SCTP stack to chunk->transport = chunk_tp;
* override the primary destination address with the
* address found with the sendto/sendmsg call.
*/
if (sinfo_flags & MSG_ADDR_OVER) {
if (!msg->msg_name) {
err = -EINVAL;
goto out_free;
}
chunk->transport = sctp_assoc_lookup_paddr(asoc, &to);
if (!chunk->transport) {
err = -EINVAL;
goto out_free;
}
}
/* Send it to the lower layers. */ /* Send it to the lower layers. Note: all chunks
sctp_primitive_SEND(asoc, chunk); * must either fail or succeed. The lower layer
* works that way today. Keep it that way or this
* breaks.
*/
err = sctp_primitive_SEND(asoc, chunk);
/* Did the lower layer accept the chunk? */
if (err)
sctp_chunk_free(chunk);
SCTP_DEBUG_PRINTK("We sent primitively.\n"); SCTP_DEBUG_PRINTK("We sent primitively.\n");
} }
if (!err) { sctp_datamsg_free(datamsg);
if (err)
goto out_free;
else
err = msg_len; err = msg_len;
goto out_unlock;
}
/* If we are already past ASSOCIATE, the lower /* If we are already past ASSOCIATE, the lower
* layers are responsible for association cleanup. * layers are responsible for association cleanup.
*/ */
goto out_free_chunk; goto out_unlock;
out_free: out_free:
if (new_asoc) if (new_asoc)
sctp_association_free(asoc); sctp_association_free(asoc);
out_free_chunk:
if (chunk)
sctp_free_chunk(chunk);
out_unlock: out_unlock:
sctp_release_sock(sk); sctp_release_sock(sk);
out_nounlock: out_nounlock:
return err; return sctp_error(sk, msg_flags, err);
#if 0 #if 0
do_sock_err: do_sock_err:
...@@ -1134,8 +1240,9 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) ...@@ -1134,8 +1240,9 @@ static int sctp_skb_pull(struct sk_buff *skb, int len)
*/ */
static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
int len, int noblock, int flags, int *addr_len) struct msghdr *msg, int len, int noblock,
int flags, int *addr_len)
{ {
struct sctp_ulpevent *event = NULL; struct sctp_ulpevent *event = NULL;
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
...@@ -1151,12 +1258,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1151,12 +1258,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
sctp_lock_sock(sk); sctp_lock_sock(sk);
if ((SCTP_SOCKET_TCP == sp->type) && if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) {
(SCTP_SS_ESTABLISHED != sk->state)) {
err = -ENOTCONN; err = -ENOTCONN;
goto out; goto out;
} }
skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);
if (!skb) if (!skb)
goto out; goto out;
...@@ -1259,7 +1365,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1259,7 +1365,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sp->type) if (sctp_style(sk, TCP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (optlen != sizeof(int)) if (optlen != sizeof(int))
return -EINVAL; return -EINVAL;
...@@ -1271,10 +1377,10 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1271,10 +1377,10 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
} }
static int sctp_setsockopt_peer_addr_params(struct sock *sk, static int sctp_setsockopt_peer_addr_params(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
sctp_association_t *asoc; struct sctp_association *asoc;
union sctp_addr *addr; union sctp_addr *addr;
struct sctp_transport *trans; struct sctp_transport *trans;
int error; int error;
...@@ -1329,8 +1435,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1329,8 +1435,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
return 0; return 0;
} }
static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
int optlen)
{ {
if (optlen != sizeof(struct sctp_initmsg)) if (optlen != sizeof(struct sctp_initmsg))
return -EINVAL; return -EINVAL;
...@@ -1340,7 +1445,6 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, ...@@ -1340,7 +1445,6 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
} }
/* /*
*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
* *
* Applications that wish to use the sendto() system call may wish to * Applications that wish to use the sendto() system call may wish to
...@@ -1358,7 +1462,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -1358,7 +1462,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
sctp_association_t *asoc; struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_sndrcvinfo)) if (optlen != sizeof(struct sctp_sndrcvinfo))
return -EINVAL; return -EINVAL;
...@@ -1413,7 +1517,6 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) ...@@ -1413,7 +1517,6 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
} }
/* /*
*
* 7.1.5 SCTP_NODELAY * 7.1.5 SCTP_NODELAY
* *
* Turn on/off any Nagle-like algorithm. This means that packets are * Turn on/off any Nagle-like algorithm. This means that packets are
...@@ -1424,15 +1527,61 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) ...@@ -1424,15 +1527,61 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
__u8 val; int val;
if (optlen < sizeof(__u8)) if (optlen < sizeof(int))
return -EINVAL; return -EINVAL;
if (get_user(val, (int *)optval))
if (get_user(val, (__u8 *)optval))
return -EFAULT; return -EFAULT;
sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
return 0;
}
/*
* 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
*
* This socket option is a boolean flag which turns on or off mapped V4
* addresses. If this option is turned on and the socket is type
* PF_INET6, then IPv4 addresses will be mapped to V6 representation.
* If this option is turned off, then no mapping will be done of V4
* addresses and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket.
*/
static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen)
{
int val;
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int *)optval))
return -EFAULT;
/* FIXME: Put real support here. */
return -ENOPROTOOPT;
}
/*
* 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
*
* This socket option specifies the maximum size to put in any outgoing
* SCTP chunk. If a message is larger than this size it will be
* fragmented by SCTP into the specified size. Note that the underlying
* SCTP implementation may fragment into smaller sized chunks when the
* PMTU of the underlying association is smaller than the value set by
* the user.
*/
static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
{
int val;
if (optlen < sizeof(int))
return -EINVAL;
if (get_user(val, (int *)optval))
return -EFAULT;
if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))
return -EINVAL;
sctp_sk(sk)->user_frag = val;
return 0; return 0;
} }
...@@ -1526,20 +1675,22 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1526,20 +1675,22 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_INITMSG: case SCTP_INITMSG:
retval = sctp_setsockopt_initmsg(sk, optval, optlen); retval = sctp_setsockopt_initmsg(sk, optval, optlen);
break; break;
case SCTP_SET_DEFAULT_SEND_PARAM: case SCTP_SET_DEFAULT_SEND_PARAM:
retval = sctp_setsockopt_default_send_param(sk, optval, retval = sctp_setsockopt_default_send_param(sk, optval,
optlen); optlen);
break; break;
case SCTP_SET_PEER_PRIMARY_ADDR: case SCTP_SET_PEER_PRIMARY_ADDR:
retval = sctp_setsockopt_peer_prim(sk, optval, optlen); retval = sctp_setsockopt_peer_prim(sk, optval, optlen);
break; break;
case SCTP_NODELAY: case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen); retval = sctp_setsockopt_nodelay(sk, optval, optlen);
break; break;
case SCTP_I_WANT_MAPPED_V4_ADDR:
retval = sctp_setsockopt_mappedv4(sk, optval, optlen);
break;
case SCTP_MAXSEG:
retval = sctp_setsockopt_maxseg(sk, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -1572,10 +1723,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -1572,10 +1723,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len) int addr_len)
{ {
struct sctp_opt *sp; struct sctp_opt *sp;
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
union sctp_addr to; union sctp_addr to;
struct sctp_af *af;
sctp_scope_t scope; sctp_scope_t scope;
long timeo; long timeo;
int err = 0; int err = 0;
...@@ -1590,12 +1742,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -1590,12 +1742,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
/* connect() cannot be done on a socket that is already in ESTABLISHED /* connect() cannot be done on a socket that is already in ESTABLISHED
* state - UDP-style peeled off socket or a TCP-style socket that * state - UDP-style peeled off socket or a TCP-style socket that
* is already connected. * is already connected.
* It cannot be done even on a TCP-style listening socket. * It cannot be done even on a TCP-style listening socket.
*/ */
if ((SCTP_SS_ESTABLISHED == sk->state) || if (sctp_sstate(sk, ESTABLISHED) ||
((SCTP_SOCKET_TCP == sp->type) && (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) {
(SCTP_SS_LISTENING == sk->state))) {
err = -EISCONN; err = -EISCONN;
goto out_unlock; goto out_unlock;
} }
...@@ -1663,6 +1814,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -1663,6 +1814,11 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
goto out_unlock; goto out_unlock;
} }
/* Initialize sk's dport and daddr for getpeername() */
inet_sk(sk)->dport = htons(asoc->peer.port);
af = sctp_get_af_specific(to.sa.sa_family);
af->to_sk_daddr(&to, sk);
timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
err = sctp_wait_for_connect(asoc, &timeo); err = sctp_wait_for_connect(asoc, &timeo);
...@@ -1690,21 +1846,21 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) ...@@ -1690,21 +1846,21 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
struct sctp_opt *sp; struct sctp_opt *sp;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
struct sock *newsk = NULL; struct sock *newsk = NULL;
struct sctp_association *assoc; struct sctp_association *asoc;
long timeo; long timeo;
int error = 0; int error = 0;
sctp_lock_sock(sk); sctp_lock_sock(sk);
sp = sctp_sk(sk); sp = sctp_sk(sk);
ep = sp->ep; ep = sp->ep;
if (SCTP_SOCKET_TCP != sp->type) { if (!sctp_style(sk, TCP)) {
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
goto out; goto out;
} }
if (SCTP_SS_LISTENING != sk->state) { if (!sctp_sstate(sk, LISTENING)) {
error = -EINVAL; error = -EINVAL;
goto out; goto out;
} }
...@@ -1715,21 +1871,21 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) ...@@ -1715,21 +1871,21 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
if (error) if (error)
goto out; goto out;
/* We treat the list of associations on the endpoint as the accept /* We treat the list of associations on the endpoint as the accept
* queue and pick the first association on the list. * queue and pick the first association on the list.
*/ */
assoc = list_entry(ep->asocs.next, struct sctp_association, asocs); asoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
newsk = sp->pf->create_accept_sk(sk, assoc); newsk = sp->pf->create_accept_sk(sk, asoc);
if (!newsk) { if (!newsk) {
error = -ENOMEM; error = -ENOMEM;
goto out; goto out;
} }
/* Populate the fields of the newsk from the oldsk and migrate the /* Populate the fields of the newsk from the oldsk and migrate the
* assoc to the newsk. * asoc to the newsk.
*/ */
sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP); sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);
out: out:
sctp_release_sock(sk); sctp_release_sock(sk);
...@@ -1737,10 +1893,10 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) ...@@ -1737,10 +1893,10 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err)
return newsk; return newsk;
} }
/* FIXME: Write Comments. */ /* The SCTP ioctl handler. */
SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{ {
return -EOPNOTSUPP; /* STUB */ return -ENOIOCTLCMD;
} }
/* This is the function which gets called during socket creation to /* This is the function which gets called during socket creation to
...@@ -1749,7 +1905,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -1749,7 +1905,7 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
*/ */
SCTP_STATIC int sctp_init_sock(struct sock *sk) SCTP_STATIC int sctp_init_sock(struct sock *sk)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
struct sctp_protocol *proto; struct sctp_protocol *proto;
struct sctp_opt *sp; struct sctp_opt *sp;
...@@ -1800,7 +1956,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1800,7 +1956,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
* enable the events needed. By default, UDP-style * enable the events needed. By default, UDP-style
* sockets enable io and association change notifications. * sockets enable io and association change notifications.
*/ */
if (SCTP_SOCKET_UDP == sp->type) { if (sctp_style(sk, UDP)) {
sp->subscribe.sctp_data_io_event = 1; sp->subscribe.sctp_data_io_event = 1;
sp->subscribe.sctp_association_event = 1; sp->subscribe.sctp_association_event = 1;
} }
...@@ -1819,12 +1975,19 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1819,12 +1975,19 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Turn on/off any Nagle-like algorithm. */ /* Turn on/off any Nagle-like algorithm. */
sp->nodelay = 1; sp->nodelay = 1;
/* Enable by default. */
sp->v4mapped = 1;
/* Auto-close idle associations after the configured /* Auto-close idle associations after the configured
* number of seconds. A value of 0 disables this * number of seconds. A value of 0 disables this
* feature. Configure through the SCTP_AUTOCLOSE socket option, * feature. Configure through the SCTP_AUTOCLOSE socket option,
* for UDP-style sockets only. * for UDP-style sockets only.
*/ */
sp->autoclose = 0; sp->autoclose = 0;
/* User specified fragmentation limit. */
sp->user_frag = 0;
sp->pf = sctp_get_pf_specific(sk->family); sp->pf = sctp_get_pf_specific(sk->family);
/* Control variables for partial data delivery. */ /* Control variables for partial data delivery. */
...@@ -1835,11 +1998,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1835,11 +1998,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
* change the data structure relationships, this may still * change the data structure relationships, this may still
* be useful for storing pre-connect address information. * be useful for storing pre-connect address information.
*/ */
ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); ep = sctp_endpoint_new(sk, GFP_KERNEL);
if (NULL == ep) if (!ep)
return -ENOMEM; return -ENOMEM;
sp->ep = ep; sp->ep = ep;
sp->hmac = NULL;
SCTP_DBG_OBJCNT_INC(sock); SCTP_DBG_OBJCNT_INC(sock);
return 0; return 0;
...@@ -1848,7 +2012,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1848,7 +2012,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Cleanup any SCTP per socket resources. */ /* Cleanup any SCTP per socket resources. */
SCTP_STATIC int sctp_destroy_sock(struct sock *sk) SCTP_STATIC int sctp_destroy_sock(struct sock *sk)
{ {
sctp_endpoint_t *ep; struct sctp_endpoint *ep;
SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);
...@@ -1859,11 +2023,38 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) ...@@ -1859,11 +2023,38 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk)
return 0; return 0;
} }
/* FIXME: Comments needed. */ /* API 4.1.7 shutdown() - TCP Style Syntax
* int shutdown(int socket, int how);
*
* sd - the socket descriptor of the association to be closed.
* how - Specifies the type of shutdown. The values are
* as follows:
* SHUT_RD
* Disables further receive operations. No SCTP
* protocol action is taken.
* SHUT_WR
* Disables further send operations, and initiates
* the SCTP shutdown sequence.
* SHUT_RDWR
* Disables further send and receive operations
* and initiates the SCTP shutdown sequence.
*/
SCTP_STATIC void sctp_shutdown(struct sock *sk, int how) SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
{ {
/* UDP-style sockets do not support shutdown. */ struct sctp_endpoint *ep;
/* STUB */ struct sctp_association *asoc;
if (!sctp_style(sk, TCP))
return;
if (how & SEND_SHUTDOWN) {
ep = sctp_sk(sk)->ep;
if (!list_empty(&ep->asocs)) {
asoc = list_entry(ep->asocs.next,
struct sctp_association, asocs);
sctp_primitive_SHUTDOWN(asoc, NULL);
}
}
} }
/* 7.2.1 Association Status (SCTP_STATUS) /* 7.2.1 Association Status (SCTP_STATUS)
...@@ -1877,7 +2068,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1877,7 +2068,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
int *optlen) int *optlen)
{ {
struct sctp_status status; struct sctp_status status;
sctp_association_t *assoc = NULL; struct sctp_association *asoc = NULL;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_assoc_t associd; sctp_assoc_t associd;
int retval = 0; int retval = 0;
...@@ -1893,22 +2084,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1893,22 +2084,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
} }
associd = status.sstat_assoc_id; associd = status.sstat_assoc_id;
assoc = sctp_id2assoc(sk, associd); asoc = sctp_id2assoc(sk, associd);
if (!assoc) { if (!asoc) {
retval = -EINVAL; retval = -EINVAL;
goto out; goto out;
} }
transport = assoc->peer.primary_path; transport = asoc->peer.primary_path;
status.sstat_assoc_id = sctp_assoc2id(assoc); status.sstat_assoc_id = sctp_assoc2id(asoc);
status.sstat_state = assoc->state; status.sstat_state = asoc->state;
status.sstat_rwnd = assoc->peer.rwnd; status.sstat_rwnd = asoc->peer.rwnd;
status.sstat_unackdata = assoc->unack_data; status.sstat_unackdata = asoc->unack_data;
status.sstat_penddata = assoc->peer.tsn_map.pending_data; status.sstat_penddata = asoc->peer.tsn_map.pending_data;
status.sstat_instrms = assoc->c.sinit_max_instreams; status.sstat_instrms = asoc->c.sinit_max_instreams;
status.sstat_outstrms = assoc->c.sinit_num_ostreams; status.sstat_outstrms = asoc->c.sinit_num_ostreams;
status.sstat_fragmentation_point = assoc->frag_point; /* Just in time frag_point update. */
if (sctp_sk(sk)->user_frag)
asoc->frag_point
= min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag);
status.sstat_fragmentation_point = asoc->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(union sctp_addr)); &(transport->ipaddr), sizeof(union sctp_addr));
...@@ -1965,7 +2160,7 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in ...@@ -1965,7 +2160,7 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in
static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
{ {
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) if (sctp_style(sk, TCP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (len != sizeof(int)) if (len != sizeof(int))
return -EINVAL; return -EINVAL;
...@@ -1975,33 +2170,29 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int ...@@ -1975,33 +2170,29 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int
} }
/* Helper routine to branch off an association to a new socket. */ /* Helper routine to branch off an association to a new socket. */
SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
struct socket **sockp)
{ {
struct sock *oldsk = assoc->base.sk; struct sock *sk = asoc->base.sk;
struct sock *newsk; struct socket *sock;
struct socket *tmpsock;
int err = 0; int err = 0;
/* An association cannot be branched off from an already peeled-off /* An association cannot be branched off from an already peeled-off
* socket, nor is this supported for tcp style sockets. * socket, nor is this supported for tcp style sockets.
*/ */
if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type) if (!sctp_style(sk, UDP))
return -EOPNOTSUPP; return -EINVAL;
/* Create a new socket. */ /* Create a new socket. */
err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP, err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
&tmpsock);
if (err < 0) if (err < 0)
return err; return err;
newsk = tmpsock->sk;
/* Populate the fields of the newsk from the oldsk and migrate the /* Populate the fields of the newsk from the oldsk and migrate the
* assoc to the newsk. * asoc to the newsk.
*/ */
sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
*sockp = sock;
*newsock = tmpsock;
return err; return err;
} }
...@@ -2011,22 +2202,22 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int * ...@@ -2011,22 +2202,22 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
sctp_peeloff_arg_t peeloff; sctp_peeloff_arg_t peeloff;
struct socket *newsock; struct socket *newsock;
int retval = 0; int retval = 0;
sctp_association_t *assoc; struct sctp_association *asoc;
if (len != sizeof(sctp_peeloff_arg_t)) if (len != sizeof(sctp_peeloff_arg_t))
return -EINVAL; return -EINVAL;
if (copy_from_user(&peeloff, optval, len)) if (copy_from_user(&peeloff, optval, len))
return -EFAULT; return -EFAULT;
assoc = sctp_id2assoc(sk, peeloff.associd); asoc = sctp_id2assoc(sk, peeloff.associd);
if (NULL == assoc) { if (!asoc) {
retval = -EINVAL; retval = -EINVAL;
goto out; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
retval = sctp_do_peeloff(assoc, &newsock); retval = sctp_do_peeloff(asoc, &newsock);
if (retval < 0) if (retval < 0)
goto out; goto out;
...@@ -2037,8 +2228,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int * ...@@ -2037,8 +2228,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
goto out; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
__FUNCTION__, sk, assoc, newsock->sk, retval); __FUNCTION__, sk, asoc, newsock->sk, retval);
/* Return the fd mapped to the new socket. */ /* Return the fd mapped to the new socket. */
peeloff.sd = retval; peeloff.sd = retval;
...@@ -2049,11 +2240,11 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int * ...@@ -2049,11 +2240,11 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
return retval; return retval;
} }
static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
sctp_association_t *asoc; struct sctp_association *asoc;
union sctp_addr *addr; union sctp_addr *addr;
struct sctp_transport *trans; struct sctp_transport *trans;
...@@ -2088,7 +2279,9 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2088,7 +2279,9 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
if (copy_to_user(optval, &params, len)) if (copy_to_user(optval, &params, len))
return -EFAULT; return -EFAULT;
*optlen = len;
if (put_user(len, optlen))
return -EFAULT;
return 0; return 0;
} }
...@@ -2102,11 +2295,11 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int * ...@@ -2102,11 +2295,11 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *
return 0; return 0;
} }
static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_assoc_t id; sctp_assoc_t id;
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
...@@ -2135,7 +2328,7 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, ...@@ -2135,7 +2328,7 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
struct sctp_getaddrs getaddrs; struct sctp_getaddrs getaddrs;
...@@ -2176,8 +2369,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, ...@@ -2176,8 +2369,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_assoc_t id; sctp_assoc_t id;
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
...@@ -2214,8 +2407,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, ...@@ -2214,8 +2407,8 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
static int sctp_getsockopt_local_addrs(struct sock *sk, int len, static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
struct sctp_getaddrs getaddrs; struct sctp_getaddrs getaddrs;
...@@ -2317,7 +2510,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -2317,7 +2510,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
int len, char *optval, int *optlen) int len, char *optval, int *optlen)
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
sctp_association_t *asoc; struct sctp_association *asoc;
if (len != sizeof(struct sctp_sndrcvinfo)) if (len != sizeof(struct sctp_sndrcvinfo))
return -EINVAL; return -EINVAL;
...@@ -2350,15 +2543,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -2350,15 +2543,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
* integer boolean flag. * integer boolean flag.
*/ */
static int sctp_getsockopt_nodelay(struct sock *sk, int len, static int sctp_getsockopt_nodelay(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
__u8 val; int val;
if (len < sizeof(__u8)) if (len < sizeof(int))
return -EINVAL; return -EINVAL;
len = sizeof(__u8); len = sizeof(int);
val = (sctp_sk(sk)->nodelay == 1); val = (sctp_sk(sk)->nodelay == 1);
if (put_user(len, optlen)) if (put_user(len, optlen))
return -EFAULT; return -EFAULT;
...@@ -2366,6 +2559,62 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len, ...@@ -2366,6 +2559,62 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len,
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/*
* 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
*
* This socket option is a boolean flag which turns on or off mapped V4
* addresses. If this option is turned on and the socket is type
* PF_INET6, then IPv4 addresses will be mapped to V6 representation.
* If this option is turned off, then no mapping will be done of V4
* addresses and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket.
*/
static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
char *optval, int *optlen)
{
int val;
if (len < sizeof(int))
return -EINVAL;
len = sizeof(int);
/* FIXME: Until we have support, return disabled. */
val = 0;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
/*
* 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
*
* This socket option specifies the maximum size to put in any outgoing
* SCTP chunk. If a message is larger than this size it will be
* fragmented by SCTP into the specified size. Note that the underlying
* SCTP implementation may fragment into smaller sized chunks when the
* PMTU of the underlying association is smaller than the value set by
* the user.
*/
static int sctp_getsockopt_maxseg(struct sock *sk, int len,
char *optval, int *optlen)
{
int val;
if (len < sizeof(int))
return -EINVAL;
len = sizeof(int);
val = sctp_sk(sk)->user_frag;
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
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)
...@@ -2418,7 +2667,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -2418,7 +2667,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
break; break;
case SCTP_GET_PEER_ADDRS_NUM: case SCTP_GET_PEER_ADDRS_NUM:
retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, retval = sctp_getsockopt_peer_addrs_num(sk, len, optval,
optlen); optlen);
break; break;
case SCTP_GET_LOCAL_ADDRS_NUM: case SCTP_GET_LOCAL_ADDRS_NUM:
...@@ -2443,6 +2692,12 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -2443,6 +2692,12 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_NODELAY: case SCTP_NODELAY:
retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
break; break;
case SCTP_I_WANT_MAPPED_V4_ADDR:
retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
break;
case SCTP_MAXSEG:
retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -2553,7 +2808,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2553,7 +2808,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
} }
if (pp != NULL && pp->sk != NULL) { if (pp && pp->sk) {
/* We had a port hash table hit - there is an /* We had a port hash table hit - there is an
* available port (pp != NULL) and it is being * available port (pp != NULL) and it is being
* used by other socket (pp->sk != NULL); that other * used by other socket (pp->sk != NULL); that other
...@@ -2578,7 +2833,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2578,7 +2833,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* in an endpoint. * in an endpoint.
*/ */
for ( ; sk2 != NULL; sk2 = sk2->bind_next) { for ( ; sk2 != NULL; sk2 = sk2->bind_next) {
sctp_endpoint_t *ep2; struct sctp_endpoint *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
if (sk_reuse && sk2->reuse) if (sk_reuse && sk2->reuse)
...@@ -2601,18 +2856,17 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2601,18 +2856,17 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
/* If there was a hash table miss, create a new port. */ /* If there was a hash table miss, create a new port. */
ret = 1; ret = 1;
if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) if (!pp && !(pp = sctp_bucket_create(head, snum)))
goto fail_unlock; goto fail_unlock;
/* In either case (hit or miss), make sure fastreuse is 1 only /* In either case (hit or miss), make sure fastreuse is 1 only
* if sk->reuse is too (that is, if the caller requested * if sk->reuse is too (that is, if the caller requested
* SO_REUSEADDR on this socket -sk-). * SO_REUSEADDR on this socket -sk-).
*/ */
if (pp->sk == NULL) { if (!pp->sk)
pp->fastreuse = sk->reuse ? 1 : 0; pp->fastreuse = sk->reuse ? 1 : 0;
} else if (pp->fastreuse && sk->reuse == 0) { else if (pp->fastreuse && sk->reuse == 0)
pp->fastreuse = 0; pp->fastreuse = 0;
}
/* We are set, so fill up all the data in the hash table /* We are set, so fill up all the data in the hash table
* entry, tie the socket list information with the rest of the * entry, tie the socket list information with the rest of the
...@@ -2669,15 +2923,15 @@ static int sctp_get_port(struct sock *sk, unsigned short snum) ...@@ -2669,15 +2923,15 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
/* Only UDP style sockets that are not peeled off are allowed to /* Only UDP style sockets that are not peeled off are allowed to
* listen(). * listen().
*/ */
if (SCTP_SOCKET_UDP != sp->type) if (!sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
if (sk->state == SCTP_SS_LISTENING) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
/* /*
...@@ -2702,15 +2956,15 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) ...@@ -2702,15 +2956,15 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
/* /*
* 4.1.3 listen() - TCP Style Syntax * 4.1.3 listen() - TCP Style Syntax
* *
* Applications uses listen() to ready the SCTP endpoint for accepting * Applications uses listen() to ready the SCTP endpoint for accepting
* inbound associations. * inbound associations.
*/ */
SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
if (sk->state == SCTP_SS_LISTENING) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
/* /*
...@@ -2739,15 +2993,25 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) ...@@ -2739,15 +2993,25 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
int sctp_inet_listen(struct socket *sock, int backlog) int sctp_inet_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err; struct crypto_tfm *tfm=NULL;
int err = -EINVAL;
if (unlikely(backlog < 0))
goto out;
sctp_lock_sock(sk); sctp_lock_sock(sk);
err = -EINVAL;
if (sock->state != SS_UNCONNECTED) if (sock->state != SS_UNCONNECTED)
goto out; goto out;
if (unlikely(backlog < 0))
goto out; /* Allocate HMAC for generating cookie. */
if (sctp_hmac_alg) {
tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0);
if (!tfm) {
err = -ENOSYS;
goto out;
}
}
switch (sock->type) { switch (sock->type) {
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
...@@ -2756,14 +3020,21 @@ int sctp_inet_listen(struct socket *sock, int backlog) ...@@ -2756,14 +3020,21 @@ int sctp_inet_listen(struct socket *sock, int backlog)
case SOCK_STREAM: case SOCK_STREAM:
err = sctp_stream_listen(sk, backlog); err = sctp_stream_listen(sk, backlog);
break; break;
default: default:
goto out; break;
}; };
if (err)
goto cleanup;
/* Store away the transform reference. */
sctp_sk(sk)->hmac = tfm;
out: out:
sctp_release_sock(sk); sctp_release_sock(sk);
return err; return err;
cleanup:
if (tfm)
sctp_crypto_free_tfm(tfm);
goto out;
} }
/* /*
...@@ -2782,9 +3053,18 @@ int sctp_inet_listen(struct socket *sock, int backlog) ...@@ -2782,9 +3053,18 @@ int sctp_inet_listen(struct socket *sock, int backlog)
unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sctp_opt *sp = sctp_sk(sk);
unsigned int mask; unsigned int mask;
poll_wait(file, sk->sleep, wait); poll_wait(file, sk->sleep, wait);
/* A TCP-style listening socket becomes readable when the accept queue
* is not empty.
*/
if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
return (!list_empty(&sp->ep->asocs)) ?
(POLLIN | POLLRDNORM) : 0;
mask = 0; mask = 0;
/* Is there any exceptional events? */ /* Is there any exceptional events? */
...@@ -2798,19 +3078,9 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -2798,19 +3078,9 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
(sk->shutdown & RCV_SHUTDOWN)) (sk->shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
/* /* The association is either gone or not ready. */
* FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED))
* peeled off sockets. Additionally, TCP-style needs to consider return mask;
* other establishment conditions.
*/
if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) {
/* The association is going away. */
if (SCTP_SS_DISCONNECTING == sk->state)
mask |= POLLHUP;
/* The association is either gone or not ready. */
if (SCTP_SS_CLOSED == sk->state)
return mask;
}
/* Is it writable? */ /* Is it writable? */
if (sctp_writeable(sk)) { if (sctp_writeable(sk)) {
...@@ -2967,7 +3237,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -2967,7 +3237,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
/* Strictly check lengths following example in SCM code. */ /* Strictly check lengths following example in SCM code. */
switch (cmsg->cmsg_type) { switch (cmsg->cmsg_type) {
case SCTP_INIT: case SCTP_INIT:
/* SCTP Socket API Extension (draft 1) /* SCTP Socket API Extension
* 5.2.1 SCTP Initiation Structure (SCTP_INIT) * 5.2.1 SCTP Initiation Structure (SCTP_INIT)
* *
* This cmsghdr structure provides information for * This cmsghdr structure provides information for
...@@ -2987,7 +3257,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -2987,7 +3257,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
break; break;
case SCTP_SNDRCV: case SCTP_SNDRCV:
/* SCTP Socket API Extension (draft 1) /* SCTP Socket API Extension
* 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV)
* *
* This cmsghdr structure specifies SCTP options for * This cmsghdr structure specifies SCTP options for
...@@ -3002,7 +3272,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -3002,7 +3272,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
return -EINVAL; return -EINVAL;
cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); cmsgs->info =
(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
/* Minimally, validate the sinfo_flags. */ /* Minimally, validate the sinfo_flags. */
if (cmsgs->info->sinfo_flags & if (cmsgs->info->sinfo_flags &
...@@ -3026,10 +3297,9 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -3026,10 +3297,9 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
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)
{ {
int error; int error;
DECLARE_WAITQUEUE(wait, current); DEFINE_WAIT(wait);
__set_current_state(TASK_INTERRUPTIBLE); prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
add_wait_queue_exclusive(sk->sleep, &wait);
/* Socket errors? */ /* Socket errors? */
error = sock_error(sk); error = sock_error(sk);
...@@ -3049,8 +3319,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) ...@@ -3049,8 +3319,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
error = -ENOTCONN; error = -ENOTCONN;
/* Is there a good reason to think that we may receive some data? */ /* Is there a good reason to think that we may receive some data? */
if ((list_empty(&sctp_sk(sk)->ep->asocs)) && if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING))
(sk->state != SCTP_SS_LISTENING))
goto out; goto out;
/* Handle signals. */ /* Handle signals. */
...@@ -3067,16 +3336,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) ...@@ -3067,16 +3336,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
sctp_lock_sock(sk); sctp_lock_sock(sk);
ready: ready:
remove_wait_queue(sk->sleep, &wait); finish_wait(sk->sleep, &wait);
__set_current_state(TASK_RUNNING);
return 0; return 0;
interrupted: interrupted:
error = sock_intr_errno(*timeo_p); error = sock_intr_errno(*timeo_p);
out: out:
remove_wait_queue(sk->sleep, &wait); finish_wait(sk->sleep, &wait);
__set_current_state(TASK_RUNNING);
*err = error; *err = error;
return error; return error;
} }
...@@ -3085,13 +3352,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) ...@@ -3085,13 +3352,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
* Note: This is pretty much the same routine as in core/datagram.c * Note: This is pretty much the same routine as in core/datagram.c
* with a few changes to make lksctp work. * with a few changes to make lksctp work.
*/ */
static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
int noblock, int *err)
{ {
int error; int error;
struct sk_buff *skb; struct sk_buff *skb;
long timeo; long timeo;
/* Caller is allowed not to check sk->err before skb_recv_datagram() */ /* Caller is allowed not to check sk->err before calling. */
error = sock_error(sk); error = sock_error(sk);
if (error) if (error)
goto no_packet; goto no_packet;
...@@ -3126,6 +3394,9 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -3126,6 +3394,9 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
if (skb) if (skb)
return skb; return skb;
if (sk->shutdown & RCV_SHUTDOWN)
break;
/* User doesn't want to wait. */ /* User doesn't want to wait. */
error = -EAGAIN; error = -EAGAIN;
if (!timeo) if (!timeo)
...@@ -3140,7 +3411,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -3140,7 +3411,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
} }
/* Verify that this is a valid address. */ /* Verify that this is a valid address. */
static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
int len) int len)
{ {
struct sctp_af *af; struct sctp_af *af;
...@@ -3161,7 +3432,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, ...@@ -3161,7 +3432,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
} }
/* Get the sndbuf space available at the time on the association. */ /* Get the sndbuf space available at the time on the association. */
static inline int sctp_wspace(sctp_association_t *asoc) static inline int sctp_wspace(struct sctp_association *asoc)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
int amt = 0; int amt = 0;
...@@ -3181,9 +3452,9 @@ static inline int sctp_wspace(sctp_association_t *asoc) ...@@ -3181,9 +3452,9 @@ static inline int sctp_wspace(sctp_association_t *asoc)
* destructor in the data chunk skb for the purpose of the sndbuf space * destructor in the data chunk skb for the purpose of the sndbuf space
* tracking. * tracking.
*/ */
static inline void sctp_set_owner_w(sctp_chunk_t *chunk) static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
{ {
sctp_association_t *asoc = chunk->asoc; struct sctp_association *asoc = chunk->asoc;
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
/* The sndbuf space is tracked per association. */ /* The sndbuf space is tracked per association. */
...@@ -3191,14 +3462,14 @@ static inline void sctp_set_owner_w(sctp_chunk_t *chunk) ...@@ -3191,14 +3462,14 @@ static inline void sctp_set_owner_w(sctp_chunk_t *chunk)
chunk->skb->destructor = sctp_wfree; chunk->skb->destructor = sctp_wfree;
/* Save the chunk pointer in skb for sctp_wfree to use later. */ /* Save the chunk pointer in skb for sctp_wfree to use later. */
*((sctp_chunk_t **)(chunk->skb->cb)) = chunk; *((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk);
} }
/* If sndbuf has changed, wake up per association sndbuf waiters. */ /* If sndbuf has changed, wake up per association sndbuf waiters. */
static void __sctp_write_space(sctp_association_t *asoc) static void __sctp_write_space(struct sctp_association *asoc)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
struct socket *sock = sk->socket; struct socket *sock = sk->socket;
...@@ -3228,12 +3499,12 @@ static void __sctp_write_space(sctp_association_t *asoc) ...@@ -3228,12 +3499,12 @@ static void __sctp_write_space(sctp_association_t *asoc)
*/ */
static void sctp_wfree(struct sk_buff *skb) static void sctp_wfree(struct sk_buff *skb)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sock *sk; struct sock *sk;
/* Get the saved chunk pointer. */ /* Get the saved chunk pointer. */
chunk = *((sctp_chunk_t **)(skb->cb)); chunk = *((struct sctp_chunk **)(skb->cb));
asoc = chunk->asoc; asoc = chunk->asoc;
sk = asoc->base.sk; sk = asoc->base.sk;
asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
...@@ -3244,24 +3515,24 @@ static void sctp_wfree(struct sk_buff *skb) ...@@ -3244,24 +3515,24 @@ static void sctp_wfree(struct sk_buff *skb)
} }
/* Helper function to wait for space in the sndbuf. */ /* Helper function to wait for space in the sndbuf. */
static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
int msg_len) int msg_len)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
int err = 0; int err = 0;
long current_timeo = *timeo_p; long current_timeo = *timeo_p;
DECLARE_WAITQUEUE(wait, current); DEFINE_WAIT(wait);
SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n",
asoc, (long)(*timeo_p), msg_len); asoc, (long)(*timeo_p), msg_len);
/* Wait on the association specific sndbuf space. */
add_wait_queue_exclusive(&asoc->wait, &wait);
/* Increment the association's refcnt. */ /* Increment the association's refcnt. */
sctp_association_hold(asoc); sctp_association_hold(asoc);
/* Wait on the association specific sndbuf space. */
for (;;) { for (;;) {
set_current_state(TASK_INTERRUPTIBLE); prepare_to_wait_exclusive(&asoc->wait, &wait,
TASK_INTERRUPTIBLE);
if (!*timeo_p) if (!*timeo_p)
goto do_nonblock; goto do_nonblock;
if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
...@@ -3283,12 +3554,11 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, ...@@ -3283,12 +3554,11 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
} }
out: out:
remove_wait_queue(&asoc->wait, &wait); finish_wait(&asoc->wait, &wait);
/* Release the association's refcnt. */ /* Release the association's refcnt. */
sctp_association_put(asoc); sctp_association_put(asoc);
__set_current_state(TASK_RUNNING);
return err; return err;
do_error: do_error:
...@@ -3307,12 +3577,12 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, ...@@ -3307,12 +3577,12 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
/* If socket sndbuf has changed, wake up all per association waiters. */ /* If socket sndbuf has changed, wake up all per association waiters. */
void sctp_write_space(struct sock *sk) void sctp_write_space(struct sock *sk)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
/* Wake up the tasks in each wait queue. */ /* Wake up the tasks in each wait queue. */
list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) {
asoc = list_entry(pos, sctp_association_t, asocs); asoc = list_entry(pos, struct sctp_association, asocs);
__sctp_write_space(asoc); __sctp_write_space(asoc);
} }
} }
...@@ -3341,32 +3611,33 @@ static int sctp_writeable(struct sock *sk) ...@@ -3341,32 +3611,33 @@ static int sctp_writeable(struct sock *sk)
/* Wait for an association to go into ESTABLISHED state. If timeout is 0, /* Wait for an association to go into ESTABLISHED state. If timeout is 0,
* returns immediately with EINPROGRESS. * returns immediately with EINPROGRESS.
*/ */
static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p) static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
{ {
struct sock *sk = asoc->base.sk; struct sock *sk = asoc->base.sk;
int err = 0; int err = 0;
long current_timeo = *timeo_p; long current_timeo = *timeo_p;
DECLARE_WAITQUEUE(wait, current); DEFINE_WAIT(wait);
SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
(long)(*timeo_p)); (long)(*timeo_p));
add_wait_queue_exclusive(&asoc->wait, &wait);
/* Increment the association's refcnt. */ /* Increment the association's refcnt. */
sctp_association_hold(asoc); sctp_association_hold(asoc);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); prepare_to_wait_exclusive(&asoc->wait, &wait,
TASK_INTERRUPTIBLE);
if (!*timeo_p) if (!*timeo_p)
goto do_nonblock; goto do_nonblock;
if (sk->shutdown & RCV_SHUTDOWN)
break;
if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
asoc->base.dead) asoc->base.dead)
goto do_error; goto do_error;
if (signal_pending(current)) if (signal_pending(current))
goto do_interrupted; goto do_interrupted;
if (asoc->state == SCTP_STATE_ESTABLISHED) if (sctp_state(asoc, ESTABLISHED))
break; break;
/* Let another process have a go. Since we are going /* Let another process have a go. Since we are going
...@@ -3380,13 +3651,11 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p) ...@@ -3380,13 +3651,11 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
} }
out: out:
remove_wait_queue(&asoc->wait, &wait); finish_wait(&asoc->wait, &wait);
/* Release the association's refcnt. */ /* Release the association's refcnt. */
sctp_association_put(asoc); sctp_association_put(asoc);
__set_current_state(TASK_RUNNING);
return err; return err;
do_error: do_error:
...@@ -3406,14 +3675,14 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) ...@@ -3406,14 +3675,14 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
{ {
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
int err = 0; int err = 0;
DECLARE_WAITQUEUE(wait, current); DEFINE_WAIT(wait);
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
if (list_empty(&ep->asocs)) { if (list_empty(&ep->asocs)) {
sctp_release_sock(sk); sctp_release_sock(sk);
timeo = schedule_timeout(timeo); timeo = schedule_timeout(timeo);
...@@ -3421,7 +3690,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) ...@@ -3421,7 +3690,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
} }
err = -EINVAL; err = -EINVAL;
if (sk->state != SCTP_SS_LISTENING) if (!sctp_sstate(sk, LISTENING))
break; break;
err = 0; err = 0;
...@@ -3437,21 +3706,37 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo) ...@@ -3437,21 +3706,37 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
break; break;
} }
remove_wait_queue(sk->sleep, &wait); finish_wait(sk->sleep, &wait);
__set_current_state(TASK_RUNNING);
return err; return err;
} }
/* Populate the fields of the newsk from the oldsk and migrate the assoc void sctp_wait_for_close(struct sock *sk, long timeout)
{
DEFINE_WAIT(wait);
do {
prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
if (list_empty(&sctp_sk(sk)->ep->asocs))
break;
sctp_release_sock(sk);
timeout = schedule_timeout(timeout);
sctp_lock_sock(sk);
} while (!signal_pending(current) && timeout);
finish_wait(sk->sleep, &wait);
}
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk. * and its messages to the newsk.
*/ */
void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
struct sctp_association *assoc, sctp_socket_type_t type) struct sctp_association *assoc,
sctp_socket_type_t type)
{ {
struct sctp_opt *oldsp = sctp_sk(oldsk); struct sctp_opt *oldsp = sctp_sk(oldsk);
struct sctp_opt *newsp = sctp_sk(newsk); struct sctp_opt *newsp = sctp_sk(newsk);
sctp_endpoint_t *newep = newsp->ep; struct sctp_endpoint *newep = newsp->ep;
struct sk_buff *skb, *tmp; struct sk_buff *skb, *tmp;
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
...@@ -3466,6 +3751,7 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3466,6 +3751,7 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
* copy. * copy.
*/ */
newsp->ep = newep; newsp->ep = newep;
newsp->hmac = NULL;
/* Move any messages in the old socket's receive queue that are for the /* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue. * peeled off association to the new socket's receive queue.
...@@ -3524,9 +3810,15 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3524,9 +3810,15 @@ void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
/* Migrate the association to the new socket. */ /* Migrate the association to the new socket. */
sctp_assoc_migrate(assoc, newsk); sctp_assoc_migrate(assoc, newsk);
/* If the association on the newsk is already closed before accept()
* is called, set RCV_SHUTDOWN flag.
*/
if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
newsk->shutdown |= RCV_SHUTDOWN;
newsk->state = SCTP_SS_ESTABLISHED; newsk->state = SCTP_SS_ESTABLISHED;
} }
/* 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",
......
...@@ -53,11 +53,11 @@ static inline size_t sctp_ssnmap_size(__u16 in, __u16 out) ...@@ -53,11 +53,11 @@ static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
/* Create a new sctp_ssnmap. /* Create a new sctp_ssnmap.
* Allocate room to store at least 'len' contiguous TSNs. * Allocate room to store at least 'len' contiguous TSNs.
*/ */
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority) struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
{ {
struct sctp_ssnmap *retval; struct sctp_ssnmap *retval;
retval = kmalloc(sctp_ssnmap_size(in, out), priority); retval = kmalloc(sctp_ssnmap_size(in, out), gfp);
if (!retval) if (!retval)
goto fail; goto fail;
......
...@@ -54,16 +54,15 @@ ...@@ -54,16 +54,15 @@
/* 1st Level Abstractions. */ /* 1st Level Abstractions. */
/* Allocate and initialize a new transport. */ /* Allocate and initialize a new transport. */
struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
int priority)
{ {
struct sctp_transport *transport; struct sctp_transport *transport;
transport = t_new(struct sctp_transport, priority); transport = t_new(struct sctp_transport, gfp);
if (!transport) if (!transport)
goto fail; goto fail;
if (!sctp_transport_init(transport, addr, priority)) if (!sctp_transport_init(transport, addr, gfp))
goto fail_init; goto fail_init;
transport->malloced = 1; transport->malloced = 1;
...@@ -81,7 +80,7 @@ struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, ...@@ -81,7 +80,7 @@ struct sctp_transport *sctp_transport_new(const union sctp_addr *addr,
/* Initialize a new transport from provided memory. */ /* Initialize a new transport from provided memory. */
struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr, const union sctp_addr *addr,
int priority) int gfp)
{ {
struct sctp_protocol *proto = sctp_get_protocol(); struct sctp_protocol *proto = sctp_get_protocol();
...@@ -117,8 +116,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -117,8 +116,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->error_threshold = 0; peer->error_threshold = 0;
peer->error_count = 0; peer->error_count = 0;
peer->debug_name = "unnamedtransport";
INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->transmitted);
INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->send_ready);
INIT_LIST_HEAD(&peer->transports); INIT_LIST_HEAD(&peer->transports);
...@@ -138,6 +135,13 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -138,6 +135,13 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->dead = 0; peer->dead = 0;
peer->malloced = 0; peer->malloced = 0;
/* Initialize the state information for SFR-CACC */
peer->cacc.changeover_active = 0;
peer->cacc.cycling_changeover = 0;
peer->cacc.next_tsn_at_change = 0;
peer->cacc.cacc_saw_newack = 0;
return peer; return peer;
} }
...@@ -199,13 +203,13 @@ void sctp_transport_reset_timers(struct sctp_transport *transport) ...@@ -199,13 +203,13 @@ void sctp_transport_reset_timers(struct sctp_transport *transport)
* Register the reference count in the association. * Register the reference count in the association.
*/ */
void sctp_transport_set_owner(struct sctp_transport *transport, void sctp_transport_set_owner(struct sctp_transport *transport,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
transport->asoc = asoc; transport->asoc = asoc;
sctp_association_hold(asoc); sctp_association_hold(asoc);
} }
/* Initialize the pmtu of a transport. */ /* Initialize the pmtu of a transport. */
void sctp_transport_pmtu(struct sctp_transport *transport) void sctp_transport_pmtu(struct sctp_transport *transport)
{ {
struct dst_entry *dst; struct dst_entry *dst;
...@@ -225,7 +229,7 @@ void sctp_transport_pmtu(struct sctp_transport *transport) ...@@ -225,7 +229,7 @@ void sctp_transport_pmtu(struct sctp_transport *transport)
void sctp_transport_route(struct sctp_transport *transport, void sctp_transport_route(struct sctp_transport *transport,
union sctp_addr *saddr, struct sctp_opt *opt) union sctp_addr *saddr, struct sctp_opt *opt)
{ {
sctp_association_t *asoc = transport->asoc; struct sctp_association *asoc = transport->asoc;
struct sctp_af *af = transport->af_specific; struct sctp_af *af = transport->af_specific;
union sctp_addr *daddr = &transport->ipaddr; union sctp_addr *daddr = &transport->ipaddr;
struct dst_entry *dst; struct dst_entry *dst;
...@@ -238,9 +242,15 @@ void sctp_transport_route(struct sctp_transport *transport, ...@@ -238,9 +242,15 @@ void sctp_transport_route(struct sctp_transport *transport,
af->get_saddr(asoc, dst, daddr, &transport->saddr); af->get_saddr(asoc, dst, daddr, &transport->saddr);
transport->dst = dst; transport->dst = dst;
if (dst) if (dst) {
transport->pmtu = dst_pmtu(dst); transport->pmtu = dst_pmtu(dst);
else
/* Initialize sk->rcv_saddr, if the transport is the
* association's active path for getsockname().
*/
if (asoc && (transport == asoc->peer.active_path))
af->to_sk_saddr(&transport->saddr, asoc->base.sk);
} else
transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; transport->pmtu = SCTP_DEFAULT_MAXSEGMENT;
} }
...@@ -359,7 +369,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, ...@@ -359,7 +369,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
* two conditions are met can the cwnd be increased otherwise * two conditions are met can the cwnd be increased otherwise
* the cwnd MUST not be increased. If these conditions are met * the cwnd MUST not be increased. If these conditions are met
* then cwnd MUST be increased by at most the lesser of * then cwnd MUST be increased by at most the lesser of
* 1) the total size of the previously outstanding DATA * 1) the total size of the previously outstanding DATA
* chunk(s) acknowledged, and 2) the destination's path MTU. * chunk(s) acknowledged, and 2) the destination's path MTU.
*/ */
if (bytes_acked > pmtu) if (bytes_acked > pmtu)
...@@ -373,17 +383,17 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, ...@@ -373,17 +383,17 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
transport, bytes_acked, cwnd, transport, bytes_acked, cwnd,
ssthresh, flight_size, pba); ssthresh, flight_size, pba);
} else { } else {
/* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh,
* upon each SACK arrival that advances the Cumulative TSN Ack * upon each SACK arrival that advances the Cumulative TSN Ack
* Point, increase partial_bytes_acked by the total number of * Point, increase partial_bytes_acked by the total number of
* bytes of all new chunks acknowledged in that SACK including * bytes of all new chunks acknowledged in that SACK including
* chunks acknowledged by the new Cumulative TSN Ack and by * chunks acknowledged by the new Cumulative TSN Ack and by
* Gap Ack Blocks. * Gap Ack Blocks.
* *
* When partial_bytes_acked is equal to or greater than cwnd * When partial_bytes_acked is equal to or greater than cwnd
* and before the arrival of the SACK the sender had cwnd or * and before the arrival of the SACK the sender had cwnd or
* more bytes of data outstanding (i.e., before arrival of the * more bytes of data outstanding (i.e., before arrival of the
* SACK, flightsize was greater than or equal to cwnd), * SACK, flightsize was greater than or equal to cwnd),
* increase cwnd by MTU, and reset partial_bytes_acked to * increase cwnd by MTU, and reset partial_bytes_acked to
* (partial_bytes_acked - cwnd). * (partial_bytes_acked - cwnd).
*/ */
......
...@@ -55,13 +55,12 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, ...@@ -55,13 +55,12 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
/* Create a new sctp_tsnmap. /* Create a new sctp_tsnmap.
* Allocate room to store at least 'len' contiguous TSNs. * Allocate room to store at least 'len' contiguous TSNs.
*/ */
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
{ {
struct sctp_tsnmap *retval; struct sctp_tsnmap *retval;
retval = kmalloc(sizeof(struct sctp_tsnmap) + retval = kmalloc(sizeof(struct sctp_tsnmap) +
sctp_tsnmap_storage_size(len), sctp_tsnmap_storage_size(len), gfp);
priority);
if (!retval) if (!retval)
goto fail; goto fail;
......
...@@ -52,12 +52,12 @@ static void sctp_ulpevent_set_owner(struct sk_buff *skb, ...@@ -52,12 +52,12 @@ static void sctp_ulpevent_set_owner(struct sk_buff *skb,
const struct sctp_association *asoc); const struct sctp_association *asoc);
/* Create a new sctp_ulpevent. */ /* Create a new sctp_ulpevent. */
struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority) struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sk_buff *skb; struct sk_buff *skb;
skb = alloc_skb(size, priority); skb = alloc_skb(size, gfp);
if (!skb) if (!skb)
goto fail; goto fail;
...@@ -106,16 +106,16 @@ int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event) ...@@ -106,16 +106,16 @@ int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
* zero'd out. * zero'd out.
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
const sctp_association_t *asoc, const struct sctp_association *asoc,
__u16 flags, __u16 state, __u16 error, __u16 outbound, __u16 flags, __u16 state, __u16 error, __u16 outbound,
__u16 inbound, int priority) __u16 inbound, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_assoc_change *sac; struct sctp_assoc_change *sac;
struct sk_buff *skb; struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, gfp);
if (!event) if (!event)
goto fail; goto fail;
skb = sctp_event2skb(event); skb = sctp_event2skb(event);
...@@ -207,15 +207,16 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( ...@@ -207,15 +207,16 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
* an interface details event is sent. * an interface details event is sent.
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const sctp_association_t *asoc, const struct sockaddr_storage *aaddr, const struct sctp_association *asoc,
int flags, int state, int error, int priority) const struct sockaddr_storage *aaddr,
int flags, int state, int error, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_paddr_change *spc; struct sctp_paddr_change *spc;
struct sk_buff *skb; struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, gfp);
if (!event) if (!event)
goto fail; goto fail;
...@@ -315,8 +316,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( ...@@ -315,8 +316,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
* error formats. * error formats.
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_remote_error( struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const sctp_association_t *asoc, sctp_chunk_t *chunk, const struct sctp_association *asoc, struct sctp_chunk *chunk,
__u16 flags, int priority) __u16 flags, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_remote_error *sre; struct sctp_remote_error *sre;
...@@ -327,7 +328,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( ...@@ -327,7 +328,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
ch = (sctp_errhdr_t *)(chunk->skb->data); ch = (sctp_errhdr_t *)(chunk->skb->data);
cause = ch->cause; cause = ch->cause;
elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);
/* Pull off the ERROR header. */ /* Pull off the ERROR header. */
skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); skb_pull(chunk->skb, sizeof(sctp_errhdr_t));
...@@ -335,10 +336,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( ...@@ -335,10 +336,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
/* Copy the skb to a new skb with room for us to prepend /* Copy the skb to a new skb with room for us to prepend
* notification with. * notification with.
*/ */
skb = skb_copy_expand(chunk->skb, skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),
sizeof(struct sctp_remote_error), /* headroom */ 0, gfp);
0, /* tailroom */
priority);
/* Pull off the rest of the cause TLV from the chunk. */ /* Pull off the rest of the cause TLV from the chunk. */
skb_pull(chunk->skb, elen); skb_pull(chunk->skb, elen);
...@@ -419,23 +418,27 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( ...@@ -419,23 +418,27 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_send_failed( struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
const sctp_association_t *asoc, sctp_chunk_t *chunk, const struct sctp_association *asoc, struct sctp_chunk *chunk,
__u16 flags, __u32 error, int priority) __u16 flags, __u32 error, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_send_failed *ssf; struct sctp_send_failed *ssf;
struct sk_buff *skb; struct sk_buff *skb;
/* Pull off any padding. */
int len = ntohs(chunk->chunk_hdr->length);
/* Make skb with more room so we can prepend notification. */ /* Make skb with more room so we can prepend notification. */
skb = skb_copy_expand(chunk->skb, skb = skb_copy_expand(chunk->skb,
sizeof(struct sctp_send_failed), /* headroom */ sizeof(struct sctp_send_failed), /* headroom */
0, /* tailroom */ 0, /* tailroom */
priority); gfp);
if (!skb) if (!skb)
goto fail; goto fail;
/* Pull off the common chunk header and DATA header. */ /* Pull off the common chunk header and DATA header. */
skb_pull(skb, sizeof(sctp_data_chunk_t)); skb_pull(skb, sizeof(struct sctp_data_chunk));
len -= sizeof(struct sctp_data_chunk);
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb); event = sctp_skb2event(skb);
...@@ -476,7 +479,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -476,7 +479,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
* This field is the total length of the notification data, including * This field is the total length of the notification data, including
* the notification header. * the notification header.
*/ */
ssf->ssf_length = skb->len; ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
skb_trim(skb, ssf->ssf_length);
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
...@@ -497,6 +501,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -497,6 +501,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
*/ */
memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
/* Per TSVWG discussion with Randy. Allow the application to
* ressemble a fragmented message.
*/
ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
* *
...@@ -521,15 +530,15 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -521,15 +530,15 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const sctp_association_t *asoc, const struct sctp_association *asoc,
__u16 flags, int priority) __u16 flags, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_shutdown_event *sse; struct sctp_shutdown_event *sse;
struct sk_buff *skb; struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, gfp);
if (!event) if (!event)
goto fail; goto fail;
...@@ -586,8 +595,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( ...@@ -586,8 +595,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
* Socket Extensions for SCTP * Socket Extensions for SCTP
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
sctp_chunk_t *chunk, int priority) struct sctp_chunk *chunk,
int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *info;
...@@ -595,7 +605,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -595,7 +605,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
size_t padding, len; size_t padding, len;
/* Clone the original skb, sharing the data. */ /* Clone the original skb, sharing the data. */
skb = skb_clone(chunk->skb, priority); skb = skb_clone(chunk->skb, gfp);
if (!skb) if (!skb)
goto fail; goto fail;
...@@ -631,7 +641,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -631,7 +641,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
event->iif = sctp_chunk_iif(chunk); event->iif = sctp_chunk_iif(chunk);
/* Note: Not clearing the entire event struct as /* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However, * this is just a fragment of the real event. However,
* we still need to do rwnd accounting. * we still need to do rwnd accounting.
*/ */
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
sctp_ulpevent_set_owner_r(list, asoc); sctp_ulpevent_set_owner_r(list, asoc);
...@@ -690,16 +700,16 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -690,16 +700,16 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
info->sinfo_flags |= MSG_UNORDERED; info->sinfo_flags |= MSG_UNORDERED;
/* sinfo_cumtsn: 32 bit (unsigned integer) /* sinfo_cumtsn: 32 bit (unsigned integer)
* *
* This field will hold the current cumulative TSN as * This field will hold the current cumulative TSN as
* known by the underlying SCTP layer. Note this field is * known by the underlying SCTP layer. Note this field is
* ignored when sending and only valid for a receive * ignored when sending and only valid for a receive
* operation when sinfo_flags are set to MSG_UNORDERED. * operation when sinfo_flags are set to MSG_UNORDERED.
*/ */
info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
} }
/* Note: For reassembly, we need to have the fragmentation bits. /* Note: For reassembly, we need to have the fragmentation bits.
* For now, merge these into the msg_flags, since those bit * For now, merge these into the msg_flags, since those bit
* possitions are not used. * possitions are not used.
*/ */
...@@ -732,7 +742,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -732,7 +742,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
return NULL; return NULL;
} }
/* Create a partial delivery related event. /* Create a partial delivery related event.
* *
* 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
* *
...@@ -741,14 +751,14 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -741,14 +751,14 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
* various events. * various events.
*/ */
struct sctp_ulpevent *sctp_ulpevent_make_pdapi( struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const sctp_association_t *asoc, __u32 indication, int priority) const struct sctp_association *asoc, __u32 indication, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_rcv_pdapi_event *pd; struct sctp_rcv_pdapi_event *pd;
struct sk_buff *skb; struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, gfp);
if (!event) if (!event)
goto fail; goto fail;
...@@ -780,7 +790,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( ...@@ -780,7 +790,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
pd->pdapi_indication = indication; pd->pdapi_indication = indication;
/* pdapi_assoc_id: sizeof (sctp_assoc_t) /* pdapi_assoc_id: sizeof (sctp_assoc_t)
* *
* The association id field, holds the identifier for the association. * The association id field, holds the identifier for the association.
*/ */
pd->pdapi_assoc_id = sctp_assoc2id(asoc); pd->pdapi_assoc_id = sctp_assoc2id(asoc);
...@@ -817,7 +827,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, ...@@ -817,7 +827,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
/* Do accounting for bytes just read by user. */ /* Do accounting for bytes just read by user. */
static void sctp_rcvmsg_rfree(struct sk_buff *skb) static void sctp_rcvmsg_rfree(struct sk_buff *skb)
{ {
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
/* Current stack structures assume that the rcv buffer is /* Current stack structures assume that the rcv buffer is
...@@ -834,7 +844,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -834,7 +844,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
/* Charge receive window for bytes received. */ /* Charge receive window for bytes received. */
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
......
...@@ -57,11 +57,11 @@ static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *, ...@@ -57,11 +57,11 @@ static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *,
/* 1st Level Abstractions */ /* 1st Level Abstractions */
/* Create a new ULP queue. */ /* Create a new ULP queue. */
struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority) struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp)
{ {
struct sctp_ulpq *ulpq; struct sctp_ulpq *ulpq;
ulpq = kmalloc(sizeof(struct sctp_ulpq), priority); ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp);
if (!ulpq) if (!ulpq)
goto fail; goto fail;
if (!sctp_ulpq_init(ulpq, asoc)) if (!sctp_ulpq_init(ulpq, asoc))
...@@ -77,7 +77,7 @@ struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority) ...@@ -77,7 +77,7 @@ struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority)
/* Initialize a ULP queue from a block of memory. */ /* Initialize a ULP queue from a block of memory. */
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
sctp_association_t *asoc) struct sctp_association *asoc)
{ {
memset(ulpq, sizeof(struct sctp_ulpq), 0x00); memset(ulpq, sizeof(struct sctp_ulpq), 0x00);
...@@ -118,8 +118,8 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq) ...@@ -118,8 +118,8 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
} }
/* Process an incoming DATA chunk. */ /* Process an incoming DATA chunk. */
int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
int priority) int gfp)
{ {
struct sk_buff_head temp; struct sk_buff_head temp;
sctp_data_chunk_t *hdr; sctp_data_chunk_t *hdr;
...@@ -128,7 +128,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, ...@@ -128,7 +128,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; hdr = (sctp_data_chunk_t *) chunk->chunk_hdr;
/* Create an event from the incoming chunk. */ /* Create an event from the incoming chunk. */
event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp);
if (!event) if (!event)
return -ENOMEM; return -ENOMEM;
...@@ -253,6 +253,21 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, ...@@ -253,6 +253,21 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
tsn = event->sndrcvinfo.sinfo_tsn; tsn = event->sndrcvinfo.sinfo_tsn;
/* See if it belongs at the end. */
pos = skb_peek_tail(&ulpq->reasm);
if (!pos) {
__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
return;
}
/* Short circuit just dropping it at the end. */
cevent = sctp_skb2event(pos);
ctsn = cevent->sndrcvinfo.sinfo_tsn;
if (TSN_lt(ctsn, tsn)) {
__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
return;
}
/* Find the right place in this list. We store them by TSN. */ /* Find the right place in this list. We store them by TSN. */
skb_queue_walk(&ulpq->reasm, pos) { skb_queue_walk(&ulpq->reasm, pos) {
cevent = sctp_skb2event(pos); cevent = sctp_skb2event(pos);
...@@ -262,12 +277,9 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, ...@@ -262,12 +277,9 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
break; break;
} }
/* If the queue is empty, we have a different function to call. */ /* Insert before pos. */
if (skb_peek(&ulpq->reasm)) __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->reasm);
__skb_insert(sctp_event2skb(event), pos->prev, pos,
&ulpq->reasm);
else
__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
} }
/* Helper function to return an event corresponding to the reassembled /* Helper function to return an event corresponding to the reassembled
...@@ -592,8 +604,27 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, ...@@ -592,8 +604,27 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
__u16 sid, csid; __u16 sid, csid;
__u16 ssn, cssn; __u16 ssn, cssn;
pos = skb_peek_tail(&ulpq->lobby);
if (!pos) {
__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
return;
}
sid = event->sndrcvinfo.sinfo_stream; sid = event->sndrcvinfo.sinfo_stream;
ssn = event->sndrcvinfo.sinfo_ssn; ssn = event->sndrcvinfo.sinfo_ssn;
cevent = (struct sctp_ulpevent *) pos->cb;
csid = cevent->sndrcvinfo.sinfo_stream;
cssn = cevent->sndrcvinfo.sinfo_ssn;
if (sid > csid) {
__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
return;
}
if ((sid == csid) && SSN_lt(cssn, ssn)) {
__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
return;
}
/* Find the right place in this list. We store them by /* Find the right place in this list. We store them by
* stream ID and then by SSN. * stream ID and then by SSN.
...@@ -609,12 +640,10 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, ...@@ -609,12 +640,10 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
break; break;
} }
/* If the queue is empty, we have a different function to call. */
if (skb_peek(&ulpq->lobby)) /* Insert before pos. */
__skb_insert(sctp_event2skb(event), pos->prev, pos, __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->lobby);
&ulpq->lobby);
else
__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
} }
static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
...@@ -705,7 +734,7 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) ...@@ -705,7 +734,7 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed)
/* Partial deliver the first message as there is pressure on rwnd. */ /* Partial deliver the first message as there is pressure on rwnd. */
void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
struct sctp_chunk *chunk, int priority) struct sctp_chunk *chunk, int gfp)
{ {
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -729,7 +758,7 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, ...@@ -729,7 +758,7 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
/* Renege some packets to make room for an incoming chunk. */ /* Renege some packets to make room for an incoming chunk. */
void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
int priority) int gfp)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
__u16 needed, freed; __u16 needed, freed;
...@@ -755,9 +784,9 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, ...@@ -755,9 +784,9 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
__u32 tsn; __u32 tsn;
tsn = ntohl(chunk->subh.data_hdr->tsn); tsn = ntohl(chunk->subh.data_hdr->tsn);
sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn); sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
sctp_ulpq_tail_data(ulpq, chunk, priority); sctp_ulpq_tail_data(ulpq, chunk, gfp);
sctp_ulpq_partial_delivery(ulpq, chunk, priority); sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
} }
return; return;
...@@ -768,7 +797,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, ...@@ -768,7 +797,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
/* Notify the application if an association is aborted and in /* Notify the application if an association is aborted and in
* partial delivery mode. Send up any pending received messages. * partial delivery mode. Send up any pending received messages.
*/ */
void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority) void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int gfp)
{ {
struct sctp_ulpevent *ev = NULL; struct sctp_ulpevent *ev = NULL;
struct sock *sk; struct sock *sk;
...@@ -781,7 +810,7 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority) ...@@ -781,7 +810,7 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
&sctp_sk(sk)->subscribe)) &sctp_sk(sk)->subscribe))
ev = sctp_ulpevent_make_pdapi(ulpq->asoc, ev = sctp_ulpevent_make_pdapi(ulpq->asoc,
SCTP_PARTIAL_DELIVERY_ABORTED, SCTP_PARTIAL_DELIVERY_ABORTED,
priority); gfp);
if (ev) if (ev)
__skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev)); __skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
......
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