Commit 5d068c48 authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/linux-2.5.46

into dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/lksctp-2.5.46
parents db01fdce 26e2d0a7
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* *
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -72,6 +73,7 @@ typedef enum { ...@@ -72,6 +73,7 @@ typedef enum {
SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ SCTP_CMD_STRIKE, /* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_UPDATE, /* Update the heartbeat timers. */
SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */ SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */ SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */
SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */ SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */
......
...@@ -3,41 +3,41 @@ ...@@ -3,41 +3,41 @@
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* The base lksctp header. * The base lksctp header.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Xingang Guo <xingang.guo@intel.com> * Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -52,10 +52,10 @@ ...@@ -52,10 +52,10 @@
* structs * structs
* prototypes * prototypes
* macros, externs, and inlines * macros, externs, and inlines
* *
* Move test_frame specific items out of the kernel headers * Move test_frame specific items out of the kernel headers
* and into the test frame headers. This is not perfect in any sense * and into the test frame headers. This is not perfect in any sense
* and will continue to evolve. * and will continue to evolve.
*/ */
...@@ -78,11 +78,12 @@ ...@@ -78,11 +78,12 @@
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
#endif #endif
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.h> #include <asm/page.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/snmp.h>
#include <net/sctp/structs.h> #include <net/sctp/structs.h>
#include <net/sctp/constants.h> #include <net/sctp/constants.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
...@@ -104,19 +105,19 @@ ...@@ -104,19 +105,19 @@
#endif #endif
/* Certain internal static functions need to be exported when /* Certain internal static functions need to be exported when
* compiled into the test frame. * compiled into the test frame.
*/ */
#ifndef SCTP_STATIC #ifndef SCTP_STATIC
#define SCTP_STATIC static #define SCTP_STATIC static
#endif #endif
/* /*
* Function declarations. * Function declarations.
*/ */
/* /*
* sctp_protocol.c * sctp_protocol.c
*/ */
extern sctp_protocol_t sctp_proto; extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
...@@ -141,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); ...@@ -141,7 +142,7 @@ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg);
extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); extern int sctp_primitive_ABORT(sctp_association_t *, void *arg);
extern int sctp_primitive_SEND(sctp_association_t *, void *arg); extern int sctp_primitive_SEND(sctp_association_t *, void *arg);
extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/* /*
* sctp_crc32c.c * sctp_crc32c.c
...@@ -201,6 +202,11 @@ extern void sctp_hash_digest(const char *secret, const int secret_len, ...@@ -201,6 +202,11 @@ extern void sctp_hash_digest(const char *secret, const int secret_len,
#define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk) #define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk)
#define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk)
/* SCTP SNMP MIB stats handlers */
extern struct sctp_mib sctp_statistics[NR_CPUS * 2];
#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field)
#define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field)
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
/* Determine if this is a valid kernel address. */ /* Determine if this is a valid kernel address. */
static inline int sctp_is_valid_kaddr(unsigned long addr) static inline int sctp_is_valid_kaddr(unsigned long addr)
...@@ -412,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) ...@@ -412,6 +418,19 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return retval; return retval;
} }
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
* there is room for a param header too.
*/
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
/* Round an int up to the next multiple of 4. */ /* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3) #define WORD_ROUND(s) (((s)+3)&~3)
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@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>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -156,6 +157,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort; ...@@ -156,6 +157,7 @@ sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_closed;
sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_error_shutdown;
sctp_state_fn_t sctp_sf_ignore_primitive; sctp_state_fn_t sctp_sf_ignore_primitive;
sctp_state_fn_t sctp_sf_do_prm_requestheartbeat;
/* Prototypes for other event state functions. */ /* Prototypes for other event state functions. */
sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
...@@ -205,9 +207,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, ...@@ -205,9 +207,6 @@ sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *,
sctp_chunk_t *, sctp_chunk_t *,
const int priority); const int priority);
__u32 sctp_generate_verification_tag(void); __u32 sctp_generate_verification_tag(void);
sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *,
const int priority, int *addrs_len);
void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
/* Prototypes for chunk-building functions. */ /* Prototypes for chunk-building functions. */
...@@ -253,6 +252,9 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *, ...@@ -253,6 +252,9 @@ sctp_chunk_t *sctp_make_abort(const sctp_association_t *,
sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *,
const sctp_chunk_t *, const sctp_chunk_t *,
__u32 tsn); __u32 tsn);
sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
const sctp_chunk_t *,
const struct msghdr *);
sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *,
const sctp_transport_t *, const sctp_transport_t *,
const void *payload, const void *payload,
...@@ -332,7 +334,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *); ...@@ -332,7 +334,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *);
/* 4th level prototypes */ /* 4th level prototypes */
void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *, void sctp_param2sockaddr(sockaddr_storage_t *addr, sctp_addr_param_t *,
__u16 port); __u16 port);
int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); int sctp_addr2sockaddr(const union sctp_params, sockaddr_storage_t *);
int sockaddr2sctp_addr(const sockaddr_storage_t *, sctp_addr_param_t *); int sockaddr2sctp_addr(const sockaddr_storage_t *, sctp_addr_param_t *);
/* Extern declarations for major data structures. */ /* Extern declarations for major data structures. */
......
...@@ -3,34 +3,34 @@ ...@@ -3,34 +3,34 @@
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp. * Copyright (c) 2001 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email addresses: * email addresses:
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* Randall Stewart <randall@sctp.chicago.il.us> * Randall Stewart <randall@sctp.chicago.il.us>
* Ken Morneau <kmorneau@cisco.com> * Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com> * Qiaobing Xie <qxie1@email.mot.com>
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -246,8 +246,11 @@ typedef struct sctp_func { ...@@ -246,8 +246,11 @@ typedef struct sctp_func {
int optname, int optname,
char *optval, char *optval,
int *optlen); int *optlen);
int (*get_dst_mtu) (const sockaddr_storage_t *address); struct dst_entry *(*get_dst) (sockaddr_storage_t *daddr,
__u16 net_header_len; sockaddr_storage_t *saddr);
int (*cmp_saddr) (struct dst_entry *dst,
sockaddr_storage_t *saddr);
__u16 net_header_len;
int sockaddr_len; int sockaddr_len;
sa_family_t sa_family; sa_family_t sa_family;
struct list_head list; struct list_head list;
...@@ -356,20 +359,6 @@ typedef struct sctp_signed_cookie { ...@@ -356,20 +359,6 @@ typedef struct sctp_signed_cookie {
} sctp_signed_cookie_t; } sctp_signed_cookie_t;
/* This convenience type allows us to avoid casting when walking
* through a parameter list.
*/
typedef union {
__u8 *v;
sctp_paramhdr_t *p;
sctp_cookie_preserve_param_t *bht;
sctp_hostname_param_t *dns;
sctp_cookie_param_t *cookie;
sctp_supported_addrs_param_t *sat;
sctp_ipv4addr_param_t *v4;
sctp_ipv6addr_param_t *v6;
} sctpParam_t;
/* This is another convenience type to allocate memory for address /* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around * params for the maximum size and pass such structures around
...@@ -380,6 +369,21 @@ typedef union { ...@@ -380,6 +369,21 @@ typedef union {
sctp_ipv6addr_param_t v6; sctp_ipv6addr_param_t v6;
} sctp_addr_param_t; } sctp_addr_param_t;
/* A convenience type to allow walking through the various
* parameters and avoid casting all over the place.
*/
union sctp_params {
void *v;
sctp_paramhdr_t *p;
sctp_cookie_preserve_param_t *life;
sctp_hostname_param_t *dns;
sctp_cookie_param_t *cookie;
sctp_supported_addrs_param_t *sat;
sctp_ipv4addr_param_t *v4;
sctp_ipv6addr_param_t *v6;
sctp_addr_param_t *addr;
};
/* RFC 2960. Section 3.3.5 Heartbeat. /* RFC 2960. Section 3.3.5 Heartbeat.
* Heartbeat Information: variable length * Heartbeat Information: variable length
* The Sender-specific Heartbeat Info field should normally include * The Sender-specific Heartbeat Info field should normally include
...@@ -430,7 +434,7 @@ struct SCTP_chunk { ...@@ -430,7 +434,7 @@ struct SCTP_chunk {
*/ */
/* We point this at the FIRST TLV parameter to chunk_hdr. */ /* We point this at the FIRST TLV parameter to chunk_hdr. */
sctpParam_t param_hdr; union sctp_params param_hdr;
union { union {
__u8 *v; __u8 *v;
sctp_datahdr_t *data_hdr; sctp_datahdr_t *data_hdr;
...@@ -471,11 +475,13 @@ struct SCTP_chunk { ...@@ -471,11 +475,13 @@ struct SCTP_chunk {
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */ __u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */ __u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */ __u8 tsn_missing_report; /* Data chunk missing counter. */
/* What is the origin IP address for this chunk? */ /* What is the origin IP address for this chunk? */
sockaddr_storage_t source; sockaddr_storage_t source;
/* Destination address for this chunk. */
sockaddr_storage_t dest;
/* For an inbound chunk, this tells us where it came from. /* For an inbound chunk, this tells us where it came from.
* For an outbound chunk, it tells us where we'd like it to * For an outbound chunk, it tells us where we'd like it to
...@@ -492,7 +498,7 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); ...@@ -492,7 +498,7 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data);
sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *,
struct sock *); struct sock *);
void sctp_init_source(sctp_chunk_t *chunk); void sctp_init_addrs(sctp_chunk_t *chunk);
const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk);
/* This is a structure for holding either an IPv6 or an IPv4 address. */ /* This is a structure for holding either an IPv6 or an IPv4 address. */
...@@ -655,6 +661,9 @@ struct SCTP_transport { ...@@ -655,6 +661,9 @@ struct SCTP_transport {
/* PMTU : The current known path MTU. */ /* PMTU : The current known path MTU. */
__u32 pmtu; __u32 pmtu;
/* Destination */
struct dst_entry *dst;
/* When was the last time(in jiffies) that a data packet was sent on /* When was the last time(in jiffies) that a data packet was sent on
* this transport? This is used to adjust the cwnd when the transport * this transport? This is used to adjust the cwnd when the transport
* becomes inactive. * becomes inactive.
...@@ -676,13 +685,15 @@ struct SCTP_transport { ...@@ -676,13 +685,15 @@ struct SCTP_transport {
*/ */
unsigned long last_time_ecne_reduced; unsigned long last_time_ecne_reduced;
/* state : The current state of this destination, /* active : The current active state of this destination,
* : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. * : i.e. DOWN, UP, etc.
*/ */
struct { int active;
int active;
int hb_allowed; /* hb_allowed : The current heartbeat state of this destination,
} state; * : i.e. ALLOW-HB, NO-HEARTBEAT, etc.
*/
int hb_allowed;
/* These are the error stats for this destination. */ /* These are the error stats for this destination. */
...@@ -735,6 +746,7 @@ extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); ...@@ -735,6 +746,7 @@ extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int);
extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, extern sctp_transport_t *sctp_transport_init(sctp_transport_t *,
const sockaddr_storage_t *, int); const sockaddr_storage_t *, int);
extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *);
extern void sctp_transport_route(sctp_transport_t *, sockaddr_storage_t *);
extern void sctp_transport_free(sctp_transport_t *); extern void sctp_transport_free(sctp_transport_t *);
extern void sctp_transport_destroy(sctp_transport_t *); extern void sctp_transport_destroy(sctp_transport_t *);
extern void sctp_transport_reset_timers(sctp_transport_t *); extern void sctp_transport_reset_timers(sctp_transport_t *);
...@@ -885,9 +897,9 @@ int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, ...@@ -885,9 +897,9 @@ int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *,
int priority); int priority);
int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *);
int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *);
sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
int *addrs_len, int *addrs_len,
int priority); int priority);
int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp,
__u8 *raw_addr_list, __u8 *raw_addr_list,
int addrs_len, int addrs_len,
...@@ -904,7 +916,7 @@ int sctp_addr_is_valid(const sockaddr_storage_t *addr); ...@@ -904,7 +916,7 @@ int sctp_addr_is_valid(const sockaddr_storage_t *addr);
typedef enum { typedef enum {
SCTP_EP_TYPE_SOCKET, SCTP_EP_TYPE_SOCKET,
SCTP_EP_TYPE_ASSOCIATION, SCTP_EP_TYPE_ASSOCIATION,
} sctp_endpoint_type_t; } sctp_endpoint_type_t;
/* /*
* A common base class to bridge the implmentation view of a * A common base class to bridge the implmentation view of a
...@@ -1052,22 +1064,11 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1052,22 +1064,11 @@ int sctp_verify_init(const sctp_association_t *asoc,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk); sctp_chunk_t **err_chunk);
int sctp_verify_param(const sctp_association_t *asoc, int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
sctpParam_t param, const sockaddr_storage_t *peer_addr,
sctp_cid_t cid, sctp_init_chunk_t *peer_init, int priority);
sctp_chunk_t *chunk, int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
sctp_chunk_t **err_chunk); const sockaddr_storage_t *peer_addr, int priority);
int sctp_process_unk_param(const sctp_association_t *asoc,
sctpParam_t param,
sctp_chunk_t *chunk,
sctp_chunk_t **err_chunk);
void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const sockaddr_storage_t *peer_addr,
sctp_init_chunk_t *peer_init, int priority);
int sctp_process_param(sctp_association_t *asoc,
sctpParam_t param,
const sockaddr_storage_t *peer_addr,
sctp_cid_t cid, int priority);
__u32 sctp_generate_tag(const sctp_endpoint_t *ep); __u32 sctp_generate_tag(const sctp_endpoint_t *ep);
__u32 sctp_generate_tsn(const sctp_endpoint_t *ep); __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
...@@ -1154,10 +1155,10 @@ struct SCTP_association { ...@@ -1154,10 +1155,10 @@ struct SCTP_association {
sctp_transport_t *primary_path; sctp_transport_t *primary_path;
/* Cache the primary path address here, when we /* Cache the primary path address here, when we
* need a an address for msg_name. * need a an address for msg_name.
*/ */
sockaddr_storage_t primary_addr; sockaddr_storage_t primary_addr;
/* active_path /* active_path
* The path that we are currently using to * The path that we are currently using to
* transmit new data and most control chunks. * transmit new data and most control chunks.
...@@ -1258,7 +1259,7 @@ struct SCTP_association { ...@@ -1258,7 +1259,7 @@ struct SCTP_association {
/* Overall : The threshold for this association that if /* Overall : The threshold for this association that if
* Error : the Overall Error Count reaches will cause * Error : the Overall Error Count reaches will cause
* Threshold : this association to be torn down. * Threshold : this association to be torn down.
*/ */
int overall_error_threshold; int overall_error_threshold;
...@@ -1304,13 +1305,13 @@ struct SCTP_association { ...@@ -1304,13 +1305,13 @@ struct SCTP_association {
*/ */
__u32 next_tsn; __u32 next_tsn;
/* /*
* Last Rcvd : This is the last TSN received in sequence. This value * Last Rcvd : This is the last TSN received in sequence. This value
* TSN : is set initially by taking the peer's Initial TSN, * TSN : is set initially by taking the peer's Initial TSN,
* : received in the INIT or INIT ACK chunk, and * : received in the INIT or INIT ACK chunk, and
* : subtracting one from it. * : subtracting one from it.
* *
* Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point.
*/ */
__u32 ctsn_ack_point; __u32 ctsn_ack_point;
......
...@@ -189,6 +189,35 @@ struct udp_mib ...@@ -189,6 +189,35 @@ struct udp_mib
unsigned long __pad[0]; unsigned long __pad[0];
} ____cacheline_aligned; } ____cacheline_aligned;
/* draft-ietf-sigtran-sctp-mib-07.txt */
struct sctp_mib
{
unsigned long SctpCurrEstab;
unsigned long SctpActiveEstabs;
unsigned long SctpPassiveEstabs;
unsigned long SctpAborteds;
unsigned long SctpShutdowns;
unsigned long SctpOutOfBlues;
unsigned long SctpChecksumErrors;
unsigned long SctpOutCtrlChunks;
unsigned long SctpOutOrderChunks;
unsigned long SctpOutUnorderChunks;
unsigned long SctpInCtrlChunks;
unsigned long SctpInOrderChunks;
unsigned long SctpInUnorderChunks;
unsigned long SctpFragUsrMsgs;
unsigned long SctpReasmUsrMsgs;
unsigned long SctpOutSCTPPacks;
unsigned long SctpInSCTPPacks;
unsigned long SctpRtoAlgorithm;
unsigned long SctpRtoMin;
unsigned long SctpRtoMax;
unsigned long SctpRtoInitial;
unsigned long SctpValCookieLife;
unsigned long SctpMaxInitRetr;
unsigned long __pad[0];
} ____cacheline_aligned;
struct linux_mib struct linux_mib
{ {
unsigned long SyncookiesSent; unsigned long SyncookiesSent;
......
...@@ -208,7 +208,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -208,7 +208,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->ctsn_ack_point = asoc->next_tsn - 1; asoc->ctsn_ack_point = asoc->next_tsn - 1;
asoc->highest_sacked = asoc->ctsn_ack_point; asoc->highest_sacked = asoc->ctsn_ack_point;
asoc->last_cwr_tsn = asoc->ctsn_ack_point;
asoc->unack_data = 0; asoc->unack_data = 0;
SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n",
...@@ -404,6 +404,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -404,6 +404,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
sctp_transport_set_owner(peer, asoc); sctp_transport_set_owner(peer, asoc);
/* Cache a route for the transport. */
sctp_transport_route(peer, NULL);
/* If this is the first transport addr on this association, /* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU. * initialize the association PMTU to the peer's PMTU.
* If not and the current association PMTU is higher than the new * If not and the current association PMTU is higher than the new
...@@ -458,6 +461,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -458,6 +461,9 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
min(asoc->overall_error_threshold + peer->error_threshold, min(asoc->overall_error_threshold + peer->error_threshold,
asoc->max_retrans); asoc->max_retrans);
/* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1;
/* Initialize the peer's heartbeat interval based on the /* Initialize the peer's heartbeat interval based on the
* sock configured value. * sock configured value.
*/ */
...@@ -520,12 +526,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -520,12 +526,12 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
/* Record the transition on the transport. */ /* Record the transition on the transport. */
switch (command) { switch (command) {
case SCTP_TRANSPORT_UP: case SCTP_TRANSPORT_UP:
transport->state.active = 1; transport->active = 1;
spc_state = ADDRESS_AVAILABLE; spc_state = ADDRESS_AVAILABLE;
break; break;
case SCTP_TRANSPORT_DOWN: case SCTP_TRANSPORT_DOWN:
transport->state.active = 0; transport->active = 0;
spc_state = ADDRESS_UNREACHABLE; spc_state = ADDRESS_UNREACHABLE;
break; break;
...@@ -555,7 +561,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -555,7 +561,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, sctp_transport_t, transports); t = list_entry(pos, sctp_transport_t, transports);
if (!t->state.active) if (!t->active)
continue; continue;
if (!first || t->last_time_heard > first->last_time_heard) { if (!first || t->last_time_heard > first->last_time_heard) {
second = first; second = first;
...@@ -575,7 +581,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -575,7 +581,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
* [If the primary is active but not most recent, bump the most * [If the primary is active but not most recent, bump the most
* recently used transport.] * recently used transport.]
*/ */
if (asoc->peer.primary_path->state.active && if (asoc->peer.primary_path->active &&
first != asoc->peer.primary_path) { first != asoc->peer.primary_path) {
second = first; second = first;
first = asoc->peer.primary_path; first = asoc->peer.primary_path;
...@@ -1015,7 +1021,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) ...@@ -1015,7 +1021,7 @@ sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
/* Try to find an active transport. */ /* Try to find an active transport. */
if (t->state.active) { if (t->active) {
break; break;
} else { } else {
/* Keep track of the next transport in case /* Keep track of the next transport in case
......
...@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) ...@@ -196,18 +196,16 @@ int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr)
* *
* The second argument is the return value for the length. * The second argument is the return value for the length.
*/ */
sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
int priority) int *addrs_len, int priority)
{ {
sctpParam_t addrparms; union sctp_params addrparms;
sctpParam_t retval; union sctp_params retval;
int addrparms_len; int addrparms_len;
sctp_addr_param_t rawaddr; sctp_addr_param_t rawaddr;
int len; int len;
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
struct list_head *pos; struct list_head *pos;
retval.v = NULL;
addrparms_len = 0; addrparms_len = 0;
len = 0; len = 0;
...@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, ...@@ -216,11 +214,11 @@ sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len,
len += sizeof(sctp_addr_param_t); len += sizeof(sctp_addr_param_t);
} }
addrparms.v = kmalloc(len, priority); retval.v = kmalloc(len, priority);
if (!addrparms.v) if (!retval.v)
goto end_raw; goto end_raw;
retval = addrparms; addrparms = retval;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sockaddr_storage_list, list);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -217,8 +218,8 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -217,8 +218,8 @@ int sctp_rcv(struct sk_buff *skb)
/* Remember the SCTP header. */ /* Remember the SCTP header. */
chunk->sctp_hdr = sh; chunk->sctp_hdr = sh;
/* Set the source address. */ /* Set the source and destination addresses of the incoming chunk. */
sctp_init_source(chunk); sctp_init_addrs(chunk);
/* Remember where we came from. */ /* Remember where we came from. */
chunk->transport = transport; chunk->transport = transport;
...@@ -567,7 +568,7 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr, ...@@ -567,7 +568,7 @@ sctp_association_t *sctp_lookup_association(const sockaddr_storage_t *laddr,
sctp_local_bh_disable(); sctp_local_bh_disable();
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
sctp_local_bh_enable(); sctp_local_bh_enable();
return asoc; return asoc;
} }
...@@ -613,13 +614,11 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, ...@@ -613,13 +614,11 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
sockaddr_storage_t *paddr = &addr; sockaddr_storage_t *paddr = &addr;
struct sctphdr *sh = (struct sctphdr *) skb->h.raw; struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
sctp_chunkhdr_t *ch; sctp_chunkhdr_t *ch;
__u8 *ch_end, *data; union sctp_params params;
sctp_paramhdr_t *parm; sctp_init_chunk_t *init;
ch = (sctp_chunkhdr_t *) skb->data; ch = (sctp_chunkhdr_t *) skb->data;
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* If this is INIT/INIT-ACK look inside the chunk too. */ /* If this is INIT/INIT-ACK look inside the chunk too. */
switch (ch->type) { switch (ch->type) {
case SCTP_CID_INIT: case SCTP_CID_INIT:
...@@ -645,24 +644,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, ...@@ -645,24 +644,17 @@ static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb,
/* Find the start of the TLVs and the end of the chunk. This is /* Find the start of the TLVs and the end of the chunk. This is
* the region we search for address parameters. * the region we search for address parameters.
*/ */
data = skb->data + sizeof(sctp_init_chunk_t); init = (sctp_init_chunk_t *)skb->data;
/* See sctp_process_init() for how to go thru TLVs. */
while (data < ch_end) {
parm = (sctp_paramhdr_t *)data;
if (!parm->length)
break;
data += WORD_ROUND(ntohs(parm->length)); /* Walk the parameters looking for embedded addresses. */
sctp_walk_params(params, init, init_hdr.params) {
/* Note: Ignoring hostname addresses. */ /* Note: Ignoring hostname addresses. */
if ((SCTP_PARAM_IPV4_ADDRESS != parm->type) && if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) &&
(SCTP_PARAM_IPV6_ADDRESS != parm->type)) (SCTP_PARAM_IPV6_ADDRESS != params.p->type))
continue; continue;
sctp_param2sockaddr(paddr, (sctp_addr_param_t *)parm, sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source));
ntohs(sh->source));
asoc = __sctp_lookup_association(laddr, paddr, transportp); asoc = __sctp_lookup_association(laddr, paddr, transportp);
if (asoc) if (asoc)
return asoc; return asoc;
......
...@@ -158,35 +158,60 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -158,35 +158,60 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
} }
#endif /* TEST_FRAME */ #endif /* TEST_FRAME */
/* Returns the mtu for the given v6 destination address. */ /* FIXME: This macro needs to be moved to a common header file. */
int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) #define NIP6(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr,
sockaddr_storage_t *saddr)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl; struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr,
int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; } } };
fl.proto = 0;
fl.fl6_dst = (struct in6_addr *)&address->v6.sin6_addr; SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
fl.fl6_src = NULL; __FUNCTION__, NIP6(fl.fl6_dst));
fl.fl6_flowlabel = 0;
fl.oif = 0; if (saddr) {
fl.uli_u.ports.sport = 0; fl.fl6_src = &saddr->v6.sin6_addr;
fl.uli_u.ports.dport = 0; SCTP_DEBUG_PRINTK(
"SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
NIP6(fl.fl6_src));
}
dst = ip6_route_output(NULL, &fl); dst = ip6_route_output(NULL, &fl);
if (dst) { if (dst) {
dst_mtu = dst_pmtu(dst); struct rt6_info *rt;
SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " rt = (struct rt6_info *)dst;
"ip6_route_output: dev:%s pmtu:%d\n", SCTP_DEBUG_PRINTK(
dst->dev->name, dst_mtu); "rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
dst_release(dst); "rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
NIP6(&rt->rt6i_dst.addr), NIP6(&rt->rt6i_src.addr));
} else { } else {
SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " SCTP_DEBUG_PRINTK("NO ROUTE\n");
"ip6_route_output failed, returning " return NULL;
"%d as dst_mtu\n", dst_mtu);
} }
return dst_mtu; return dst;
}
/* Check if the dst entry's source addr matches the given source addr. */
int sctp_v6_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr)
{
struct rt6_info *rt = (struct rt6_info *)dst;
return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr);
} }
/* Initialize a PF_INET6 socket msg_name. */ /* Initialize a PF_INET6 socket msg_name. */
...@@ -301,7 +326,8 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -301,7 +326,8 @@ static sctp_func_t sctp_ipv6_specific = {
.queue_xmit = sctp_v6_xmit, .queue_xmit = sctp_v6_xmit,
.setsockopt = ipv6_setsockopt, .setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt, .getsockopt = ipv6_getsockopt,
.get_dst_mtu = sctp_v6_get_dst_mtu, .get_dst = sctp_v6_get_dst,
.cmp_saddr = sctp_v6_cmp_saddr,
.net_header_len = sizeof(struct ipv6hdr), .net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6), .sockaddr_len = sizeof(struct sockaddr_in6),
.sa_family = AF_INET6, .sa_family = AF_INET6,
......
...@@ -245,6 +245,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -245,6 +245,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
int err = 0; int err = 0;
int padding; /* How much padding do we need? */ int padding; /* How much padding do we need? */
__u8 packet_has_data = 0; __u8 packet_has_data = 0;
struct dst_entry *dst;
/* Do NOT generate a chunkless packet... */ /* Do NOT generate a chunkless packet... */
if (skb_queue_empty(&packet->chunks)) if (skb_queue_empty(&packet->chunks))
...@@ -410,13 +411,6 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -410,13 +411,6 @@ int sctp_packet_transmit(sctp_packet_t *packet)
asoc->peer.last_sent_to = transport; asoc->peer.last_sent_to = transport;
} }
/* Hey, before Linux changes, here's what we have to
* do to force IP routing to recognize the change of
* dest addr. --xguo
*/
if (sk->dst_cache)
sk->dst_cache->obsolete = 1;
if (packet_has_data) { if (packet_has_data) {
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
...@@ -434,6 +428,13 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -434,6 +428,13 @@ int sctp_packet_transmit(sctp_packet_t *packet)
} }
} }
dst = transport->dst;
if (!dst || dst->obsolete) {
sctp_transport_route(transport, NULL);
}
nskb->dst = dst_clone(transport->dst);
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
nskb->len); nskb->len);
(*transport->af_specific->queue_xmit)(nskb); (*transport->af_specific->queue_xmit)(nskb);
......
...@@ -204,18 +204,43 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) ...@@ -204,18 +204,43 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
return error; return error;
} }
/* Insert a chunk into the retransmit queue. Chunks on the retransmit
* queue are kept in order, based on the TSNs.
*/
void sctp_retransmit_insert(struct list_head *tlchunk, sctp_outqueue_t *q)
{
struct list_head *rlchunk;
sctp_chunk_t *tchunk, *rchunk;
__u32 ttsn, rtsn;
int done = 0;
tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list);
ttsn = ntohl(tchunk->subh.data_hdr->tsn);
list_for_each(rlchunk, &q->retransmit) {
rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list);
rtsn = ntohl(rchunk->subh.data_hdr->tsn);
if (TSN_lt(ttsn, rtsn)) {
list_add(tlchunk, rlchunk->prev);
done = 1;
break;
}
}
if (!done) {
list_add_tail(tlchunk, &q->retransmit);
}
}
/* Mark all the eligible packets on a transport for retransmission. */ /* Mark all the eligible packets on a transport for retransmission. */
void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport, void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
struct list_head *lchunk; struct list_head *lchunk, *ltemp;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
struct list_head tlist;
INIT_LIST_HEAD(&tlist);
while (!list_empty(&transport->transmitted)) { /* Walk through the specified transmitted queue. */
lchunk = sctp_list_dequeue(&transport->transmitted); list_for_each_safe(lchunk, ltemp, &transport->transmitted) {
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
/* If we are doing retransmission due to a fast retransmit, /* If we are doing retransmission due to a fast retransmit,
...@@ -224,10 +249,8 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport, ...@@ -224,10 +249,8 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
* retransmission due to a timeout, only the chunks that are * retransmission due to a timeout, only the chunks that are
* not yet acked should be added to the retransmit queue. * not yet acked should be added to the retransmit queue.
*/ */
if ((fast_retransmit && !chunk->fast_retransmit) || if ((fast_retransmit && chunk->fast_retransmit) ||
(!fast_retransmit && chunk->tsn_gap_acked)) { (!fast_retransmit && !chunk->tsn_gap_acked)) {
list_add_tail(lchunk, &tlist);
} else {
/* RFC 2960 6.2.1 Processing a Received SACK /* RFC 2960 6.2.1 Processing a Received SACK
* *
* C) Any time a DATA chunk is marked for * C) Any time a DATA chunk is marked for
...@@ -257,16 +280,15 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport, ...@@ -257,16 +280,15 @@ void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
chunk->rtt_in_progress = 0; chunk->rtt_in_progress = 0;
transport->rto_pending = 0; transport->rto_pending = 0;
} }
list_add_tail(lchunk, &q->retransmit);
/* Move the chunk to the retransmit queue. The chunks
* on the retransmit queue is always kept in order.
*/
list_del(lchunk);
sctp_retransmit_insert(lchunk, q);
} }
} }
/* Reconstruct the transmitted queue with chunks that are not
* eligible for retransmission.
*/
while (NULL != (lchunk = sctp_list_dequeue(&tlist)))
list_add_tail(lchunk, &transport->transmitted);
SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, " SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, "
"cwnd: %d, ssthresh: %d, flight_size: %d, " "cwnd: %d, ssthresh: %d, flight_size: %d, "
"pba: %d\n", __FUNCTION__, "pba: %d\n", __FUNCTION__,
...@@ -656,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -656,7 +678,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if (!new_transport) { if (!new_transport) {
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
} else if (!new_transport->state.active) { } else if (!new_transport->active) {
/* If the chunk is Heartbeat, send it to /* If the chunk is Heartbeat, send it to
* chunk->transport, even it's inactive. * chunk->transport, even it's inactive.
*/ */
...@@ -813,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -813,7 +835,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/ */
new_transport = chunk->transport; new_transport = chunk->transport;
if (new_transport == NULL || if (new_transport == NULL ||
!new_transport->state.active) !new_transport->active)
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
/* Change packets if necessary. */ /* Change packets if necessary. */
...@@ -1382,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1382,7 +1404,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* Mark the destination transport address as /* Mark the destination transport address as
* active if it is not so marked. * active if it is not so marked.
*/ */
if (!transport->state.active) { if (!transport->active) {
sctp_assoc_control_transport( sctp_assoc_control_transport(
transport->asoc, transport->asoc,
transport, transport,
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Narasimha Budihal <narasimha@refcode.org> * Narasimha Budihal <narasimha@refcode.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT); ...@@ -181,6 +182,28 @@ DECLARE_PRIMITIVE(ABORT);
DECLARE_PRIMITIVE(SEND); DECLARE_PRIMITIVE(SEND);
/* 10.1 ULP-to-SCTP
* J) Request Heartbeat
*
* Format: REQUESTHEARTBEAT(association id, destination transport address)
*
* -> result
*
* Instructs the local endpoint to perform a HeartBeat on the specified
* destination transport address of the given association. The returned
* result should indicate whether the transmission of the HEARTBEAT
* chunk to the destination address is successful.
*
* Mandatory attributes:
*
* o association id - local handle to the SCTP association
*
* o destination transport address - the transport address of the
* asociation on which a heartbeat should be issued.
*/
DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
/* COMMENT BUG. Find out where this is mentioned in the spec. */ /* COMMENT BUG. Find out where this is mentioned in the spec. */
int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg)
{ {
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
/* Global data structures. */ /* Global data structures. */
sctp_protocol_t sctp_proto; sctp_protocol_t sctp_proto;
struct proc_dir_entry *proc_net_sctp; struct proc_dir_entry *proc_net_sctp;
struct sctp_mib sctp_statistics[NR_CPUS * 2];
/* This is the global socket data structure used for responding to /* This is the global socket data structure used for responding to
* the Out-of-the-blue (OOTB) packets. A control sock will be created * the Out-of-the-blue (OOTB) packets. A control sock will be created
...@@ -255,27 +256,41 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, ...@@ -255,27 +256,41 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
return error; return error;
} }
/* Returns the mtu for the given v4 destination address. */ /* Returns the dst cache entry for the given source and destination ip
int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) * addresses.
*/
struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr,
sockaddr_storage_t *saddr)
{ {
int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
struct rtable *rt; struct rtable *rt;
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = { .nl_u = { .ip4_u = { .daddr =
{ .daddr = address->v4.sin_addr.s_addr } } }; daddr->v4.sin_addr.s_addr,
} } };
if (saddr)
fl.fl4_src = saddr->v4.sin_addr.s_addr;
SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
__FUNCTION__, NIPQUAD(fl.fl4_dst),
NIPQUAD(fl.fl4_src));
if (ip_route_output_key(&rt, &fl)) { if (ip_route_output_key(&rt, &fl)) {
SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key" SCTP_DEBUG_PRINTK("NO ROUTE\n");
" failed, returning %d as dst_mtu\n", return NULL;
dst_mtu);
} else {
dst_mtu = dst_pmtu(&rt->u.dst);
SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: "
"ip_route_output_key: dev:%s pmtu:%d\n",
rt->u.dst.dev->name, dst_mtu);
ip_rt_put(rt);
} }
return dst_mtu; SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
NIPQUAD(rt->rt_src), NIPQUAD(rt->rt_dst));
return &rt->u.dst;
}
/* Check if the dst entry's source addr matches the given source addr. */
int sctp_v4_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr)
{
struct rtable *rt = (struct rtable *)dst;
return (rt->rt_src == saddr->v4.sin_addr.s_addr);
} }
/* Event handler for inet device events. /* Event handler for inet device events.
...@@ -437,7 +452,8 @@ sctp_func_t sctp_ipv4_specific = { ...@@ -437,7 +452,8 @@ sctp_func_t sctp_ipv4_specific = {
.queue_xmit = ip_queue_xmit, .queue_xmit = ip_queue_xmit,
.setsockopt = ip_setsockopt, .setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt, .getsockopt = ip_getsockopt,
.get_dst_mtu = sctp_v4_get_dst_mtu, .get_dst = sctp_v4_get_dst,
.cmp_saddr = sctp_v4_cmp_saddr,
.net_header_len = sizeof(struct iphdr), .net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in), .sockaddr_len = sizeof(struct sockaddr_in),
.sa_family = AF_INET, .sa_family = AF_INET,
......
This diff is collapsed.
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Dajiang Zhang <dajiang.zhang@nokia.com> * Dajiang Zhang <dajiang.zhang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -66,12 +67,15 @@ static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, ...@@ -66,12 +67,15 @@ static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
sctp_transport_t *transport); sctp_transport_t *transport);
static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_event_t event_type, sctp_chunk_t *chunk);
static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
sctp_init_chunk_t *peer_init, sctp_init_chunk_t *peer_init,
int priority); int priority);
static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *);
static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *, sctp_association_t *,
sctp_transport_t *);
static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *,
sctp_bind_addr_t *); sctp_bind_addr_t *);
static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *,
...@@ -192,6 +196,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -192,6 +196,7 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
/* BUG--we should now recover some memory, probably by /* BUG--we should now recover some memory, probably by
* reneging... * reneging...
*/ */
error = -ENOMEM;
break; break;
case SCTP_DISPOSITION_DELETE_TCB: case SCTP_DISPOSITION_DELETE_TCB:
...@@ -251,7 +256,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -251,7 +256,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
int force; int force;
sctp_cmd_t *command; sctp_cmd_t *command;
sctp_chunk_t *new_obj; sctp_chunk_t *new_obj;
sctp_chunk_t *chunk; sctp_chunk_t *chunk = NULL;
sctp_packet_t *packet; sctp_packet_t *packet;
struct list_head *pos; struct list_head *pos;
struct timer_list *timer; struct timer_list *timer;
...@@ -259,7 +264,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -259,7 +264,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_transport_t *t; sctp_transport_t *t;
sctp_sackhdr_t sackh; sctp_sackhdr_t sackh;
chunk = (sctp_chunk_t *) event_arg; if(SCTP_EVENT_T_TIMEOUT != event_type)
chunk = (sctp_chunk_t *) event_arg;
/* Note: This whole file is a huge candidate for rework. /* Note: This whole file is a huge candidate for rework.
* For example, each command could either have its own handler, so * For example, each command could either have its own handler, so
...@@ -504,7 +510,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -504,7 +510,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_ASSOC_FAILED: case SCTP_CMD_ASSOC_FAILED:
sctp_cmd_assoc_failed(commands, asoc); sctp_cmd_assoc_failed(commands, asoc, event_type,
chunk);
break; break;
case SCTP_CMD_COUNTER_INC: case SCTP_CMD_COUNTER_INC:
...@@ -557,6 +564,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -557,6 +564,11 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_HB_TIMERS_START: case SCTP_CMD_HB_TIMERS_START:
sctp_cmd_hb_timers_start(commands, asoc); sctp_cmd_hb_timers_start(commands, asoc);
break; break;
case SCTP_CMD_HB_TIMERS_UPDATE:
t = command->obj.transport;
sctp_cmd_hb_timers_update(commands, asoc, t);
break;
case SCTP_CMD_REPORT_ERROR: case SCTP_CMD_REPORT_ERROR:
error = command->obj.error; error = command->obj.error;
...@@ -595,10 +607,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -595,10 +607,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
/* A helper function for delayed processing of INET ECN CE bit. */ /* A helper function for delayed processing of INET ECN CE bit. */
static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
{ {
/* /* Save the TSN away for comparison when we receive CWR */
* Save the TSN away for comparison when we receive CWR
* Note: dp->TSN is expected in host endian
*/
asoc->last_ecne_tsn = lowest_tsn; asoc->last_ecne_tsn = lowest_tsn;
asoc->need_ecne = 1; asoc->need_ecne = 1;
...@@ -621,7 +630,6 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, ...@@ -621,7 +630,6 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
sctp_chunk_t *chunk) sctp_chunk_t *chunk)
{ {
sctp_chunk_t *repl; sctp_chunk_t *repl;
sctp_transport_t *transport;
/* Our previously transmitted packet ran into some congestion /* Our previously transmitted packet ran into some congestion
* so we should take action by reducing cwnd and ssthresh * so we should take action by reducing cwnd and ssthresh
...@@ -629,43 +637,28 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, ...@@ -629,43 +637,28 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
* sending a CWR. * sending a CWR.
*/ */
/* Find which transport's congestion variables /* First, try to determine if we want to actually lower
* need to be adjusted. * our cwnd variables. Only lower them if the ECNE looks more
* recent than the last response.
*/ */
if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
sctp_transport_t *transport;
transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn); /* Find which transport's congestion variables
* need to be adjusted.
*/
transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
/* Update the congestion variables. */ /* Update the congestion variables. */
if (transport) if (transport)
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE); sctp_transport_lower_cwnd(transport,
SCTP_LOWER_CWND_ECNE);
asoc->last_cwr_tsn = lowest_tsn;
}
/* Save away a rough idea of when we last sent out a CWR. /* Always try to quiet the other end. In case of lost CWR,
* We compare against this value (see above) to decide if * resend last_cwr_tsn.
* this is a fairly new request.
* Note that this is not a perfect solution. We may
* have moved beyond the window (several times) by the
* next time we get an ECNE. However, it is cute. This idea
* came from Randy's reference code.
*
* Here's what RFC 2960 has to say about CWR. This is NOT
* what we do.
*
* RFC 2960 Appendix A
*
* CWR:
*
* RFC 2481 details a specific bit for a sender to send in
* the header of its next outbound TCP segment to indicate
* to its peer that it has reduced its congestion window.
* This is termed the CWR bit. For SCTP the same
* indication is made by including the CWR chunk. This
* chunk contains one data element, i.e. the TSN number
* that was sent in the ECNE chunk. This element
* represents the lowest TSN number in the datagram that
* was originally marked with the CE bit.
*/ */
asoc->last_cwr_tsn = asoc->next_tsn - 1;
repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
/* If we run out of memory, it will look like a lost CWR. We'll /* If we run out of memory, it will look like a lost CWR. We'll
...@@ -994,7 +987,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, ...@@ -994,7 +987,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
*/ */
asoc->overall_error_count++; asoc->overall_error_count++;
if (transport->state.active && if (transport->active &&
(transport->error_count++ >= transport->error_threshold)) { (transport->error_count++ >= transport->error_threshold)) {
SCTP_DEBUG_PRINTK("transport_strike: transport " SCTP_DEBUG_PRINTK("transport_strike: transport "
"IP:%d.%d.%d.%d failed.\n", "IP:%d.%d.%d.%d failed.\n",
...@@ -1038,14 +1031,26 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, ...@@ -1038,14 +1031,26 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */ /* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */
static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_association_t *asoc) sctp_association_t *asoc,
sctp_event_t event_type,
sctp_chunk_t *chunk)
{ {
sctp_ulpevent_t *event; sctp_ulpevent_t *event;
__u16 error = 0;
if (event_type == SCTP_EVENT_T_PRIMITIVE)
error = SCTP_ERROR_USER_ABORT;
if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
(ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) +
sizeof(struct sctp_errhdr)))) {
error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
}
event = sctp_ulpevent_make_assoc_change(asoc, event = sctp_ulpevent_make_assoc_change(asoc,
0, 0,
SCTP_COMM_LOST, SCTP_COMM_LOST,
0, 0, 0, error, 0, 0,
GFP_ATOMIC); GFP_ATOMIC);
if (event) if (event)
...@@ -1100,6 +1105,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, ...@@ -1100,6 +1105,16 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
} }
} }
/* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timers_update(sctp_cmd_seq_t *cmds,
sctp_association_t *asoc,
sctp_transport_t *t)
{
/* Update the heartbeat timer. */
if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies))
sctp_transport_hold(t);
}
/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ /* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */
void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
sctp_bind_addr_t *bp) sctp_bind_addr_t *bp)
...@@ -1135,7 +1150,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, ...@@ -1135,7 +1150,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
/* Mark the destination transport address as active if it is not so /* Mark the destination transport address as active if it is not so
* marked. * marked.
*/ */
if (!t->state.active) if (!t->active)
sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
SCTP_HEARTBEAT_SUCCESS); SCTP_HEARTBEAT_SUCCESS);
...@@ -1158,10 +1173,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, ...@@ -1158,10 +1173,6 @@ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
/* Mark one strike against a transport. */ /* Mark one strike against a transport. */
sctp_do_8_2_transport_strike(asoc, t); sctp_do_8_2_transport_strike(asoc, t);
/* Update the heartbeat timer. */
if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies))
sctp_transport_hold(t);
} }
/* Helper function to process the process SACK command. */ /* Helper function to process the process SACK command. */
......
This diff is collapsed.
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { ...@@ -706,21 +707,28 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ #define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
......
...@@ -804,10 +804,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -804,10 +804,12 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
msg_len, sinfo_flags); msg_len, sinfo_flags);
/* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow /* If MSG_EOF is set, no data can be sent. Disallow sending zero
* sending 0-length messages when MSG_EOF|MSG_ABORT is not set. * length messages when MSG_EOF|MSG_ABORT is not set.
*/ * If MSG_ABORT is set, the message length could be non zero with
if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) || * the msg_iov set to the user abort reason.
*/
if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) ||
(!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) {
err = -EINVAL; err = -EINVAL;
goto out_nounlock; goto out_nounlock;
...@@ -879,7 +881,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -879,7 +881,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} }
if (sinfo_flags & MSG_ABORT) { if (sinfo_flags & MSG_ABORT) {
SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc); SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
sctp_primitive_ABORT(asoc, NULL); sctp_primitive_ABORT(asoc, msg);
err = 0; err = 0;
goto out_unlock; goto out_unlock;
} }
...@@ -1238,6 +1240,9 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1238,6 +1240,9 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
{ {
sctp_opt_t *sp = sctp_sk(sk); sctp_opt_t *sp = sctp_sk(sk);
/* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sp->type)
return -EOPNOTSUPP;
if (optlen != sizeof(int)) if (optlen != sizeof(int))
return -EINVAL; return -EINVAL;
if (copy_from_user(&sp->autoclose, optval, optlen)) if (copy_from_user(&sp->autoclose, optval, optlen))
...@@ -1247,6 +1252,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1247,6 +1252,67 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return 0; return 0;
} }
static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
char *optval,
int optlen)
{
struct sctp_paddrparams params;
sctp_association_t *asoc;
sockaddr_storage_t *addr;
sctp_transport_t *trans;
int error;
if (optlen != sizeof(struct sctp_paddrparams))
return -EINVAL;
if (copy_from_user(&params, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id);
if (!asoc)
return -EINVAL;
addr = (sockaddr_storage_t *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans)
return -ENOENT;
/* Applications can enable or disable heartbeats for any peer address
* of an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable.
*
* The value of the heartbeat interval, in milliseconds. A value of
* UINT32_MAX (4294967295), when modifying the parameter, specifies
* that a heartbeat should be sent immediately to the peer address,
* and the current interval should remain unchanged.
*/
if (0xffffffff == params.spp_hbinterval) {
error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans);
if (error)
return error;
}
else {
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
* address should be disabled.
*/
if (params.spp_hbinterval) {
trans->hb_allowed = 1;
trans->hb_interval = params.spp_hbinterval * HZ / 1000;
} else
trans->hb_allowed = 0;
}
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
trans->error_threshold = params.spp_pathmaxrxt;
return 0;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -1337,6 +1403,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1337,6 +1403,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_autoclose(sk, optval, optlen); retval = sctp_setsockopt_autoclose(sk, optval, optlen);
break; break;
case SCTP_SET_PEER_ADDR_PARAMS:
retval = sctp_setsockopt_set_peer_addr_params(sk, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -1498,28 +1569,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1498,28 +1569,26 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (len != sizeof(status)) { if (len != sizeof(status)) {
retval = -EINVAL; retval = -EINVAL;
goto out_nounlock; goto out;
} }
if (copy_from_user(&status, optval, sizeof(status))) { if (copy_from_user(&status, optval, sizeof(status))) {
retval = -EFAULT; retval = -EFAULT;
goto out_nounlock; goto out;
} }
sctp_lock_sock(sk);
associd = status.sstat_assoc_id; associd = status.sstat_assoc_id;
if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) { if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) {
assoc = sctp_id2assoc(sk, associd); assoc = sctp_id2assoc(sk, associd);
if (!assoc) { if (!assoc) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
} else { } else {
ep = sctp_sk(sk)->ep; ep = sctp_sk(sk)->ep;
if (list_empty(&ep->asocs)) { if (list_empty(&ep->asocs)) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); assoc = list_entry(ep->asocs.next, sctp_association_t, asocs);
...@@ -1538,7 +1607,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1538,7 +1607,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
memcpy(&status.sstat_primary.spinfo_address, memcpy(&status.sstat_primary.spinfo_address,
&(transport->ipaddr), sizeof(sockaddr_storage_t)); &(transport->ipaddr), sizeof(sockaddr_storage_t));
status.sstat_primary.spinfo_state = transport->state.active; status.sstat_primary.spinfo_state = transport->active;
status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_cwnd = transport->cwnd;
status.sstat_primary.spinfo_srtt = transport->srtt; status.sstat_primary.spinfo_srtt = transport->srtt;
status.sstat_primary.spinfo_rto = transport->rto; status.sstat_primary.spinfo_rto = transport->rto;
...@@ -1546,7 +1615,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1546,7 +1615,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (put_user(len, optlen)) { if (put_user(len, optlen)) {
retval = -EFAULT; retval = -EFAULT;
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n",
...@@ -1555,13 +1624,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1555,13 +1624,10 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
if (copy_to_user(optval, &status, len)) { if (copy_to_user(optval, &status, len)) {
retval = -EFAULT; retval = -EFAULT;
goto out_unlock; goto out;
} }
out_unlock: out:
sctp_release_sock(sk);
out_nounlock:
return (retval); return (retval);
} }
...@@ -1593,6 +1659,9 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt ...@@ -1593,6 +1659,9 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt
static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
{ {
/* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sctp_sk(sk)->type)
return -EOPNOTSUPP;
if (len != sizeof(int)) if (len != sizeof(int))
return -EINVAL; return -EINVAL;
if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len))
...@@ -1614,10 +1683,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso ...@@ -1614,10 +1683,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
int err = 0; int err = 0;
/* An association cannot be branched off from an already peeled-off /* An association cannot be branched off from an already peeled-off
* socket. * socket, nor is this supported for tcp style sockets.
*/ */
if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type) if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type)
return -EINVAL; return -EOPNOTSUPP;
/* Create a new socket. */ /* Create a new socket. */
err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock); err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock);
...@@ -1676,25 +1745,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval ...@@ -1676,25 +1745,23 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if (copy_from_user(&peeloff, optval, len)) if (copy_from_user(&peeloff, optval, len))
return -EFAULT; return -EFAULT;
sctp_lock_sock(sk);
assoc = sctp_id2assoc(sk, peeloff.associd); assoc = sctp_id2assoc(sk, peeloff.associd);
if (NULL == assoc) { if (NULL == assoc) {
retval = -EINVAL; retval = -EINVAL;
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc);
retval = sctp_do_peeloff(assoc, &newsock); retval = sctp_do_peeloff(assoc, &newsock);
if (retval < 0) if (retval < 0)
goto out_unlock; goto out;
/* Map the socket to an unused fd that can be returned to the user. */ /* Map the socket to an unused fd that can be returned to the user. */
retval = sock_map_fd(newsock); retval = sock_map_fd(newsock);
if (retval < 0) { if (retval < 0) {
sock_release(newsock); sock_release(newsock);
goto out_unlock; goto out;
} }
SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n",
...@@ -1705,11 +1772,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval ...@@ -1705,11 +1772,54 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
if (copy_to_user(optval, &peeloff, len)) if (copy_to_user(optval, &peeloff, len))
retval = -EFAULT; retval = -EFAULT;
out_unlock: out:
sctp_release_sock(sk);
return retval; return retval;
} }
static inline int sctp_getsockopt_get_peer_addr_params(struct sock *sk,
int len, char *optval, int *optlen)
{
struct sctp_paddrparams params;
sctp_association_t *asoc;
sockaddr_storage_t *addr;
sctp_transport_t *trans;
if (len != sizeof(struct sctp_paddrparams))
return -EINVAL;
if (copy_from_user(&params, optval, *optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id);
if (!asoc)
return -EINVAL;
addr = (sockaddr_storage_t *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans)
return -ENOENT;
/* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this
* address should be disabled.
*/
if (!trans->hb_allowed)
params.spp_hbinterval = 0;
else
params.spp_hbinterval = trans->hb_interval * 1000 / HZ;
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
params.spp_pathmaxrxt = trans->error_threshold;
if (copy_to_user(optval, &params, len))
return -EFAULT;
*optlen = len;
return 0;
}
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
...@@ -1740,6 +1850,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1740,6 +1850,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; return -EFAULT;
sctp_lock_sock(sk);
switch (optname) { switch (optname) {
case SCTP_STATUS: case SCTP_STATUS:
retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen);
...@@ -1762,11 +1874,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1762,11 +1874,17 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); retval = sctp_getsockopt_peeloff(sk, len, optval, optlen);
break; break;
case SCTP_GET_PEER_ADDR_PARAMS:
retval = sctp_getsockopt_get_peer_addr_params(sk, len, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
}; };
sctp_release_sock(sk);
return retval; return retval;
} }
......
...@@ -87,7 +87,6 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, ...@@ -87,7 +87,6 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
peer->ipaddr = *addr; peer->ipaddr = *addr;
peer->af_specific = sctp_get_af_specific(addr); peer->af_specific = sctp_get_af_specific(addr);
peer->asoc = NULL; peer->asoc = NULL;
peer->pmtu = peer->af_specific->get_dst_mtu(addr);
/* From 6.3.1 RTO Calculation: /* From 6.3.1 RTO Calculation:
* *
...@@ -105,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, ...@@ -105,8 +104,8 @@ sctp_transport_t *sctp_transport_init(sctp_transport_t *peer,
peer->last_time_used = jiffies; peer->last_time_used = jiffies;
peer->last_time_ecne_reduced = jiffies; peer->last_time_ecne_reduced = jiffies;
peer->state.active = 1; peer->active = 1;
peer->state.hb_allowed = 0; peer->hb_allowed = 0;
/* Initialize the default path max_retrans. */ /* Initialize the default path max_retrans. */
peer->max_retrans = proto->max_retrans_path; peer->max_retrans = proto->max_retrans_path;
...@@ -161,6 +160,7 @@ void sctp_transport_destroy(sctp_transport_t *transport) ...@@ -161,6 +160,7 @@ void sctp_transport_destroy(sctp_transport_t *transport)
if (transport->asoc) if (transport->asoc)
sctp_association_put(transport->asoc); sctp_association_put(transport->asoc);
dst_release(transport->dst);
kfree(transport); kfree(transport);
SCTP_DBG_OBJCNT_DEC(transport); SCTP_DBG_OBJCNT_DEC(transport);
} }
...@@ -200,6 +200,78 @@ void sctp_transport_set_owner(sctp_transport_t *transport, ...@@ -200,6 +200,78 @@ void sctp_transport_set_owner(sctp_transport_t *transport,
sctp_association_hold(asoc); sctp_association_hold(asoc);
} }
/* Caches the dst entry for a transport's destination address and an optional
* souce address.
*/
void sctp_transport_route(sctp_transport_t *transport,
sockaddr_storage_t *saddr)
{
sctp_association_t *asoc = transport->asoc;
sctp_func_t *af = transport->af_specific;
sockaddr_storage_t *daddr = &transport->ipaddr;
sctp_bind_addr_t *bp;
rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr;
struct list_head *pos;
struct dst_entry *dst;
dst = af->get_dst(daddr, saddr);
/* If there is no association or if a source address is passed,
* no more validation is required.
*/
if (!asoc || saddr)
goto out;
if (SCTP_STATE_ESTABLISHED == asoc->state) {
bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;
} else {
bp = &asoc->ep->base.bind_addr;
addr_lock = &asoc->ep->base.addr_lock;
}
if (dst) {
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list,
list);
if (af->cmp_saddr(dst, &laddr->a))
goto out_unlock;
}
sctp_read_unlock(addr_lock);
/* None of the bound addresses match the source address of the
* dst. So release it.
*/
dst_release(dst);
}
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source address.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list);
dst = af->get_dst(daddr, &laddr->a);
if (dst)
goto out_unlock;
}
out_unlock:
sctp_read_unlock(addr_lock);
out:
transport->dst = dst;
if (dst)
transport->pmtu = dst_pmtu(dst);
else
transport->pmtu = SCTP_DEFAULT_MAXSEGMENT;
}
/* Hold a reference to a transport. */ /* Hold a reference to a transport. */
void sctp_transport_hold(sctp_transport_t *transport) void sctp_transport_hold(sctp_transport_t *transport)
{ {
......
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