Commit efcf40ab 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/net-2.5
parents 702ab28f 87611822
...@@ -267,7 +267,8 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 }; ...@@ -267,7 +267,8 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
* nearest power of 2. * nearest power of 2.
*/ */
enum { SCTP_MIN_PMTU = 576 }; enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 128 }; enum { SCTP_MAX_DUP_TSNS = 16 };
enum { SCTP_MAX_GABS = 16 };
typedef enum { typedef enum {
SCTP_COUNTER_INIT_ERROR, SCTP_COUNTER_INIT_ERROR,
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@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.
...@@ -311,6 +312,11 @@ void sctp_sysctl_unregister(void); ...@@ -311,6 +312,11 @@ 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; }
static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen, void **context) {
return -ENOSYS;
}
#endif #endif
/* Size of Supported Address Parameter for 'x' address types. */ /* Size of Supported Address Parameter for 'x' address types. */
......
/* SCTP reference Implementation
* Copyright (C) 1999 Cisco, Inc.
* Copyright (C) 1999 Motorola, Inc.
*
* This file originates from Randy Stewart's SCTP reference Implementation.
*
* 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:
* Randy Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
*/
#ifndef __SLA1_h__
#define __SLA1_h__
struct SLA_1_Context {
unsigned int A;
unsigned int B;
unsigned int C;
unsigned int D;
unsigned int E;
unsigned int H0;
unsigned int H1;
unsigned int H2;
unsigned int H3;
unsigned int H4;
unsigned int words[80];
unsigned int TEMP;
/* block I am collecting to process */
char SLAblock[64];
/* collected so far */
int howManyInBlock;
unsigned int runningTotal;
};
#define F1(B,C,D) (((B & C) | ((~B) & D))) /* 0 <= t <= 19 */
#define F2(B,C,D) (B ^ C ^ D) /* 20 <= t <= 39 */
#define F3(B,C,D) ((B & C) | (B & D) | (C & D)) /* 40 <= t <= 59 */
#define F4(B,C,D) (B ^ C ^ D) /*600 <= t <= 79 */
/* circular shift */
#define CSHIFT(A,B) ((B << A) | (B >> (32-A)))
#define K1 0x5a827999 /* 0 <= t <= 19 */
#define K2 0x6ed9eba1 /* 20 <= t <= 39 */
#define K3 0x8f1bbcdc /* 40 <= t <= 59 */
#define K4 0xca62c1d6 /* 60 <= t <= 79 */
#define H0INIT 0x67452301
#define H1INIT 0xefcdab89
#define H2INIT 0x98badcfe
#define H3INIT 0x10325476
#define H4INIT 0xc3d2e1f0
extern void SLA1_Init(struct SLA_1_Context *);
extern void SLA1_Process(struct SLA_1_Context *, const unsigned char *, int);
extern void SLA1_Final(struct SLA_1_Context *, unsigned char *);
#endif
...@@ -84,7 +84,7 @@ typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *, ...@@ -84,7 +84,7 @@ typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *,
typedef void (sctp_timer_event_t) (unsigned long); typedef void (sctp_timer_event_t) (unsigned long);
typedef struct { typedef struct {
sctp_state_fn_t *fn; sctp_state_fn_t *fn;
char *name; const char *name;
} sctp_sm_table_entry_t; } sctp_sm_table_entry_t;
/* A naming convention of "sctp_sf_xxx" applies to all the state functions /* A naming convention of "sctp_sf_xxx" applies to all the state functions
...@@ -176,9 +176,6 @@ sctp_state_fn_t sctp_sf_do_9_2_reshutack; ...@@ -176,9 +176,6 @@ sctp_state_fn_t sctp_sf_do_9_2_reshutack;
sctp_state_fn_t sctp_sf_do_9_2_reshut; sctp_state_fn_t sctp_sf_do_9_2_reshut;
sctp_state_fn_t sctp_sf_do_9_2_shutack; sctp_state_fn_t sctp_sf_do_9_2_shutack;
sctp_state_fn_t lucky;
sctp_state_fn_t other_stupid;
/* Prototypes for timeout event state functions. Not in use. */ /* Prototypes for timeout event state functions. Not in use. */
sctp_state_fn_t sctp_do_4_2_reinit; sctp_state_fn_t sctp_do_4_2_reinit;
sctp_state_fn_t sctp_do_4_3_reecho; sctp_state_fn_t sctp_do_4_3_reecho;
...@@ -193,9 +190,9 @@ sctp_state_fn_t sctp_addip_do_asconf_ack; ...@@ -193,9 +190,9 @@ sctp_state_fn_t sctp_addip_do_asconf_ack;
/* Prototypes for utility support functions. */ /* Prototypes for utility support functions. */
__u8 sctp_get_chunk_type(struct sctp_chunk *chunk); __u8 sctp_get_chunk_type(struct sctp_chunk *chunk);
sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t,
sctp_state_t state, sctp_state_t,
sctp_subtype_t event_subtype); sctp_subtype_t);
int sctp_chunk_iif(const struct sctp_chunk *); int sctp_chunk_iif(const struct sctp_chunk *);
struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *, struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *,
struct sctp_chunk *, struct sctp_chunk *,
...@@ -284,20 +281,13 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -284,20 +281,13 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
int gfp); int gfp);
/* 2nd level prototypes */ /* 2nd level prototypes */
int int sctp_cmd_interpreter(sctp_event_t, sctp_subtype_t, sctp_state_t,
sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, struct sctp_endpoint *, struct sctp_association *,
sctp_state_t state, void *event_arg, sctp_disposition_t,
struct sctp_endpoint *ep, sctp_cmd_seq_t *retval, int gfp);
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *retval,
int gfp);
int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *); int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
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);
...@@ -311,7 +301,7 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *, ...@@ -311,7 +301,7 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *,
const struct sctp_chunk *); const struct sctp_chunk *);
void sctp_ootb_pkt_free(struct sctp_packet *); void sctp_ootb_pkt_free(struct sctp_packet *);
sctp_cookie_param_t * struct sctp_cookie_param *
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);
...@@ -332,18 +322,18 @@ __u32 sctp_generate_tag(const struct sctp_endpoint *); ...@@ -332,18 +322,18 @@ __u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const struct sctp_endpoint *); __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, union sctp_addr_param *,
__u16 port, int iif); __u16 port, int iif);
int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *); int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *);
int sockaddr2sctp_addr(const union sctp_addr *, sctp_addr_param_t *); int sockaddr2sctp_addr(const union sctp_addr *, union sctp_addr_param *);
/* Extern declarations for major data structures. */ /* Extern declarations for major data structures. */
sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
extern sctp_sm_table_entry_t extern const sctp_sm_table_entry_t
primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES]; primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
extern sctp_sm_table_entry_t extern const sctp_sm_table_entry_t
other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES]; other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
extern sctp_sm_table_entry_t extern const sctp_sm_table_entry_t
timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES]; timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES];
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu>
* *
* 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.
...@@ -97,7 +99,7 @@ struct sctp_bind_bucket { ...@@ -97,7 +99,7 @@ struct sctp_bind_bucket {
unsigned short fastreuse; unsigned short fastreuse;
struct sctp_bind_bucket *next; struct sctp_bind_bucket *next;
struct sctp_bind_bucket **pprev; struct sctp_bind_bucket **pprev;
struct hlist_head sk_list; struct hlist_head owner;
}; };
struct sctp_bind_hashbucket { struct sctp_bind_hashbucket {
...@@ -183,7 +185,7 @@ extern struct sctp_globals { ...@@ -183,7 +185,7 @@ extern struct sctp_globals {
* We actively maintain this complete list of interfaces on * We actively maintain this complete list of interfaces on
* the system by catching routing events. * the system by catching routing events.
* *
* It is a list of struct sockaddr_storage_list. * It is a list of sctp_sockaddr_entry.
*/ */
struct list_head local_addr_list; struct list_head local_addr_list;
spinlock_t local_addr_lock; spinlock_t local_addr_lock;
...@@ -325,6 +327,7 @@ struct sctp_opt { ...@@ -325,6 +327,7 @@ 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;
struct sctp_assocparams assocparams;
int user_frag; int user_frag;
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
...@@ -347,7 +350,7 @@ struct sctp_opt { ...@@ -347,7 +350,7 @@ struct sctp_opt {
* *
*/ */
typedef struct sctp_cookie { struct sctp_cookie {
/* My : Tag expected in every inbound packet and sent /* My : Tag expected in every inbound packet and sent
* Verification: in the INIT or INIT ACK chunk. * Verification: in the INIT or INIT ACK chunk.
...@@ -393,38 +396,38 @@ typedef struct sctp_cookie { ...@@ -393,38 +396,38 @@ typedef struct sctp_cookie {
* the association TCB is re-constructed from the cookie. * the association TCB is re-constructed from the cookie.
*/ */
__u32 raw_addr_list_len; __u32 raw_addr_list_len;
sctp_init_chunk_t peer_init[0]; struct sctp_init_chunk peer_init[0];
} sctp_cookie_t; };
/* The format of our cookie that we send to our peer. */ /* The format of our cookie that we send to our peer. */
typedef struct sctp_signed_cookie { struct sctp_signed_cookie {
__u8 signature[SCTP_SECRET_SIZE]; __u8 signature[SCTP_SECRET_SIZE];
sctp_cookie_t c; struct sctp_cookie c;
} sctp_signed_cookie_t; };
/* This is another convenience type to allocate memory for address /* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around * params for the maximum size and pass such structures around
* internally. * internally.
*/ */
typedef union { union sctp_addr_param {
sctp_ipv4addr_param_t v4; struct sctp_ipv4addr_param v4;
sctp_ipv6addr_param_t v6; struct sctp_ipv6addr_param v6;
} sctp_addr_param_t; };
/* A convenience type to allow walking through the various /* A convenience type to allow walking through the various
* parameters and avoid casting all over the place. * parameters and avoid casting all over the place.
*/ */
union sctp_params { union sctp_params {
void *v; void *v;
sctp_paramhdr_t *p; struct sctp_paramhdr *p;
sctp_cookie_preserve_param_t *life; struct sctp_cookie_preserve_param *life;
sctp_hostname_param_t *dns; struct sctp_hostname_param *dns;
sctp_cookie_param_t *cookie; struct sctp_cookie_param *cookie;
sctp_supported_addrs_param_t *sat; struct sctp_supported_addrs_param *sat;
sctp_ipv4addr_param_t *v4; struct sctp_ipv4addr_param *v4;
sctp_ipv6addr_param_t *v6; struct sctp_ipv6addr_param *v6;
sctp_addr_param_t *addr; union sctp_addr_param *addr;
}; };
/* RFC 2960. Section 3.3.5 Heartbeat. /* RFC 2960. Section 3.3.5 Heartbeat.
...@@ -435,7 +438,7 @@ union sctp_params { ...@@ -435,7 +438,7 @@ union sctp_params {
* HEARTBEAT is sent (see Section 8.3). * HEARTBEAT is sent (see Section 8.3).
*/ */
typedef struct sctp_sender_hb_info { typedef struct sctp_sender_hb_info {
sctp_paramhdr_t param_hdr; struct sctp_paramhdr param_hdr;
union sctp_addr daddr; union sctp_addr daddr;
unsigned long sent_at; unsigned long sent_at;
} sctp_sender_hb_info_t __attribute__((packed)); } sctp_sender_hb_info_t __attribute__((packed));
...@@ -555,23 +558,22 @@ struct sctp_chunk { ...@@ -555,23 +558,22 @@ struct sctp_chunk {
union sctp_params param_hdr; union sctp_params param_hdr;
union { union {
__u8 *v; __u8 *v;
sctp_datahdr_t *data_hdr; struct sctp_datahdr *data_hdr;
sctp_inithdr_t *init_hdr; struct sctp_inithdr *init_hdr;
sctp_sackhdr_t *sack_hdr; struct sctp_sackhdr *sack_hdr;
sctp_heartbeathdr_t *hb_hdr; struct sctp_heartbeathdr *hb_hdr;
sctp_sender_hb_info_t *hbs_hdr; struct sctp_sender_hb_info *hbs_hdr;
sctp_shutdownhdr_t *shutdown_hdr; struct sctp_shutdownhdr *shutdown_hdr;
sctp_signed_cookie_t *cookie_hdr; struct sctp_signed_cookie *cookie_hdr;
sctp_ecnehdr_t *ecne_hdr; struct sctp_ecnehdr *ecne_hdr;
sctp_cwrhdr_t *ecn_cwr_hdr; struct sctp_cwrhdr *ecn_cwr_hdr;
sctp_errhdr_t *err_hdr; struct sctp_errhdr *err_hdr;
} subh; } subh;
__u8 *chunk_end; __u8 *chunk_end;
sctp_chunkhdr_t *chunk_hdr; struct sctp_chunkhdr *chunk_hdr;
struct sctphdr *sctp_hdr;
sctp_sctphdr_t *sctp_hdr;
/* This needs to be recoverable for SCTP_SEND_FAILED events. */ /* This needs to be recoverable for SCTP_SEND_FAILED events. */
struct sctp_sndrcvinfo sinfo; struct sctp_sndrcvinfo sinfo;
...@@ -632,7 +634,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); ...@@ -632,7 +634,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
* sin_port -- ordinary port number * sin_port -- ordinary port number
* sin_addr -- cast to either (struct in_addr) or (struct in6_addr) * sin_addr -- cast to either (struct in_addr) or (struct in6_addr)
*/ */
struct sockaddr_storage_list { struct sctp_sockaddr_entry {
struct list_head list; struct list_head list;
union sctp_addr a; union sctp_addr a;
}; };
...@@ -1020,7 +1022,7 @@ void sctp_outq_teardown(struct sctp_outq *); ...@@ -1020,7 +1022,7 @@ 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 *, struct sctp_chunk *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 *, struct sctp_sackhdr *);
int sctp_outq_is_empty(const struct sctp_outq *); int sctp_outq_is_empty(const struct sctp_outq *);
int sctp_outq_set_output_handlers(struct sctp_outq *, int sctp_outq_set_output_handlers(struct sctp_outq *,
sctp_outq_ohandler_init_t init, sctp_outq_ohandler_init_t init,
...@@ -1271,7 +1273,7 @@ struct sctp_association { ...@@ -1271,7 +1273,7 @@ struct sctp_association {
struct sctp_endpoint *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; struct sctp_cookie c;
/* This is all information about our peer. */ /* This is all information about our peer. */
struct { struct {
...@@ -1376,7 +1378,7 @@ struct sctp_association { ...@@ -1376,7 +1378,7 @@ struct sctp_association {
__u8 ipv4_address; /* Peer understands IPv4 addresses? */ __u8 ipv4_address; /* Peer understands IPv4 addresses? */
__u8 ipv6_address; /* Peer understands IPv6 addresses? */ __u8 ipv6_address; /* Peer understands IPv6 addresses? */
__u8 hostname_address;/* Peer understands DNS addresses? */ __u8 hostname_address;/* Peer understands DNS addresses? */
sctp_inithdr_t i; struct sctp_inithdr i;
int cookie_len; int cookie_len;
void *cookie; void *cookie;
...@@ -1400,9 +1402,6 @@ struct sctp_association { ...@@ -1400,9 +1402,6 @@ struct sctp_association {
*/ */
sctp_state_t state; sctp_state_t state;
/* When did we enter this state? */
int state_timestamp;
/* The cookie life I award for any cookie. */ /* The cookie life I award for any cookie. */
struct timeval cookie_life; struct timeval cookie_life;
...@@ -1411,12 +1410,6 @@ struct sctp_association { ...@@ -1411,12 +1410,6 @@ struct sctp_association {
*/ */
int overall_error_count; int overall_error_count;
/* Overall : The threshold for this association that if
* Error : the Overall Error Count reaches will cause
* Threshold : this association to be torn down.
*/
int overall_error_threshold;
/* These are the association's initial, max, and min RTO values. /* These are the association's initial, max, and min RTO values.
* These values will be initialized by system defaults, but can * These values will be initialized by system defaults, but can
* be modified via the SCTP_RTOINFO socket option. * be modified via the SCTP_RTOINFO socket option.
...@@ -1710,13 +1703,13 @@ __u32 sctp_association_get_next_tsn(struct sctp_association *); ...@@ -1710,13 +1703,13 @@ __u32 sctp_association_get_next_tsn(struct sctp_association *);
__u32 sctp_association_get_tsn_block(struct sctp_association *, int); __u32 sctp_association_get_tsn_block(struct sctp_association *, int);
void sctp_assoc_sync_pmtu(struct sctp_association *); void sctp_assoc_sync_pmtu(struct sctp_association *);
void sctp_assoc_rwnd_increase(struct sctp_association *, int); void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned);
void sctp_assoc_rwnd_decrease(struct sctp_association *, int); void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned);
void sctp_assoc_set_primary(struct sctp_association *, void sctp_assoc_set_primary(struct sctp_association *,
struct sctp_transport *); struct sctp_transport *);
int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, int); int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, int);
int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
sctp_cookie_t *, int gfp); struct sctp_cookie*, int gfp);
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 kernel reference Implementation Copyright (C) 1999-2001 /* SCTP kernel reference Implementation
* Cisco, Motorola, Intel, and International Business Machines Corp. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -97,13 +100,16 @@ struct sctp_tsnmap { ...@@ -97,13 +100,16 @@ struct sctp_tsnmap {
/* Data chunks pending receipt. used by SCTP_STATUS sockopt */ /* Data chunks pending receipt. used by SCTP_STATUS sockopt */
__u16 pending_data; __u16 pending_data;
/* We record duplicate TSNs here. We clear this after /* Record duplicate TSNs here. We clear this after
* every SACK. Store up to SCTP_MAX_DUP_TSNS worth of * every SACK. Store up to SCTP_MAX_DUP_TSNS worth of
* information. * information.
*/ */
__u32 dup_tsns[SCTP_MAX_DUP_TSNS]; __u32 dup_tsns[SCTP_MAX_DUP_TSNS];
__u16 num_dup_tsns; __u16 num_dup_tsns;
/* Record gap ack block information here. */
struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
int malloced; int malloced;
__u8 raw_map[0]; __u8 raw_map[0];
...@@ -140,12 +146,18 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn); ...@@ -140,12 +146,18 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn); void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
/* Retrieve the Cumulative TSN ACK Point. */ /* Retrieve the Cumulative TSN ACK Point. */
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *); static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
{
return map->cumulative_tsn_ack_point;
}
/* Retrieve the highest TSN we've seen. */ /* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *); static inline __u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
{
return map->max_tsn_seen;
}
/* How many Duplicate TSNs are stored? */ /* How many duplicate TSNs are stored? */
static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map) static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map)
{ {
return map->num_dup_tsns; return map->num_dup_tsns;
...@@ -158,6 +170,27 @@ static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map) ...@@ -158,6 +170,27 @@ static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map)
return map->dup_tsns; return map->dup_tsns;
} }
/* How many gap ack blocks do we have recorded? */
__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map);
/* Refresh the count on pending data. */
__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map);
/* Return pointer to gap ack blocks as needed by SACK. */
static inline struct sctp_gap_ack_block *sctp_tsnmap_get_gabs(struct sctp_tsnmap *map)
{
return map->gabs;
}
/* Is there a gap in the TSN map? */
static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
int has_gap;
has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen);
return has_gap;
}
/* Mark a duplicate TSN. Note: limit the storage of duplicate TSN /* Mark a duplicate TSN. Note: limit the storage of duplicate TSN
* information. * information.
*/ */
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ryan Layer <rmlayer@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
...@@ -517,11 +518,14 @@ struct sctp_rtoinfo { ...@@ -517,11 +518,14 @@ struct sctp_rtoinfo {
*/ */
struct sctp_assocparams { struct sctp_assocparams {
__u16 sasoc_asocmaxrxt;
sctp_assoc_t sasoc_assoc_id; sctp_assoc_t sasoc_assoc_id;
__u16 sasoc_asocmaxrxt;
__u16 sasoc_number_peer_destinations;
__u32 sasoc_peer_rwnd;
__u32 sasoc_local_rwnd;
__u32 sasoc_cookie_life;
}; };
/* /*
* 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR)
* *
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ryan Layer <rmlayer@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.
...@@ -125,23 +126,24 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -125,23 +126,24 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->base.addr_lock = RW_LOCK_UNLOCKED; asoc->base.addr_lock = RW_LOCK_UNLOCKED;
asoc->state = SCTP_STATE_CLOSED; asoc->state = SCTP_STATE_CLOSED;
asoc->state_timestamp = jiffies;
/* Set things that have constant value. */
asoc->cookie_life.tv_sec = sctp_valid_cookie_life / HZ;
asoc->cookie_life.tv_usec = (sctp_valid_cookie_life % HZ) *
1000000L / HZ;
/* Set these values from the socket values, a conversion between
* millsecons to seconds/microseconds must also be done.
*/
asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000;
asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000)
* 1000;
asoc->pmtu = 0; asoc->pmtu = 0;
asoc->frag_point = 0; asoc->frag_point = 0;
/* Initialize the default association max_retrans and RTO values. */ /* Set the association max_retrans and RTO values from the
asoc->max_retrans = sctp_max_retrans_association; * socket values.
asoc->rto_initial = sctp_rto_initial; */
asoc->rto_max = sctp_rto_max; asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
asoc->rto_min = sctp_rto_min; asoc->rto_initial = sp->rtoinfo.srto_initial * HZ / 1000;
asoc->rto_max = sp->rtoinfo.srto_max * HZ / 1000;
asoc->rto_min = sp->rtoinfo.srto_min * HZ / 1000;
asoc->overall_error_threshold = asoc->max_retrans;
asoc->overall_error_count = 0; asoc->overall_error_count = 0;
/* Initialize the maximum mumber of new data packets that can be sent /* Initialize the maximum mumber of new data packets that can be sent
...@@ -164,7 +166,8 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -164,7 +166,8 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams;
asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams;
asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; asoc->max_init_attempts = sp->initmsg.sinit_max_attempts;
asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ;
asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ / 1000;
/* Allocate storage for the ssnmap after the inbound and outbound /* Allocate storage for the ssnmap after the inbound and outbound
* streams have been negotiated during Init. * streams have been negotiated during Init.
...@@ -491,9 +494,14 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -491,9 +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.
*/ */
peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ;
/* Set the path max_retrans. */
peer->max_retrans = asoc->max_retrans;
/* Set the transport's RTO.initial value */
peer->rto = asoc->rto_initial;
/* 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);
...@@ -793,6 +801,26 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc, ...@@ -793,6 +801,26 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
return transport; return transport;
} }
/* Is this a live association structure. */
int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc)
{
/* First, verify that this is a kernel address. */
if (!sctp_is_valid_kaddr((unsigned long) asoc))
return 0;
/* Verify that this _is_ an sctp_association
* data structure and if so, that the socket matches.
*/
if (SCTP_ASSOC_EYECATCHER != asoc->eyecatcher)
return 0;
if (asoc->base.sk != sk)
return 0;
/* The association is valid. */
return 1;
}
/* 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(struct sctp_association *asoc) static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
{ {
...@@ -801,7 +829,6 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc) ...@@ -801,7 +829,6 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
struct sock *sk; struct sock *sk;
struct sctp_inq *inqueue; struct sctp_inq *inqueue;
int state, subtype; int state, subtype;
sctp_assoc_t associd = sctp_assoc2id(asoc);
int error = 0; int error = 0;
/* The association should be held so we should be safe. */ /* The association should be held so we should be safe. */
...@@ -831,7 +858,7 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc) ...@@ -831,7 +858,7 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
/* Check to see if the association is freed in response to /* Check to see if the association is freed in response to
* the incoming chunk. If so, get out of the while loop. * the incoming chunk. If so, get out of the while loop.
*/ */
if (!sctp_id2assoc(sk, associd)) if (!sctp_assoc_valid(sk, asoc))
break; break;
/* If there is an error on chunk, discard this packet. */ /* If there is an error on chunk, discard this packet. */
...@@ -1033,7 +1060,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) ...@@ -1033,7 +1060,7 @@ 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(struct sctp_association *asoc, int len) void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
{ {
struct sctp_chunk *sack; struct sctp_chunk *sack;
struct timer_list *timer; struct timer_list *timer;
...@@ -1079,7 +1106,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len) ...@@ -1079,7 +1106,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len)
} }
/* Decrease asoc's rwnd by len. */ /* Decrease asoc's rwnd by len. */
void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len) void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned 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);
...@@ -1119,11 +1146,11 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp) ...@@ -1119,11 +1146,11 @@ 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(struct sctp_association *asoc, int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
sctp_cookie_t *cookie, int gfp) struct sctp_cookie *cookie, int gfp)
{ {
int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);
int var_size3 = cookie->raw_addr_list_len; int var_size3 = cookie->raw_addr_list_len;
__u8 *raw = (__u8 *)cookie + sizeof(sctp_cookie_t) + var_size2; __u8 *raw = (__u8 *)cookie + sizeof(struct sctp_cookie) + var_size2;
return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3, return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,
asoc->ep->base.bind_addr.port, gfp); asoc->ep->base.bind_addr.port, gfp);
......
...@@ -65,7 +65,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, ...@@ -65,7 +65,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src, 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 sctp_sockaddr_entry *addr;
struct list_head *pos; struct list_head *pos;
int error = 0; int error = 0;
...@@ -74,7 +74,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, ...@@ -74,7 +74,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
/* Extract the addresses which are relevant for this scope. */ /* Extract the addresses which are relevant for this scope. */
list_for_each(pos, &src->address_list) { list_for_each(pos, &src->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
error = sctp_copy_one_addr(dest, &addr->a, scope, error = sctp_copy_one_addr(dest, &addr->a, scope,
gfp, flags); gfp, flags);
if (error < 0) if (error < 0)
...@@ -87,7 +87,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, ...@@ -87,7 +87,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
*/ */
if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
list_for_each(pos, &src->address_list) { list_for_each(pos, &src->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, addr = list_entry(pos, struct sctp_sockaddr_entry,
list); list);
error = sctp_copy_one_addr(dest, &addr->a, error = sctp_copy_one_addr(dest, &addr->a,
SCTP_SCOPE_LINK, gfp, SCTP_SCOPE_LINK, gfp,
...@@ -135,12 +135,12 @@ void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) ...@@ -135,12 +135,12 @@ void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
/* Dispose of the address list. */ /* Dispose of the address list. */
static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
{ {
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
/* Empty the bind address list. */ /* Empty the bind address list. */
list_for_each_safe(pos, temp, &bp->address_list) { list_for_each_safe(pos, temp, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
list_del(pos); list_del(pos);
kfree(addr); kfree(addr);
SCTP_DBG_OBJCNT_DEC(addr); SCTP_DBG_OBJCNT_DEC(addr);
...@@ -163,14 +163,14 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp) ...@@ -163,14 +163,14 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp)
int sctp_add_bind_addr(struct sctp_bind_addr *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 sctp_sockaddr_entry *addr;
/* Add the address to the bind address list. */ /* Add the address to the bind address list. */
addr = t_new(struct sockaddr_storage_list, gfp); addr = t_new(struct sctp_sockaddr_entry, gfp);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
addr->a = *new; memcpy(&addr->a, new, sizeof(*new));
/* Fix up the port if it has not yet been set. /* Fix up the port if it has not yet been set.
* Both v4 and v6 have the port at the same offset. * Both v4 and v6 have the port at the same offset.
...@@ -191,10 +191,10 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, ...@@ -191,10 +191,10 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
int sctp_del_bind_addr(struct sctp_bind_addr *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 sctp_sockaddr_entry *addr;
list_for_each_safe(pos, temp, &bp->address_list) { list_for_each_safe(pos, temp, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_cmp_addr_exact(&addr->a, del_addr)) { if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
/* Found the exact match. */ /* Found the exact match. */
list_del(pos); list_del(pos);
...@@ -219,22 +219,22 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, ...@@ -219,22 +219,22 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
union sctp_params addrparms; union sctp_params addrparms;
union sctp_params retval; union sctp_params retval;
int addrparms_len; int addrparms_len;
sctp_addr_param_t rawaddr; union sctp_addr_param rawaddr;
int len; int len;
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
struct list_head *pos; struct list_head *pos;
addrparms_len = 0; addrparms_len = 0;
len = 0; len = 0;
/* Allocate enough memory at once. */ /* Allocate enough memory at once. */
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
len += sizeof(sctp_addr_param_t); len += sizeof(union sctp_addr_param);
} }
/* Don't even bother embedding an address if there /* Don't even bother embedding an address if there
* is only one. * is only one.
*/ */
if (len == sizeof(sctp_addr_param_t)) { if (len == sizeof(union sctp_addr_param)) {
retval.v = NULL; retval.v = NULL;
goto end_raw; goto end_raw;
} }
...@@ -246,7 +246,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, ...@@ -246,7 +246,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
addrparms = retval; addrparms = retval;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
len = sockaddr2sctp_addr(&addr->a, &rawaddr); len = sockaddr2sctp_addr(&addr->a, &rawaddr);
memcpy(addrparms.v, &rawaddr, len); memcpy(addrparms.v, &rawaddr, len);
addrparms.v += len; addrparms.v += len;
...@@ -265,16 +265,16 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, ...@@ -265,16 +265,16 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int sctp_raw_to_bind_addrs(struct sctp_bind_addr *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; union sctp_addr_param *rawaddr;
sctp_paramhdr_t *param; struct sctp_paramhdr *param;
union sctp_addr addr; union sctp_addr addr;
int retval = 0; int retval = 0;
int len; int len;
/* Convert the raw address to standard address format */ /* Convert the raw address to standard address format */
while (addrs_len) { while (addrs_len) {
param = (sctp_paramhdr_t *)raw_addr_list; param = (struct sctp_paramhdr *)raw_addr_list;
rawaddr = (sctp_addr_param_t *)raw_addr_list; rawaddr = (union sctp_addr_param *)raw_addr_list;
switch (param->type) { switch (param->type) {
case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV4_ADDRESS:
...@@ -312,11 +312,11 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp, ...@@ -312,11 +312,11 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
const union sctp_addr *addr, const union sctp_addr *addr,
struct sctp_opt *opt) struct sctp_opt *opt)
{ {
struct sockaddr_storage_list *laddr; struct sctp_sockaddr_entry *laddr;
struct list_head *pos; struct list_head *pos;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (opt->pf->cmp_addr(&laddr->a, addr, opt)) if (opt->pf->cmp_addr(&laddr->a, addr, opt))
return 1; return 1;
} }
......
...@@ -129,7 +129,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -129,7 +129,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
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 * HZ / 1000;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
/* sctpimpguide-05 Section 2.12.2 /* sctpimpguide-05 Section 2.12.2
...@@ -137,7 +137,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ...@@ -137,7 +137,7 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
* recommended value of 5 times 'RTO.Max'. * recommended value of 5 times 'RTO.Max'.
*/ */
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 * HZ / 1000);
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
SCTP_DEFAULT_TIMEOUT_HEARTBEAT; SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
...@@ -313,13 +313,13 @@ int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, ...@@ -313,13 +313,13 @@ 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 sctp_sockaddr_entry *addr;
struct sctp_bind_addr *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;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_has_association(&addr->a, paddr)) { if (sctp_has_association(&addr->a, paddr)) {
sctp_read_unlock(&ep->base.addr_lock); sctp_read_unlock(&ep->base.addr_lock);
return 1; return 1;
......
/* SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola
*
* This file origiantes from Randy Stewart's SCTP reference Implementation.
*
* 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:
* Randy Stewart rstewar1@email.mot.com
* Ken Morneau kmorneau@cisco.com
* Qiaobing Xie qxie1@email.mot.com
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorperated 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 :)"
*/
#include <linux/types.h>
#include <asm/string.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sla1.h>
/* SCTP Main driver.
* passing a two pointers and two lengths,
* returning a digest pointer filled. The md5 code
* was taken directly from the RFC (2104) so to understand it
* you may want to go look at the RFC referenced in the
* SCTP spec. We did modify this code to either user OUR
* implementation of SLA1 or the MD5 that comes from its
* RFC. SLA1 may have IPR issues so you need to check in
* to this if you wish to use it... Or at least that is
* what the FIP-180.1 web page says.
*/
void sctp_hash_digest(const char *key, const int in_key_len,
const char *text, const int text_len,
__u8 *digest)
{
int key_len = in_key_len;
struct SLA_1_Context context;
__u8 k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
__u8 k_opad[65]; /* outer padding -
* key XORd with opad
*/
__u8 tk[20];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
struct SLA_1_Context tctx;
SLA1_Init(&tctx);
SLA1_Process(&tctx, key, key_len);
SLA1_Final(&tctx,tk);
key = tk;
key_len = 20;
}
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof k_ipad);
memset(k_opad, 0, sizeof k_opad);
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < 64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner hash */
SLA1_Init(&context); /* init context for 1st
* pass
*/
SLA1_Process(&context, k_ipad, 64); /* start with inner pad */
SLA1_Process(&context, text, text_len); /* then text of datagram */
SLA1_Final(&context,digest); /* finish up 1st pass */
/*
* perform outer hash
*/
SLA1_Init(&context); /* init context for 2nd
* pass
*/
SLA1_Process(&context, k_opad, 64); /* start with outer pad */
SLA1_Process(&context, digest, 20); /* then results of 1st
* hash
*/
SLA1_Final(&context, digest); /* finish up 2nd pass */
}
...@@ -248,7 +248,7 @@ void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, ...@@ -248,7 +248,7 @@ void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
{ {
struct sctp_bind_addr *bp; struct sctp_bind_addr *bp;
rwlock_t *addr_lock; rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr; struct sctp_sockaddr_entry *laddr;
struct list_head *pos; struct list_head *pos;
sctp_scope_t scope; sctp_scope_t scope;
union sctp_addr *baddr = NULL; union sctp_addr *baddr = NULL;
...@@ -277,7 +277,7 @@ void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, ...@@ -277,7 +277,7 @@ void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
*/ */
sctp_read_lock(addr_lock); sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
if ((laddr->a.sa.sa_family == AF_INET6) && if ((laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) { (scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
...@@ -309,7 +309,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, ...@@ -309,7 +309,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
{ {
struct inet6_dev *in6_dev; struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
read_lock(&addrconf_lock); read_lock(&addrconf_lock);
if ((in6_dev = __in6_dev_get(dev)) == NULL) { if ((in6_dev = __in6_dev_get(dev)) == NULL) {
...@@ -320,7 +320,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, ...@@ -320,7 +320,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
read_lock(&in6_dev->lock); read_lock(&in6_dev->lock);
for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
if (addr) { if (addr) {
addr->a.v6.sin6_family = AF_INET6; addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0; addr->a.v6.sin6_port = 0;
......
...@@ -1012,7 +1012,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1012,7 +1012,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
__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; unsigned outstanding;
struct sctp_transport *primary = asoc->peer.primary_path; struct sctp_transport *primary = asoc->peer.primary_path;
int count_of_newacks = 0; int count_of_newacks = 0;
......
...@@ -133,12 +133,12 @@ void sctp_snmp_proc_exit(void) ...@@ -133,12 +133,12 @@ void sctp_snmp_proc_exit(void)
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
{ {
struct list_head *pos; struct list_head *pos;
struct sockaddr_storage_list *laddr; struct sctp_sockaddr_entry *laddr;
union sctp_addr *addr; union sctp_addr *addr;
struct sctp_af *af; struct sctp_af *af;
list_for_each(pos, &epb->bind_addr.address_list) { list_for_each(pos, &epb->bind_addr.address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
addr = (union sctp_addr *)&laddr->a; addr = (union sctp_addr *)&laddr->a;
af = sctp_get_af_specific(addr->sa.sa_family); af = sctp_get_af_specific(addr->sa.sa_family);
af->seq_dump_addr(seq, addr); af->seq_dump_addr(seq, addr);
......
...@@ -143,7 +143,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -143,7 +143,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
{ {
struct in_device *in_dev; struct in_device *in_dev;
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
read_lock(&inetdev_lock); read_lock(&inetdev_lock);
if ((in_dev = __in_dev_get(dev)) == NULL) { if ((in_dev = __in_dev_get(dev)) == NULL) {
...@@ -154,7 +154,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -154,7 +154,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
read_lock(&in_dev->lock); read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
if (addr) { if (addr) {
addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0; addr->a.v4.sin_port = 0;
...@@ -198,11 +198,11 @@ static void sctp_get_local_addr_list(void) ...@@ -198,11 +198,11 @@ static void sctp_get_local_addr_list(void)
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void __sctp_free_local_addr_list(void) static void __sctp_free_local_addr_list(void)
{ {
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
list_for_each_safe(pos, temp, &sctp_local_addr_list) { list_for_each_safe(pos, temp, &sctp_local_addr_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
list_del(pos); list_del(pos);
kfree(addr); kfree(addr);
} }
...@@ -222,14 +222,14 @@ static void sctp_free_local_addr_list(void) ...@@ -222,14 +222,14 @@ static void sctp_free_local_addr_list(void)
int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
int gfp, int copy_flags) int gfp, int copy_flags)
{ {
struct sockaddr_storage_list *addr; struct sctp_sockaddr_entry *addr;
int error = 0; int error = 0;
struct list_head *pos; struct list_head *pos;
unsigned long flags; unsigned long flags;
sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
list_for_each(pos, &sctp_local_addr_list) { list_for_each(pos, &sctp_local_addr_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_in_scope(&addr->a, scope)) { if (sctp_in_scope(&addr->a, scope)) {
/* Now that the address is in scope, check to see if /* Now that the address is in scope, check to see if
* the address type is really supported by the local * the address type is really supported by the local
...@@ -412,7 +412,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, ...@@ -412,7 +412,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
struct flowi fl; struct flowi fl;
struct sctp_bind_addr *bp; struct sctp_bind_addr *bp;
rwlock_t *addr_lock; rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr; struct sctp_sockaddr_entry *laddr;
struct list_head *pos; struct list_head *pos;
struct dst_entry *dst = NULL; struct dst_entry *dst = NULL;
union sctp_addr dst_saddr; union sctp_addr dst_saddr;
...@@ -447,7 +447,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, ...@@ -447,7 +447,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
*/ */
sctp_read_lock(addr_lock); sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, laddr = list_entry(pos, struct sctp_sockaddr_entry,
list); list);
sctp_v4_dst_saddr(&dst_saddr, dst, bp->port); sctp_v4_dst_saddr(&dst_saddr, dst, bp->port);
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
...@@ -467,7 +467,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, ...@@ -467,7 +467,7 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
*/ */
sctp_read_lock(addr_lock); sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (AF_INET == laddr->a.sa.sa_family) { if (AF_INET == laddr->a.sa.sa_family) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr; fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
*
* This file is part of the SCTP kernel reference Implementation
*
* (It's really SHA-1 but Hey I was tired when I created this
* file, and on a plane to France :-)
*
* 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:
* Randall Stewart <rstewar1@email.mot.com>
* kmorneau@cisco.com
* qxie1@email.mot.com
*
* Based on:
* Randy Stewart, et al. SCTP Reference Implementation which is licenced
* under the GPL.
*
* 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/fcntl.h>
#include <asm/string.h> /* for memcpy */
#include <linux/sched.h> /* dead chicken for in.h */
#include <linux/in.h> /* for htonl and ntohl */
#include <net/sctp/sla1.h>
void SLA1_Init(struct SLA_1_Context *ctx)
{
/* Init the SLA-1 context structure. */
ctx->A = 0;
ctx->B = 0;
ctx->C = 0;
ctx->D = 0;
ctx->E = 0;
ctx->H0 = H0INIT;
ctx->H1 = H1INIT;
ctx->H2 = H2INIT;
ctx->H3 = H3INIT;
ctx->H4 = H4INIT;
ctx->TEMP = 0;
memset(ctx->words, 0, sizeof(ctx->words));
ctx->howManyInBlock = 0;
ctx->runningTotal = 0;
}
void SLA1processABlock(struct SLA_1_Context *ctx,unsigned int *block)
{
int i;
/* init the W0-W15 to the block of words being
* hashed.
*/
/* step a) */
for (i = 0; i < 16; i++)
ctx->words[i] = ntohl(block[i]);
/* now init the rest based on the SLA-1 formula, step b) */
for (i = 16; i < 80; i++)
ctx->words[i] =
CSHIFT(1, ((ctx->words[(i-3)]) ^
(ctx->words[(i-8)]) ^
(ctx->words[(i-14)]) ^
(ctx->words[(i-16)])));
/* step c) */
ctx->A = ctx->H0;
ctx->B = ctx->H1;
ctx->C = ctx->H2;
ctx->D = ctx->H3;
ctx->E = ctx->H4;
/* step d) */
for (i = 0; i < 80; i++) {
if (i < 20) {
ctx->TEMP = ((CSHIFT(5, ctx->A)) +
(F1(ctx->B, ctx->C, ctx->D)) +
(ctx->E) +
ctx->words[i] +
K1
);
} else if (i < 40) {
ctx->TEMP = ((CSHIFT(5, ctx->A)) +
(F2(ctx->B, ctx->C, ctx->D)) +
(ctx->E) +
(ctx->words[i]) +
K2
);
} else if (i < 60) {
ctx->TEMP = ((CSHIFT(5, ctx->A)) +
(F3(ctx->B, ctx->C, ctx->D)) +
(ctx->E) +
(ctx->words[i]) +
K3
);
} else {
ctx->TEMP = ((CSHIFT(5, ctx->A)) +
(F4(ctx->B, ctx->C, ctx->D)) +
(ctx->E) +
(ctx->words[i]) +
K4
);
}
ctx->E = ctx->D;
ctx->D = ctx->C;
ctx->C = CSHIFT(30, ctx->B);
ctx->B = ctx->A;
ctx->A = ctx->TEMP;
}
/* step e) */
ctx->H0 = (ctx->H0) + (ctx->A);
ctx->H1 = (ctx->H1) + (ctx->B);
ctx->H2 = (ctx->H2) + (ctx->C);
ctx->H3 = (ctx->H3) + (ctx->D);
ctx->H4 = (ctx->H4) + (ctx->E);
}
void SLA1_Process(struct SLA_1_Context *ctx, const unsigned char *ptr, int siz)
{
int numberLeft, leftToFill;
numberLeft = siz;
while (numberLeft > 0) {
leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock;
if (leftToFill > numberLeft) {
/* can only partially fill up this one */
memcpy(&ctx->SLAblock[ctx->howManyInBlock],
ptr, numberLeft);
ctx->howManyInBlock += siz;
ctx->runningTotal += siz;
break;
} else {
/* block is now full, process it */
memcpy(&ctx->SLAblock[ctx->howManyInBlock],
ptr, leftToFill);
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
numberLeft -= leftToFill;
ctx->runningTotal += leftToFill;
ctx->howManyInBlock = 0;
}
}
}
void SLA1_Final(struct SLA_1_Context *ctx, unsigned char *digestBuf)
{
/* if any left in block fill with padding
* and process. Then transfer the digest to
* the pointer. At the last block some special
* rules need to apply. We must add a 1 bit
* following the message, then we pad with
* 0's. The total size is encoded as a 64 bit
* number at the end. Now if the last buffer has
* more than 55 octets in it we cannot fit
* the 64 bit number + 10000000 pad on the end
* and must add the 10000000 pad, pad the rest
* of the message with 0's and then create a
* all 0 message with just the 64 bit size
* at the end and run this block through by itself.
* Also the 64 bit int must be in network byte
* order.
*/
int i, leftToFill;
unsigned int *ptr;
if (ctx->howManyInBlock > 55) {
/* special case, we need to process two
* blocks here. One for the current stuff
* plus possibly the pad. The other for
* the size.
*/
leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock;
if (leftToFill == 0) {
/* Should not really happen but I am paranoid */
/* Not paranoid enough! It is possible for leftToFill
* to become negative! AAA!!!! This is another reason
* to pick MD5 :-)...
*/
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
/* init last block, a bit different then the rest :-) */
ctx->SLAblock[0] = 0x80;
for (i = 1; i < sizeof(ctx->SLAblock); i++) {
ctx->SLAblock[i] = 0x0;
}
} else if (leftToFill == 1) {
ctx->SLAblock[ctx->howManyInBlock] = 0x80;
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
/* init last block */
memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock));
} else {
ctx->SLAblock[ctx->howManyInBlock] = 0x80;
for (i = (ctx->howManyInBlock + 1);
i < sizeof(ctx->SLAblock);
i++) {
ctx->SLAblock[i] = 0x0;
}
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
/* init last block */
memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock));
}
/* This is in bits so multiply by 8 */
ctx->runningTotal *= 8;
ptr = (unsigned int *) &ctx->SLAblock[60];
*ptr = htonl(ctx->runningTotal);
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
} else {
/* easy case, we just pad this
* message to size - end with 0
* add the magic 0x80 to the next
* word and then put the network byte
* order size in the last spot and
* process the block.
*/
ctx->SLAblock[ctx->howManyInBlock] = 0x80;
for (i = (ctx->howManyInBlock + 1);
i < sizeof(ctx->SLAblock);
i++) {
ctx->SLAblock[i] = 0x0;
}
/* get last int spot */
ctx->runningTotal *= 8;
ptr = (unsigned int *) &ctx->SLAblock[60];
*ptr = htonl(ctx->runningTotal);
SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock);
}
/* Now at this point all we need do is transfer the
* digest back to the user
*/
digestBuf[3] = (ctx->H0 & 0xff);
digestBuf[2] = ((ctx->H0 >> 8) & 0xff);
digestBuf[1] = ((ctx->H0 >> 16) & 0xff);
digestBuf[0] = ((ctx->H0 >> 24) & 0xff);
digestBuf[7] = (ctx->H1 & 0xff);
digestBuf[6] = ((ctx->H1 >> 8) & 0xff);
digestBuf[5] = ((ctx->H1 >> 16) & 0xff);
digestBuf[4] = ((ctx->H1 >> 24) & 0xff);
digestBuf[11] = (ctx->H2 & 0xff);
digestBuf[10] = ((ctx->H2 >> 8) & 0xff);
digestBuf[9] = ((ctx->H2 >> 16) & 0xff);
digestBuf[8] = ((ctx->H2 >> 24) & 0xff);
digestBuf[15] = (ctx->H3 & 0xff);
digestBuf[14] = ((ctx->H3 >> 8) & 0xff);
digestBuf[13] = ((ctx->H3 >> 16) & 0xff);
digestBuf[12] = ((ctx->H3 >> 24) & 0xff);
digestBuf[19] = (ctx->H4 & 0xff);
digestBuf[18] = ((ctx->H4 >> 8) & 0xff);
digestBuf[17] = ((ctx->H4 >> 16) & 0xff);
digestBuf[16] = ((ctx->H4 >> 24) & 0xff);
}
...@@ -589,27 +589,17 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, ...@@ -589,27 +589,17 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
sctp_sackhdr_t sack; struct sctp_sackhdr sack;
sctp_gap_ack_block_t gab; int len;
int length;
__u32 ctsn; __u32 ctsn;
struct sctp_tsnmap_iter iter;
__u16 num_gabs, num_dup_tsns; __u16 num_gabs, num_dup_tsns;
struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
ctsn = sctp_tsnmap_get_ctsn(map); ctsn = sctp_tsnmap_get_ctsn(map);
SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); SCTP_DEBUG_PRINTK("sackCTSNAck sent: 0x%x.\n", ctsn);
/* Count the number of Gap Ack Blocks. */
num_gabs = 0;
if (sctp_tsnmap_has_gap(map)) {
sctp_tsnmap_iter_init(map, &iter);
while (sctp_tsnmap_next_gap_ack(map, &iter,
&gab.start, &gab.end))
num_gabs++;
}
/* How much room is needed in the chunk? */
num_gabs = sctp_tsnmap_num_gabs(map);
num_dup_tsns = sctp_tsnmap_num_dups(map); num_dup_tsns = sctp_tsnmap_num_dups(map);
/* Initialize the SACK header. */ /* Initialize the SACK header. */
...@@ -618,12 +608,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) ...@@ -618,12 +608,12 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
sack.num_gap_ack_blocks = htons(num_gabs); sack.num_gap_ack_blocks = htons(num_gabs);
sack.num_dup_tsns = htons(num_dup_tsns); sack.num_dup_tsns = htons(num_dup_tsns);
length = sizeof(sack) len = sizeof(sack)
+ sizeof(sctp_gap_ack_block_t) * num_gabs + sizeof(struct sctp_gap_ack_block) * num_gabs
+ sizeof(__u32) * num_dup_tsns; + sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */ /* Create the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -662,19 +652,13 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) ...@@ -662,19 +652,13 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
retval->subh.sack_hdr = retval->subh.sack_hdr =
sctp_addto_chunk(retval, sizeof(sack), &sack); sctp_addto_chunk(retval, sizeof(sack), &sack);
/* Put the Gap Ack Blocks into the chunk. */ /* Add the gap ack block information. */
if (num_gabs) { if (num_gabs)
sctp_tsnmap_iter_init(map, &iter); sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
while(sctp_tsnmap_next_gap_ack(map, &iter, sctp_tsnmap_get_gabs(map));
&gab.start, &gab.end)) {
gab.start = htons(gab.start);
gab.end = htons(gab.end);
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t),
&gab);
}
}
/* Register the duplicates. */ /* Add the duplicate TSN information. */
if (num_dup_tsns)
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map)); sctp_tsnmap_get_dups(map));
...@@ -1275,14 +1259,14 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, ...@@ -1275,14 +1259,14 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
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; struct sctp_signed_cookie *cookie;
struct scatterlist sg; struct scatterlist sg;
int headersize, bodysize; int headersize, bodysize;
unsigned int keylen; unsigned int keylen;
char *key; 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(struct sctp_cookie)
+ ntohs(init_chunk->chunk_hdr->length) + addrs_len; + ntohs(init_chunk->chunk_hdr->length) + addrs_len;
/* Pad out the cookie to a multiple to make the signature /* Pad out the cookie to a multiple to make the signature
...@@ -1304,7 +1288,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, ...@@ -1304,7 +1288,7 @@ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
* out on the network. * out on the network.
*/ */
memset(retval, 0x00, *cookie_len); memset(retval, 0x00, *cookie_len);
cookie = (sctp_signed_cookie_t *) retval->body; cookie = (struct sctp_signed_cookie *) retval->body;
/* Set up the parameter header. */ /* Set up the parameter header. */
retval->p.type = SCTP_PARAM_STATE_COOKIE; retval->p.type = SCTP_PARAM_STATE_COOKIE;
...@@ -1351,26 +1335,26 @@ struct sctp_association *sctp_unpack_cookie( ...@@ -1351,26 +1335,26 @@ struct sctp_association *sctp_unpack_cookie(
int *error, struct sctp_chunk **errp) int *error, struct sctp_chunk **errp)
{ {
struct sctp_association *retval = NULL; struct sctp_association *retval = NULL;
sctp_signed_cookie_t *cookie; struct sctp_signed_cookie *cookie;
sctp_cookie_t *bear_cookie; struct sctp_cookie *bear_cookie;
int headersize, bodysize, fixed_size; int headersize, bodysize, fixed_size;
__u8 digest[SCTP_SIGNATURE_SIZE]; __u8 digest[SCTP_SIGNATURE_SIZE];
struct scatterlist sg; struct scatterlist sg;
unsigned int keylen; unsigned int keylen, len;
char *key; char *key;
sctp_scope_t scope; sctp_scope_t scope;
struct sk_buff *skb = chunk->skb; struct sk_buff *skb = chunk->skb;
headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE;
bodysize = ntohs(chunk->chunk_hdr->length) - headersize; bodysize = ntohs(chunk->chunk_hdr->length) - headersize;
fixed_size = headersize + sizeof(sctp_cookie_t); fixed_size = headersize + sizeof(struct sctp_cookie);
/* Verify that the chunk looks like it even has a cookie. /* Verify that the chunk looks like it even has a cookie.
* There must be enough room for our cookie and our peer's * There must be enough room for our cookie and our peer's
* INIT chunk. * INIT chunk.
*/ */
if (ntohs(chunk->chunk_hdr->length) < len = ntohs(chunk->chunk_hdr->length);
(fixed_size + sizeof(sctp_chunkhdr_t))) if (len < fixed_size + sizeof(struct sctp_chunkhdr))
goto malformed; goto malformed;
/* Verify that the cookie has been padded out. */ /* Verify that the cookie has been padded out. */
...@@ -1454,7 +1438,7 @@ struct sctp_association *sctp_unpack_cookie( ...@@ -1454,7 +1438,7 @@ struct sctp_association *sctp_unpack_cookie(
retval->peer.port = ntohs(chunk->sctp_hdr->source); retval->peer.port = ntohs(chunk->sctp_hdr->source);
/* Populate the association from the cookie. */ /* Populate the association from the cookie. */
retval->c = *bear_cookie; memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie, if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie,
GFP_ATOMIC) < 0) { GFP_ATOMIC) < 0) {
...@@ -2022,7 +2006,7 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep) ...@@ -2022,7 +2006,7 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
********************************************************************/ ********************************************************************/
/* Convert from an SCTP IP parameter to a union sctp_addr. */ /* Convert from an SCTP IP parameter to a union sctp_addr. */
void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param, void sctp_param2sockaddr(union sctp_addr *addr, union sctp_addr_param *param,
__u16 port, int iif) __u16 port, int iif)
{ {
switch(param->v4.param_hdr.type) { switch(param->v4.param_hdr.type) {
...@@ -2073,7 +2057,7 @@ int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa) ...@@ -2073,7 +2057,7 @@ int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa)
/* Convert a sockaddr_in to an IP address in an SCTP param. /* Convert a sockaddr_in to an IP address in an SCTP param.
* Returns len if a valid conversion was possible. * Returns len if a valid conversion was possible.
*/ */
int sockaddr2sctp_addr(const union sctp_addr *sa, sctp_addr_param_t *p) int sockaddr2sctp_addr(const union sctp_addr *sa, union sctp_addr_param *p)
{ {
int len = 0; int len = 0;
......
...@@ -608,13 +608,13 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, ...@@ -608,13 +608,13 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
} }
/* 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, struct sctp_association *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;
asoc->state = state; asoc->state = state;
asoc->state_timestamp = jiffies;
if (sctp_style(sk, TCP)) { if (sctp_style(sk, TCP)) {
/* Change the sk->sk_state of a TCP-style socket that has /* Change the sk->sk_state of a TCP-style socket that has
...@@ -702,7 +702,7 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -702,7 +702,7 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
int gfp) int gfp)
{ {
sctp_cmd_seq_t commands; sctp_cmd_seq_t commands;
sctp_sm_table_entry_t *state_fn; const sctp_sm_table_entry_t *state_fn;
sctp_disposition_t status; sctp_disposition_t status;
int error = 0; int error = 0;
typedef const char *(printfn_t)(sctp_subtype_t); typedef const char *(printfn_t)(sctp_subtype_t);
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@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.
...@@ -537,7 +538,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, ...@@ -537,7 +538,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
* are in good shape. * are in good shape.
*/ */
chunk->subh.cookie_hdr = chunk->subh.cookie_hdr =
(sctp_signed_cookie_t *)chunk->skb->data; (struct sctp_signed_cookie *)chunk->skb->data;
skb_pull(chunk->skb, skb_pull(chunk->skb,
ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t));
...@@ -738,7 +739,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, ...@@ -738,7 +739,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
{ {
struct sctp_transport *transport = (struct sctp_transport *) arg; struct sctp_transport *transport = (struct sctp_transport *) arg;
if (asoc->overall_error_count > asoc->overall_error_threshold) { if (asoc->overall_error_count > asoc->max_retrans) {
/* 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));
...@@ -924,16 +925,16 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, ...@@ -924,16 +925,16 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
{ {
int len; int len;
struct sctp_packet *pkt; struct sctp_packet *pkt;
sctp_addr_param_t *addrparm; union sctp_addr_param *addrparm;
sctp_errhdr_t *errhdr; struct sctp_errhdr *errhdr;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; char buffer[sizeof(struct sctp_errhdr)+sizeof(union sctp_addr_param)];
/* Build the error on the stack. We are way to malloc crazy /* Build the error on the stack. We are way to malloc crazy
* throughout the code today. * throughout the code today.
*/ */
errhdr = (sctp_errhdr_t *)buffer; errhdr = (struct sctp_errhdr *)buffer;
addrparm = (sctp_addr_param_t *)errhdr->variable; addrparm = (union sctp_addr_param *)errhdr->variable;
/* Copy into a parm format. */ /* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm); len = sockaddr2sctp_addr(ssa, addrparm);
...@@ -1618,7 +1619,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, ...@@ -1618,7 +1619,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
/* "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.
*/ */
chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data; chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data;
skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t)); sizeof(sctp_chunkhdr_t));
...@@ -1866,7 +1867,7 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, ...@@ -1866,7 +1867,7 @@ sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
* yield a higher probability of success on the reattempt. * yield a higher probability of success on the reattempt.
*/ */
stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t))); stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t)));
stale = stale << 1 / 1000; stale = (stale * 2) / 1000;
bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE; bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE;
bht.param_hdr.length = htons(sizeof(bht)); bht.param_hdr.length = htons(sizeof(bht));
...@@ -1947,22 +1948,23 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, ...@@ -1947,22 +1948,23 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
unsigned len;
__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) >= /* Check that chunk header looks valid. */
(sizeof(struct sctp_chunkhdr) + len = ntohs(chunk->chunk_hdr->length);
sizeof(struct sctp_errhdr)))) if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause; error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
/* ASSOC_FAILED will DELETE_TCB. */ /* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error)); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
SCTP_INC_STATS(SctpAborteds); SCTP_INC_STATS(SctpAborteds);
SCTP_DEC_STATS(SctpCurrEstab); SCTP_DEC_STATS(SctpCurrEstab);
/* BUG? This does not look complete... */
return SCTP_DISPOSITION_ABORT; return SCTP_DISPOSITION_ABORT;
} }
...@@ -1978,6 +1980,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, ...@@ -1978,6 +1980,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
unsigned len;
__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))
...@@ -1989,9 +1992,9 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, ...@@ -1989,9 +1992,9 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
if (chunk && (ntohs(chunk->chunk_hdr->length) >= /* Check that chunk header looks valid. */
(sizeof(struct sctp_chunkhdr) + len = ntohs(chunk->chunk_hdr->length);
sizeof(struct sctp_errhdr)))) if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause; error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
/* CMD_INIT_FAILED will DELETE_TCB. */ /* CMD_INIT_FAILED will DELETE_TCB. */
...@@ -3201,82 +3204,6 @@ sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep, ...@@ -3201,82 +3204,6 @@ sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
#if 0
/*
* We did something stupid but got lucky. Namely, we sent a HEARTBEAT
* before the association was all the way up and we did NOT get an
* ABORT.
*
* Log the fact and then process normally.
*
* Section: Not specified
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t lucky(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (chunk->sctp_hdr->vtag != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
#endif /* 0 */
#if 0
/*
* The other end is doing something very stupid. We'll ignore them
* after logging their idiocy. :-)
*
* Section: Not specified
* Verification Tag: 8.5 Verification Tag [Normal verification]
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t other_stupid(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. ...
*/
if (chunk->sctp_hdr->vtag != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
#endif /* 0 */
/* /*
* The other end is violating protocol. * The other end is violating protocol.
...@@ -4070,7 +3997,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, ...@@ -4070,7 +3997,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
{ {
struct sctp_transport *transport = arg; struct sctp_transport *transport = arg;
if (asoc->overall_error_count >= asoc->overall_error_threshold) { if (asoc->overall_error_count >= asoc->max_retrans) {
/* 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));
...@@ -4241,7 +4168,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, ...@@ -4241,7 +4168,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
struct sctp_chunk *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->max_retrans) {
/* 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));
...@@ -4500,13 +4427,21 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc, ...@@ -4500,13 +4427,21 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
if (asoc) { if (asoc) {
vtag = asoc->peer.i.init_tag; vtag = asoc->peer.i.init_tag;
} else { } else {
/* Special case the INIT as there is no vtag yet. */ /* Special case the INIT and stale COOKIE_ECHO as there is no
if (SCTP_CID_INIT == chunk->chunk_hdr->type) { * vtag yet.
*/
switch(chunk->chunk_hdr->type) {
case SCTP_CID_INIT:
{
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
init = (sctp_init_chunk_t *)chunk->chunk_hdr; init = (sctp_init_chunk_t *)chunk->chunk_hdr;
vtag = ntohl(init->init_hdr.init_tag); vtag = ntohl(init->init_hdr.init_tag);
} else { break;
}
default:
vtag = ntohl(chunk->sctp_hdr->vtag); vtag = ntohl(chunk->sctp_hdr->vtag);
break;
} }
} }
...@@ -4557,6 +4492,12 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, ...@@ -4557,6 +4492,12 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
if (err_chunk) { if (err_chunk) {
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
if (packet) { if (packet) {
struct sctp_signed_cookie *cookie;
/* Override the OOTB vtag from the cookie. */
cookie = chunk->subh.cookie_hdr;
packet->vtag = cookie->c.peer_vtag;
/* Set the skb to the belonging sock for accounting. */ /* Set the skb to the belonging sock for accounting. */
err_chunk->skb->sk = ep->base.sk; err_chunk->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, err_chunk); sctp_packet_append_chunk(packet, err_chunk);
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static sctp_sm_table_entry_t bug = { static const sctp_sm_table_entry_t bug = {
.fn = sctp_sf_bug, .fn = sctp_sf_bug,
.name = "sctp_sf_bug" .name = "sctp_sf_bug"
}; };
...@@ -64,7 +64,7 @@ static sctp_sm_table_entry_t bug = { ...@@ -64,7 +64,7 @@ static sctp_sm_table_entry_t bug = {
} \ } \
return &_table[event_subtype._type][(int)state]; return &_table[event_subtype._type][(int)state];
sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
sctp_state_t state, sctp_state_t state,
sctp_subtype_t event_subtype) sctp_subtype_t event_subtype)
{ {
...@@ -418,7 +418,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -418,7 +418,7 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
* *
* For base protocol (RFC 2960). * For base protocol (RFC 2960).
*/ */
sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_DATA, TYPE_SCTP_DATA,
TYPE_SCTP_INIT, TYPE_SCTP_INIT,
TYPE_SCTP_INIT_ACK, TYPE_SCTP_INIT_ACK,
...@@ -437,7 +437,7 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU ...@@ -437,7 +437,7 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU
}; /* state_fn_t chunk_event_table[][] */ }; /* state_fn_t chunk_event_table[][] */
static sctp_sm_table_entry_t static const sctp_sm_table_entry_t
chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ /* SCTP_STATE_EMPTY */
{.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"},
...@@ -586,7 +586,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { ...@@ -586,7 +586,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* The primary index for this table is the primitive type. /* The primary index for this table is the primitive type.
* The secondary index for this table is the state. * The secondary index for this table is the state.
*/ */
sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_PRIMITIVE_ASSOCIATE, TYPE_SCTP_PRIMITIVE_ASSOCIATE,
TYPE_SCTP_PRIMITIVE_SHUTDOWN, TYPE_SCTP_PRIMITIVE_SHUTDOWN,
TYPE_SCTP_PRIMITIVE_ABORT, TYPE_SCTP_PRIMITIVE_ABORT,
...@@ -617,7 +617,7 @@ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE ...@@ -617,7 +617,7 @@ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
} }
sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_OTHER_NO_PENDING_TSN, TYPE_SCTP_OTHER_NO_PENDING_TSN,
}; };
...@@ -811,7 +811,7 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA ...@@ -811,7 +811,7 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_EVENT_TIMEOUT_NONE, TYPE_SCTP_EVENT_TIMEOUT_NONE,
TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, TYPE_SCTP_EVENT_TIMEOUT_T1_INIT,
...@@ -823,7 +823,8 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM ...@@ -823,7 +823,8 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
}; };
sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
sctp_state_t state)
{ {
if (state > SCTP_STATE_MAX) if (state > SCTP_STATE_MAX)
return &bug; return &bug;
......
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
* Sridhar Samudrala <samudrala@us.ibm.com> * Sridhar Samudrala <samudrala@us.ibm.com>
* Inaky Perez-Gonzalez <inaky.gonzalez@intel.com> * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu>
* *
* 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.
...@@ -100,6 +102,7 @@ static void sctp_sock_migrate(struct sock *, struct sock *, ...@@ -100,6 +102,7 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
extern kmem_cache_t *sctp_bucket_cachep; extern kmem_cache_t *sctp_bucket_cachep;
extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc);
/* 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.
...@@ -124,18 +127,10 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) ...@@ -124,18 +127,10 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
return asoc; return asoc;
} }
/* First, verify that this is a kernel address. */ /* Otherwise this is a UDP-style socket. */
if (sctp_is_valid_kaddr((unsigned long) id)) { asoc = (struct sctp_association *)id;
struct sctp_association *temp; if (!sctp_assoc_valid(sk, asoc))
return NULL;
/* Verify that this _is_ an sctp_association
* data structure and if so, that the socket matches.
*/
temp = (struct sctp_association *)id;
if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
(temp->base.sk == sk))
asoc = temp;
}
return asoc; return asoc;
} }
...@@ -1624,6 +1619,110 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, ...@@ -1624,6 +1619,110 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
return 0; return 0;
} }
/*
*
* 7.1.1 SCTP_RTOINFO
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
* and modify these parameters.
* All parameters are time values, in milliseconds. A value of 0, when
* modifying the parameters, indicates that the current value should not
* be changed.
*
*/
static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) {
struct sctp_rtoinfo rtoinfo;
struct sctp_association *asoc;
if (optlen != sizeof (struct sctp_rtoinfo))
return -EINVAL;
if (copy_from_user(&rtoinfo, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
/* Set the values to the specific association */
if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
if (rtoinfo.srto_initial != 0)
asoc->rto_initial = rtoinfo.srto_initial * HZ / 1000;
if (rtoinfo.srto_max != 0)
asoc->rto_max = rtoinfo.srto_max * HZ / 1000;
if (rtoinfo.srto_min != 0)
asoc->rto_min = rtoinfo.srto_min * HZ / 1000;
} else {
/* If there is no association or the association-id = 0
* set the values to the endpoint.
*/
struct sctp_opt *sp = sctp_sk(sk);
if (rtoinfo.srto_initial != 0)
sp->rtoinfo.srto_initial = rtoinfo.srto_initial;
if (rtoinfo.srto_max != 0)
sp->rtoinfo.srto_max = rtoinfo.srto_max;
if (rtoinfo.srto_min != 0)
sp->rtoinfo.srto_min = rtoinfo.srto_min;
}
return 0;
}
/*
*
* 7.1.2 SCTP_ASSOCINFO
*
* This option is used to tune the the maximum retransmission attempts
* of the association.
* Returns an error if the new association retransmission value is
* greater than the sum of the retransmission value of the peer.
* See [SCTP] for more information.
*
*/
static int sctp_setsockopt_assocrtx(struct sock *sk, char *optval,
int optlen) {
struct sctp_assocparams assocparams;
struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assocparams))
return -EINVAL;
if (copy_from_user(&assocparams, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
/* Set the values to the specific association */
if (asoc) {
if (assocparams.sasoc_asocmaxrxt != 0)
asoc->max_retrans = assocparams.sasoc_asocmaxrxt;
if (assocparams.sasoc_cookie_life != 0) {
asoc->cookie_life.tv_sec =
assocparams.sasoc_cookie_life / 1000;
asoc->cookie_life.tv_usec =
(assocparams.sasoc_cookie_life % 1000)
* 1000;
}
} else {
/* Set the values to the endpoint */
struct sctp_opt *sp = sctp_sk(sk);
if (assocparams.sasoc_asocmaxrxt != 0)
sp->assocparams.sasoc_asocmaxrxt =
assocparams.sasoc_asocmaxrxt;
if (assocparams.sasoc_cookie_life != 0)
sp->assocparams.sasoc_cookie_life =
assocparams.sasoc_cookie_life;
}
return 0;
}
/* /*
* 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
* *
...@@ -1771,6 +1870,12 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1771,6 +1870,12 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_NODELAY: case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen); retval = sctp_setsockopt_nodelay(sk, optval, optlen);
break; break;
case SCTP_RTOINFO:
retval = sctp_setsockopt_rtoinfo(sk, optval, optlen);
break;
case SCTP_ASSOCRTXINFO:
retval = sctp_setsockopt_assocrtx(sk, optval, optlen);
break;
case SCTP_I_WANT_MAPPED_V4_ADDR: case SCTP_I_WANT_MAPPED_V4_ADDR:
retval = sctp_setsockopt_mappedv4(sk, optval, optlen); retval = sctp_setsockopt_mappedv4(sk, optval, optlen);
break; break;
...@@ -2027,15 +2132,25 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2027,15 +2132,25 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; sp->initmsg.sinit_num_ostreams = sctp_max_outstreams;
sp->initmsg.sinit_max_instreams = sctp_max_instreams; sp->initmsg.sinit_max_instreams = sctp_max_instreams;
sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; sp->initmsg.sinit_max_attempts = sctp_max_retrans_init;
sp->initmsg.sinit_max_init_timeo = sctp_rto_max / HZ; sp->initmsg.sinit_max_init_timeo = (sctp_rto_max / HZ) * 1000;
/* Initialize default RTO related parameters. These parameters can /* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option. * be modified for with the SCTP_RTOINFO socket option.
* FIXME: These are not used yet. * FIXME: These are not used yet.
*/ */
sp->rtoinfo.srto_initial = sctp_rto_initial; sp->rtoinfo.srto_initial = (sctp_rto_initial / HZ) * 1000;
sp->rtoinfo.srto_max = sctp_rto_max; sp->rtoinfo.srto_max = (sctp_rto_max / HZ) * 1000;
sp->rtoinfo.srto_min = sctp_rto_min; sp->rtoinfo.srto_min = (sctp_rto_min / HZ) * 1000;
/* Initialize default association related parameters. These parameters
* can be modified with the SCTP_ASSOCINFO socket option.
*/
sp->assocparams.sasoc_asocmaxrxt = sctp_max_retrans_association;
sp->assocparams.sasoc_number_peer_destinations = 0;
sp->assocparams.sasoc_peer_rwnd = 0;
sp->assocparams.sasoc_local_rwnd = 0;
sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ)
* 1000;
/* Initialize default event subscriptions. /* Initialize default event subscriptions.
* the struct sock is initialized to zero, so only * the struct sock is initialized to zero, so only
...@@ -2050,7 +2165,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2050,7 +2165,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Default Peer Address Parameters. These defaults can /* Default Peer Address Parameters. These defaults can
* be modified via SCTP_SET_PEER_ADDR_PARAMS * be modified via SCTP_SET_PEER_ADDR_PARAMS
*/ */
sp->paddrparam.spp_hbinterval = sctp_hb_interval / HZ; sp->paddrparam.spp_hbinterval = (sctp_hb_interval / HZ) * 1000;
sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path;
/* If enabled no SCTP message fragmentation will be performed. /* If enabled no SCTP message fragmentation will be performed.
...@@ -2182,7 +2297,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -2182,7 +2297,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_state = asoc->state; status.sstat_state = asoc->state;
status.sstat_rwnd = asoc->peer.rwnd; status.sstat_rwnd = asoc->peer.rwnd;
status.sstat_unackdata = asoc->unack_data; status.sstat_unackdata = asoc->unack_data;
status.sstat_penddata = asoc->peer.tsn_map.pending_data;
status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
status.sstat_instrms = asoc->c.sinit_max_instreams; status.sstat_instrms = asoc->c.sinit_max_instreams;
status.sstat_outstrms = asoc->c.sinit_num_ostreams; status.sstat_outstrms = asoc->c.sinit_num_ostreams;
/* Just in time frag_point update. */ /* Just in time frag_point update. */
...@@ -2196,7 +2312,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -2196,7 +2312,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_state = transport->active;
status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_cwnd = transport->cwnd;
status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_srtt = transport->srtt;
status.sstat_primary.spinfo_rto = transport->rto; status.sstat_primary.spinfo_rto = (transport->rto / HZ) * 1000;
status.sstat_primary.spinfo_mtu = transport->pmtu; status.sstat_primary.spinfo_mtu = transport->pmtu;
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
...@@ -2251,7 +2367,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, ...@@ -2251,7 +2367,7 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
pinfo.spinfo_state = transport->active; pinfo.spinfo_state = transport->active;
pinfo.spinfo_cwnd = transport->cwnd; pinfo.spinfo_cwnd = transport->cwnd;
pinfo.spinfo_srtt = transport->srtt; pinfo.spinfo_srtt = transport->srtt;
pinfo.spinfo_rto = transport->rto; pinfo.spinfo_rto = (transport->rto / HZ) * 1000;
pinfo.spinfo_mtu = transport->pmtu; pinfo.spinfo_mtu = transport->pmtu;
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
...@@ -2607,7 +2723,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -2607,7 +2723,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
struct sctp_getaddrs getaddrs; struct sctp_getaddrs getaddrs;
struct sockaddr_storage_list *from; struct sctp_sockaddr_entry *from;
struct sockaddr_storage *to; struct sockaddr_storage *to;
if (len != sizeof(struct sctp_getaddrs)) if (len != sizeof(struct sctp_getaddrs))
...@@ -2635,7 +2751,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -2635,7 +2751,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
to = getaddrs.addrs; to = getaddrs.addrs;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
from = list_entry(pos, from = list_entry(pos,
struct sockaddr_storage_list, struct sctp_sockaddr_entry,
list); list);
if (copy_to_user(to, &from->a, sizeof(from->a))) if (copy_to_user(to, &from->a, sizeof(from->a)))
return -EFAULT; return -EFAULT;
...@@ -2763,6 +2879,127 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len, ...@@ -2763,6 +2879,127 @@ static int sctp_getsockopt_nodelay(struct sock *sk, int len,
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/*
*
* 7.1.1 SCTP_RTOINFO
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. sctp_rtoinfo structure is used to access
* and modify these parameters.
* All parameters are time values, in milliseconds. A value of 0, when
* modifying the parameters, indicates that the current value should not
* be changed.
*
*/
static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval,
int *optlen) {
struct sctp_rtoinfo rtoinfo;
struct sctp_association *asoc;
if (len != sizeof (struct sctp_rtoinfo))
return -EINVAL;
if (copy_from_user(&rtoinfo, optval, sizeof (struct sctp_rtoinfo)))
return -EFAULT;
asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
/* Values corresponding to the specific association. */
if (asoc) {
rtoinfo.srto_initial = (asoc->rto_initial / HZ) * 1000;
rtoinfo.srto_max = (asoc->rto_max / HZ) * 1000;
rtoinfo.srto_min = (asoc->rto_min / HZ) * 1000;
} else {
/* Values corresponding to the endpoint. */
struct sctp_opt *sp = sctp_sk(sk);
rtoinfo.srto_initial = sp->rtoinfo.srto_initial;
rtoinfo.srto_max = sp->rtoinfo.srto_max;
rtoinfo.srto_min = sp->rtoinfo.srto_min;
}
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &rtoinfo, len))
return -EFAULT;
return 0;
}
/*
*
* 7.1.2 SCTP_ASSOCINFO
*
* This option is used to tune the the maximum retransmission attempts
* of the association.
* Returns an error if the new association retransmission value is
* greater than the sum of the retransmission value of the peer.
* See [SCTP] for more information.
*
*/
static int sctp_getsockopt_assocrtx(struct sock *sk, int len, char *optval,
int *optlen) {
struct sctp_assocparams assocparams;
struct sctp_association *asoc;
struct list_head *pos;
int cnt = 0;
if (len != sizeof (struct sctp_assocparams))
return -EINVAL;
if (copy_from_user(&assocparams, optval,
sizeof (struct sctp_assocparams)))
return -EFAULT;
asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
/* Values correspoinding to the specific association */
if (assocparams.sasoc_assoc_id != 0) {
assocparams.sasoc_asocmaxrxt = asoc->max_retrans;
assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;
assocparams.sasoc_local_rwnd = asoc->a_rwnd;
assocparams.sasoc_cookie_life = (asoc->cookie_life.tv_sec
* 1000) +
(asoc->cookie_life.tv_usec
/ 1000);
list_for_each(pos, &asoc->peer.transport_addr_list) {
cnt ++;
}
assocparams.sasoc_number_peer_destinations = cnt;
} else {
/* Values corresponding to the endpoint */
struct sctp_opt *sp = sctp_sk(sk);
assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt;
assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd;
assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd;
assocparams.sasoc_cookie_life =
sp->assocparams.sasoc_cookie_life;
assocparams.sasoc_number_peer_destinations =
sp->assocparams.
sasoc_number_peer_destinations;
}
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &assocparams, len))
return -EFAULT;
return 0;
}
/* /*
* 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
* *
...@@ -2896,6 +3133,12 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -2896,6 +3133,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_RTOINFO:
retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen);
break;
case SCTP_ASSOCRTXINFO:
retval = sctp_getsockopt_assocrtx(sk, len, optval, optlen);
break;
case SCTP_I_WANT_MAPPED_V4_ADDR: case SCTP_I_WANT_MAPPED_V4_ADDR:
retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
break; break;
...@@ -2952,7 +3195,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2952,7 +3195,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
snum = addr->v4.sin_port; snum = addr->v4.sin_port;
SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum);
sctp_local_bh_disable(); sctp_local_bh_disable();
if (snum == 0) { if (snum == 0) {
...@@ -2999,7 +3241,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2999,7 +3241,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* mutex. * mutex.
*/ */
snum = rover; snum = rover;
pp = NULL;
} else { } else {
/* We are given an specific port number; we verify /* We are given an specific port number; we verify
* that it is not being used. If it is used, we will * that it is not being used. If it is used, we will
...@@ -3011,23 +3252,23 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3011,23 +3252,23 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
sctp_spin_lock(&head->lock); sctp_spin_lock(&head->lock);
for (pp = head->chain; pp; pp = pp->next) { for (pp = head->chain; pp; pp = pp->next) {
if (pp->port == snum) if (pp->port == snum)
break; goto pp_found;
} }
} }
pp = NULL;
goto pp_not_found;
if (pp && !hlist_empty(&pp->sk_list)) { pp_found:
if (!hlist_empty(&pp->owner)) {
/* 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_list not empty); that other * used by other socket (pp->owner not empty); that other
* socket is going to be sk2. * socket is going to be sk2.
*/ */
int reuse = sk->sk_reuse; int reuse = sk->sk_reuse;
struct sock *sk2; struct sock *sk2;
struct hlist_node *node; struct hlist_node *node;
SCTP_DEBUG_PRINTK("sctp_get_port() found a " SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
"possible match\n");
if (pp->fastreuse && sk->sk_reuse) if (pp->fastreuse && sk->sk_reuse)
goto success; goto success;
...@@ -3041,7 +3282,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3041,7 +3282,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* that this port/socket (sk) combination are already * that this port/socket (sk) combination are already
* in an endpoint. * in an endpoint.
*/ */
sk_for_each_bound(sk2, node, &pp->sk_list) { sk_for_each_bound(sk2, node, &pp->owner) {
struct sctp_endpoint *ep2; struct sctp_endpoint *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
...@@ -3056,10 +3297,9 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3056,10 +3297,9 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
} }
SCTP_DEBUG_PRINTK("sctp_get_port(): Found a match\n"); SCTP_DEBUG_PRINTK("sctp_get_port(): Found a match\n");
} }
pp_not_found:
/* 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 && !(pp = sctp_bucket_create(head, snum))) if (!pp && !(pp = sctp_bucket_create(head, snum)))
goto fail_unlock; goto fail_unlock;
...@@ -3067,7 +3307,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3067,7 +3307,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* if sk->sk_reuse is too (that is, if the caller requested * if sk->sk_reuse is too (that is, if the caller requested
* SO_REUSEADDR on this socket -sk-). * SO_REUSEADDR on this socket -sk-).
*/ */
if (hlist_empty(&pp->sk_list)) if (hlist_empty(&pp->owner))
pp->fastreuse = sk->sk_reuse ? 1 : 0; pp->fastreuse = sk->sk_reuse ? 1 : 0;
else if (pp->fastreuse && !sk->sk_reuse) else if (pp->fastreuse && !sk->sk_reuse)
pp->fastreuse = 0; pp->fastreuse = 0;
...@@ -3079,7 +3319,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3079,7 +3319,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
success: success:
inet_sk(sk)->num = snum; inet_sk(sk)->num = snum;
if (!sctp_sk(sk)->bind_hash) { if (!sctp_sk(sk)->bind_hash) {
sk_add_bind_node(sk, &pp->sk_list); sk_add_bind_node(sk, &pp->owner);
sctp_sk(sk)->bind_hash = pp; sctp_sk(sk)->bind_hash = pp;
} }
ret = 0; ret = 0;
...@@ -3089,8 +3329,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -3089,8 +3329,6 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
fail: fail:
sctp_local_bh_enable(); sctp_local_bh_enable();
SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret);
addr->v4.sin_port = htons(addr->v4.sin_port); addr->v4.sin_port = htons(addr->v4.sin_port);
return ret; return ret;
} }
...@@ -3316,7 +3554,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( ...@@ -3316,7 +3554,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
if (pp) { if (pp) {
pp->port = snum; pp->port = snum;
pp->fastreuse = 0; pp->fastreuse = 0;
INIT_HLIST_HEAD(&pp->sk_list); INIT_HLIST_HEAD(&pp->owner);
if ((pp->next = head->chain) != NULL) if ((pp->next = head->chain) != NULL)
pp->next->pprev = &pp->next; pp->next->pprev = &pp->next;
head->chain = pp; head->chain = pp;
...@@ -3328,7 +3566,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( ...@@ -3328,7 +3566,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
/* Caller must hold hashbucket lock for this tb with local BH disabled */ /* Caller must hold hashbucket lock for this tb with local BH disabled */
static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
{ {
if (hlist_empty(&pp->sk_list)) { if (hlist_empty(&pp->owner)) {
if (pp->next) if (pp->next)
pp->next->pprev = pp->pprev; pp->next->pprev = pp->pprev;
*(pp->pprev) = pp->next; *(pp->pprev) = pp->next;
...@@ -3337,8 +3575,8 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) ...@@ -3337,8 +3575,8 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
} }
} }
/* FIXME: Comments! */ /* Release this socket's reference to a local port. */
static __inline__ void __sctp_put_port(struct sock *sk) static inline void __sctp_put_port(struct sock *sk)
{ {
struct sctp_bind_hashbucket *head = struct sctp_bind_hashbucket *head =
&sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
...@@ -3942,6 +4180,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3942,6 +4180,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
{ {
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);
struct sctp_bind_bucket *pp; /* hash list port iterator */
struct sctp_endpoint *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;
...@@ -3951,7 +4190,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3951,7 +4190,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
*/ */
newsk->sk_sndbuf = oldsk->sk_sndbuf; newsk->sk_sndbuf = oldsk->sk_sndbuf;
newsk->sk_rcvbuf = oldsk->sk_rcvbuf; newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
*newsp = *oldsp; /* Brute force copy old sctp opt. */
memcpy(newsp, oldsp, sizeof(struct sctp_opt));
/* Restore the ep value that was overwritten with the above structure /* Restore the ep value that was overwritten with the above structure
* copy. * copy.
...@@ -3959,6 +4199,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3959,6 +4199,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
newsp->ep = newep; newsp->ep = newep;
newsp->hmac = NULL; newsp->hmac = NULL;
/* Hook this new socket in to the bind_hash list. */
pp = sctp_sk(oldsk)->bind_hash;
sk_add_bind_node(newsk, &pp->owner);
sctp_sk(newsk)->bind_hash = pp;
inet_sk(newsk)->num = inet_sk(oldsk)->num;
/* 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.
*/ */
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
* Mingqin Liu <liuming@us.ibm.com> * Mingqin Liu <liuming@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@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.
...@@ -42,42 +43,54 @@ ...@@ -42,42 +43,54 @@
#include <net/sctp/structs.h> #include <net/sctp/structs.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
static ctl_handler sctp_sysctl_jiffies_ms;
static long rto_timer_min = 0;
static long rto_timer_max = 86400000; /* One day */
static ctl_table sctp_table[] = { static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_INITIAL, .ctl_name = NET_SCTP_RTO_INITIAL,
.procname = "rto_initial", .procname = "rto_initial",
.data = &sctp_rto_initial, .data = &sctp_rto_initial,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_RTO_MIN, .ctl_name = NET_SCTP_RTO_MIN,
.procname = "rto_min", .procname = "rto_min",
.data = &sctp_rto_min, .data = &sctp_rto_min,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_RTO_MAX, .ctl_name = NET_SCTP_RTO_MAX,
.procname = "rto_max", .procname = "rto_max",
.data = &sctp_rto_max, .data = &sctp_rto_max,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_VALID_COOKIE_LIFE, .ctl_name = NET_SCTP_VALID_COOKIE_LIFE,
.procname = "valid_cookie_life", .procname = "valid_cookie_life",
.data = &sctp_valid_cookie_life, .data = &sctp_valid_cookie_life,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_MAX_BURST, .ctl_name = NET_SCTP_MAX_BURST,
...@@ -115,19 +128,23 @@ static ctl_table sctp_table[] = { ...@@ -115,19 +128,23 @@ static ctl_table sctp_table[] = {
.ctl_name = NET_SCTP_HB_INTERVAL, .ctl_name = NET_SCTP_HB_INTERVAL,
.procname = "hb_interval", .procname = "hb_interval",
.data = &sctp_hb_interval, .data = &sctp_hb_interval,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_PRESERVE_ENABLE, .ctl_name = NET_SCTP_PRESERVE_ENABLE,
.procname = "cookie_preserve_enable", .procname = "cookie_preserve_enable",
.data = &sctp_cookie_preserve_enable, .data = &sctp_cookie_preserve_enable,
.maxlen = sizeof(int), .maxlen = sizeof(long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
.strategy = &sysctl_jiffies .strategy = &sctp_sysctl_jiffies_ms,
.extra1 = &rto_timer_min,
.extra2 = &rto_timer_max
}, },
{ {
.ctl_name = NET_SCTP_RTO_ALPHA, .ctl_name = NET_SCTP_RTO_ALPHA,
...@@ -181,3 +198,37 @@ void sctp_sysctl_unregister(void) ...@@ -181,3 +198,37 @@ void sctp_sysctl_unregister(void)
{ {
unregister_sysctl_table(sctp_sysctl_header); unregister_sysctl_table(sctp_sysctl_header);
} }
/* Strategy function to convert jiffies to milliseconds. */
static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen, void **context) {
if (oldval) {
size_t olen;
if (oldlenp) {
if (get_user(olen, oldlenp))
return -EFAULT;
if (olen != sizeof (int))
return -EINVAL;
}
if (put_user((*(int *)(table->data) / HZ) * 1000,
(int *)oldval) ||
(oldlenp && put_user(sizeof (int), oldlenp)))
return -EFAULT;
}
if (newval && newlen) {
int new;
if (newlen != sizeof (int))
return -EINVAL;
if (get_user(new, (int *)newval))
return -EFAULT;
*(int *)(table->data) = (new * HZ) * 1000;
}
return 1;
}
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void sctp_tsnmap_update(struct sctp_tsnmap *map); static void sctp_tsnmap_update(struct sctp_tsnmap *map);
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map);
static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
__u16 len, __u16 base, __u16 len, __u16 base,
int *started, __u16 *start, int *started, __u16 *start,
...@@ -92,7 +91,6 @@ struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len, ...@@ -92,7 +91,6 @@ struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
map->cumulative_tsn_ack_point = initial_tsn - 1; map->cumulative_tsn_ack_point = initial_tsn - 1;
map->max_tsn_seen = map->cumulative_tsn_ack_point; map->max_tsn_seen = map->cumulative_tsn_ack_point;
map->malloced = 0; map->malloced = 0;
map->pending_data = 0;
map->num_dup_tsns = 0; map->num_dup_tsns = 0;
return map; return map;
...@@ -135,14 +133,6 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn) ...@@ -135,14 +133,6 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
return dup; return dup;
} }
/* Is there a gap in the TSN map? */
int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
int has_gap;
has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen);
return has_gap;
}
/* Mark this TSN as seen. */ /* Mark this TSN as seen. */
void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn) void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
...@@ -176,21 +166,6 @@ void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn) ...@@ -176,21 +166,6 @@ void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
sctp_tsnmap_update(map); sctp_tsnmap_update(map);
} }
void sctp_tsnmap_report_dup(struct sctp_tsnmap *map, __u32 tsn)
{
}
/* Retrieve the Cumulative TSN Ack Point. */
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
{
return map->cumulative_tsn_ack_point;
}
/* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
{
return map->max_tsn_seen;
}
/* Dispose of a tsnmap. */ /* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *map) void sctp_tsnmap_free(struct sctp_tsnmap *map)
...@@ -219,6 +194,10 @@ int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, ...@@ -219,6 +194,10 @@ int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
/* We haven't found a gap yet. */ /* We haven't found a gap yet. */
started = ended = 0; started = ended = 0;
/* If there are no more gap acks possible, get out fast. */
if (TSN_lte(map->max_tsn_seen, iter->start))
return 0;
/* Search the first mapping array. */ /* Search the first mapping array. */
if (iter->start - map->base_tsn < map->len) { if (iter->start - map->base_tsn < map->len) {
...@@ -304,10 +283,11 @@ static void sctp_tsnmap_update(struct sctp_tsnmap *map) ...@@ -304,10 +283,11 @@ static void sctp_tsnmap_update(struct sctp_tsnmap *map)
} while (map->tsn_map[ctsn - map->base_tsn]); } while (map->tsn_map[ctsn - map->base_tsn]);
map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
sctp_tsnmap_update_pending_data(map);
} }
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map) /* How many data chunks are we missing from our peer?
*/
__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
{ {
__u32 cum_tsn = map->cumulative_tsn_ack_point; __u32 cum_tsn = map->cumulative_tsn_ack_point;
__u32 max_tsn = map->max_tsn_seen; __u32 max_tsn = map->max_tsn_seen;
...@@ -339,7 +319,7 @@ static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map) ...@@ -339,7 +319,7 @@ static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
} }
out: out:
map->pending_data = pending_data; return pending_data;
} }
/* This is a private helper for finding Gap Ack Blocks. It searches a /* This is a private helper for finding Gap Ack Blocks. It searches a
...@@ -359,6 +339,8 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, ...@@ -359,6 +339,8 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
* early if we have found the end of the Gap Ack Block. * early if we have found the end of the Gap Ack Block.
*/ */
/* Also, stop looking past the maximum TSN seen. */
/* Look for the start. */ /* Look for the start. */
if (!(*started)) { if (!(*started)) {
for (; i < len; i++) { for (; i < len; i++) {
...@@ -404,3 +386,26 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn) ...@@ -404,3 +386,26 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
else else
map->overflow_map[gap - map->len] = 0; map->overflow_map[gap - map->len] = 0;
} }
/* How many gap ack blocks do we have recorded? */
__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map)
{
struct sctp_tsnmap_iter iter;
int gabs = 0;
/* Refresh the gap ack information. */
if (sctp_tsnmap_has_gap(map)) {
sctp_tsnmap_iter_init(map, &iter);
while (sctp_tsnmap_next_gap_ack(map, &iter,
&map->gabs[gabs].start,
&map->gabs[gabs].end)) {
map->gabs[gabs].start = htons(map->gabs[gabs].start);
map->gabs[gabs].end = htons(map->gabs[gabs].end);
gabs++;
if (gabs >= SCTP_MAX_GABS)
break;
}
}
return gabs;
}
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