Commit a0065b2f authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge us.ibm.com:/home/sridhar/BK/linux-2.5.60

into us.ibm.com:/home/sridhar/BK/lksctp-2.5.60
parents f2478c00 9d6d6cb3
......@@ -69,11 +69,11 @@ typedef enum {
SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */
SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */
SCTP_CMD_REPORT_BIGGAP, /* Narc on a TSN (it was too high). */
SCTP_CMD_SET_BIND_ADDR, /* Set the association bind_addr. */
SCTP_CMD_STRIKE, /* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */
SCTP_CMD_HB_TIMERS_UPDATE, /* Update the heartbeat timers. */
SCTP_CMD_HB_TIMER_UPDATE, /* Update a heartbeat timers. */
SCTP_CMD_HB_TIMERS_STOP, /* Stop the heartbeat timers. */
SCTP_CMD_TRANSPORT_RESET, /* Reset the status of a transport. */
SCTP_CMD_TRANSPORT_ON, /* Mark the transport as active. */
SCTP_CMD_REPORT_ERROR, /* Pass this error back out of the sm. */
......@@ -112,7 +112,7 @@ typedef union {
void *ptr;
sctp_chunk_t *chunk;
sctp_association_t *asoc;
sctp_transport_t *transport;
struct sctp_transport *transport;
sctp_bind_addr_t *bp;
sctp_init_chunk_t *init;
sctp_ulpevent_t *ulpevent;
......@@ -160,7 +160,7 @@ SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to)
SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr)
SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk)
SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR(TRANSPORT, sctp_transport_t *, transport)
SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport)
SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp)
SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent)
......
......@@ -56,17 +56,10 @@
#include <linux/ipv6.h> /* For ipv6hdr. */
#include <net/sctp/user.h>
/* What a hack! Jiminy Cricket! */
enum { SCTP_MAX_STREAM = 10 };
/* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating
* for ipv6 headers, but this seems worth the simplicity.
*/
#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\
+ sizeof(struct ipv6hdr)\
+ MAX_HEADER))
/* Value used for stream negotiation. */
enum { SCTP_MAX_STREAM = 0xffff };
enum { SCTP_DEFAULT_OUTSTREAMS = 10 };
enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
/* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating
......@@ -105,57 +98,37 @@ typedef enum {
*/
typedef enum {
SCTP_EVENT_TIMEOUT_NONE = 0,
SCTP_EVENT_TIMEOUT_T1_COOKIE,
SCTP_EVENT_TIMEOUT_T1_INIT,
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN,
SCTP_EVENT_TIMEOUT_T3_RTX,
SCTP_EVENT_TIMEOUT_T4_RTO,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
SCTP_EVENT_TIMEOUT_HEARTBEAT,
SCTP_EVENT_TIMEOUT_SACK,
SCTP_EVENT_TIMEOUT_AUTOCLOSE,
SCTP_EVENT_TIMEOUT_PMTU_RAISE,
} sctp_event_timeout_t;
#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_PMTU_RAISE
#define SCTP_EVENT_TIMEOUT_MAX SCTP_EVENT_TIMEOUT_AUTOCLOSE
#define SCTP_NUM_TIMEOUT_TYPES (SCTP_EVENT_TIMEOUT_MAX + 1)
typedef enum {
SCTP_EVENT_NO_PENDING_TSN = 0,
SCTP_EVENT_ICMP_UNREACHFRAG,
} sctp_event_other_t;
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_ICMP_UNREACHFRAG
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_NO_PENDING_TSN
#define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1)
/* These are primitive requests from the ULP. */
typedef enum {
SCTP_PRIMITIVE_INITIALIZE = 0,
SCTP_PRIMITIVE_ASSOCIATE,
SCTP_PRIMITIVE_ASSOCIATE = 0,
SCTP_PRIMITIVE_SHUTDOWN,
SCTP_PRIMITIVE_ABORT,
SCTP_PRIMITIVE_SEND,
SCTP_PRIMITIVE_SETPRIMARY,
SCTP_PRIMITIVE_RECEIVE,
SCTP_PRIMITIVE_STATUS,
SCTP_PRIMITIVE_CHANGEHEARTBEAT,
SCTP_PRIMITIVE_REQUESTHEARTBEAT,
SCTP_PRIMITIVE_GETSRTTREPORT,
SCTP_PRIMITIVE_SETFAILURETHRESHOLD,
SCTP_PRIMITIVE_SETPROTOPARAMETERS,
SCTP_PRIMITIVE_RECEIVE_UNSENT,
SCTP_PRIMITIVE_RECEIVE_UNACKED,
SCTP_PRIMITIVE_DESTROY,
} sctp_event_primitive_t;
#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_DESTROY
#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_REQUESTHEARTBEAT
#define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1)
/* We define here a utility type for manipulating subtypes.
......@@ -268,8 +241,13 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
#define SCTP_ADDR_REACHABLE 2
#define SCTP_ADDR_NOT_REACHABLE 1
/* Maximum chunk length considering padding requirements. */
enum { SCTP_MAX_CHUNK_LEN = ((1<<16) - sizeof(__u32)) };
/* Encourage Cookie-Echo bundling by pre-fragmenting chunks a little
* harder (until reaching ESTABLISHED state).
*/
enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
/* Guess at how big to make the TSN mapping array.
* We guarantee that we can handle at least this big a gap between the
......@@ -289,7 +267,8 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
* is enough room for 131 duplicate reports. Round down to the
* nearest power of 2.
*/
#define SCTP_MAX_DUP_TSNS 128
enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 128 };
typedef enum {
SCTP_COUNTER_INIT_ERROR,
......@@ -298,7 +277,6 @@ typedef enum {
/* How many counters does an association need? */
#define SCTP_NUMBER_COUNTERS 5
/* Here we define the default timers. */
/* cookie timer def = ? seconds */
......@@ -317,10 +295,6 @@ typedef enum {
#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000)
#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000) /* 500 ms */
/* How long do we wait before attempting to raise the PMTU? */
#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE (10 * 60 * HZ) /* 10 Minutes */
#define SCTP_DEFAULT_TIMEOUT_PMTU_RAISE_MIN (10 * 60 * HZ) /* 10 Minutes */
/* RTO.Initial - 3 seconds
* RTO.Min - 1 second
* RTO.Max - 60 seconds
......@@ -439,6 +413,13 @@ typedef enum {
#define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by
peer */
/* Reasons to retransmit. */
typedef enum {
SCTP_RETRANSMIT_T3_RTX,
SCTP_RETRANSMIT_FAST_RTX,
SCTP_RETRANSMIT_PMTU_DISCOVERY,
} sctp_retransmit_reason_t;
/* Reasons to lower cwnd. */
typedef enum {
SCTP_LOWER_CWND_T3_RTX,
......@@ -448,4 +429,3 @@ typedef enum {
} sctp_lower_cwnd_t;
#endif /* __sctp_constants_h__ */
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -37,6 +37,8 @@
* Xingang Guo <xingang.guo@intel.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@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
* be incorporated into the next SCTP release.
......@@ -147,7 +149,9 @@ extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/*
* sctp_crc32c.c
*/
extern __u32 count_crc(__u8 *ptr, __u16 count);
extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
extern __u32 sctp_end_cksum(__u32 cksum);
/*
* sctp_input.c
......@@ -162,6 +166,9 @@ extern void sctp_hash_endpoint(sctp_endpoint_t *);
extern void __sctp_hash_endpoint(sctp_endpoint_t *);
extern void sctp_unhash_endpoint(sctp_endpoint_t *);
extern void __sctp_unhash_endpoint(sctp_endpoint_t *);
extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *,
const union sctp_addr *,
struct sctp_transport **);
/*
* sctp_hashdriver.c
......@@ -266,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_transport;
extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr;
extern atomic_t sctp_dbg_objcnt_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap;
/* Macros to atomically increment/decrement objcnt counters. */
#define SCTP_DBG_OBJCNT_INC(name) \
......@@ -418,6 +426,23 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return retval;
}
/* Generate a random jitter in the range of -50% ~ +50% of input RTO. */
static inline __s32 sctp_jitter(__u32 rto)
{
static __u32 sctp_rand;
__s32 ret;
sctp_rand += jiffies;
sctp_rand ^= (sctp_rand << 12);
sctp_rand ^= (sctp_rand >> 20);
/* Choose random number from 0 to rto, then move to -50% ~ +50%
* of rto.
*/
ret = sctp_rand % rto - (rto >> 1);
return ret;
}
/* 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
......
......@@ -256,7 +256,7 @@ 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 *,
const sctp_transport_t *,
const struct sctp_transport *,
const void *payload,
const size_t paylen);
sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *,
......@@ -269,6 +269,11 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *,
const void *payload,
size_t paylen);
void sctp_chunk_assign_tsn(sctp_chunk_t *);
void sctp_chunk_assign_ssn(sctp_chunk_t *);
int sctp_datachunks_from_user(sctp_association_t *,
const struct sctp_sndrcvinfo *,
struct msghdr *, int len,
struct sk_buff_head *);
/* Prototypes for statetable processing. */
......
This diff is collapsed.
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, 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 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
* These are the definitions needed for the sctp_ulpqueue type. The
* sctp_ulpqueue is the interface between the Upper Layer Protocol, or ULP,
* These are the definitions needed for the sctp_ulpq type. The
* sctp_ulpq is the interface between the Upper Layer Protocol, or ULP,
* and the core SCTP state machine. This is the component which handles
* reassembly and ordering.
*
......@@ -28,9 +28,14 @@
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to one of the
* following email addresses:
* Please send any bug reports or fixes you make to the
* email addresses:
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
*
......@@ -42,46 +47,26 @@
#define __sctp_ulpqueue_h__
/* A structure to carry information to the ULP (e.g. Sockets API) */
typedef struct sctp_ulpqueue {
struct sctp_ulpq {
int malloced;
spinlock_t lock;
sctp_association_t *asoc;
struct sk_buff_head reasm;
struct sk_buff_head lobby;
__u16 ssn[0];
} sctp_ulpqueue_t;
/* This macro assists in creation of external storage for variable length
* internal buffers.
*/
#define sctp_ulpqueue_storage_size(inbound) (sizeof(__u16) * (inbound))
sctp_ulpqueue_t *sctp_ulpqueue_new(sctp_association_t *asoc,
__u16 inbound,
int priority);
sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq,
sctp_association_t *asoc,
__u16 inbound);
void sctp_ulpqueue_free(sctp_ulpqueue_t *);
};
/* Prototypes. */
struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority);
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */
int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *,
sctp_chunk_t *chunk,
int priority);
int sctp_ulpq_tail_data(struct sctp_ulpq *, sctp_chunk_t *chunk, int priority);
/* Add a new event for propogation to the ULP. */
int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *,
sctp_ulpevent_t *event);
int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
/* Is the ulpqueue empty. */
int sctp_ulpqueue_is_empty(sctp_ulpqueue_t *);
int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
int sctp_ulpqueue_is_empty(struct sctp_ulpq *);
#endif /* __sctp_ulpqueue_h__ */
......
......@@ -100,6 +100,14 @@ enum sctp_optname {
#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM
SCTP_SOCKOPT_PEELOFF, /* peel off association. */
#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF
SCTP_GET_PEER_ADDRS_NUM, /* Get number of peer addresss. */
#define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM
SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */
#define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS
SCTP_GET_LOCAL_ADDRS_NUM, /* Get number of local addresss. */
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
};
......@@ -576,6 +584,15 @@ struct sctp_setstrm_timeout {
__u16 ssto_streamid_end;
};
/*
* 8.3 8.5 get all peer/local addresses on a socket
* This parameter struct is for getsockopt
*/
struct sctp_getaddrs {
sctp_assoc_t assoc_id;
int addr_num;
struct sockaddr_storage *addrs;
};
/* These are bit fields for msghdr->msg_flags. See section 5.1. */
/* On user space Linux, these live in <bits/socket.h> as an enum. */
......
......@@ -6,7 +6,7 @@ menu "SCTP Configuration (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL
config IPV6_SCTP__
bool
tristate
default y if IPV6=n
default IPV6 if IPV6
......
......@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \
output.o input.o hashdriver.o sla1.o \
debug.o
debug.o ssnmap.o
ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -36,6 +37,7 @@
* Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -122,7 +124,7 @@ unsigned long update_adler32(unsigned long adler,
return (s2 << 16) + s1;
}
__u32 count_crc(__u8 *ptr, __u16 count)
__u32 sctp_start_cksum(__u8 *ptr, __u16 count)
{
/*
* Update a running Adler-32 checksum with the bytes
......@@ -146,3 +148,15 @@ __u32 count_crc(__u8 *ptr, __u16 count)
return adler;
}
__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
{
adler = update_adler32(adler, ptr, count);
return adler;
}
__u32 sctp_end_cksum(__u32 adler)
{
return adler;
}
This diff is collapsed.
......@@ -47,7 +47,7 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority)
{
sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority);
/* XXX Check for NULL? -DaveM */
if (retval)
sctp_init_cmd_seq(retval);
return retval;
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -33,6 +33,7 @@
* Written or modified by:
* Dinakaran Joseph
* Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -135,11 +136,10 @@ __u32 crc_c[256] = {
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
};
__u32 count_crc(__u8 *buffer, __u16 length)
__u32 sctp_start_cksum(__u8 *buffer, __u16 length)
{
__u32 crc32 = ~(__u32) 0;
__u32 i, result;
__u8 byte0, byte1, byte2, byte3;
__u32 i;
/* Optimize this routine to be SCTP specific, knowing how
* to skip the checksum field of the SCTP header.
......@@ -157,6 +157,24 @@ __u32 count_crc(__u8 *buffer, __u16 length)
for (i = sizeof(struct sctphdr); i < length ; i++)
CRC32C(crc32, buffer[i]);
return crc32;
}
__u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
{
__u32 i;
for (i = 0; i < length ; i++)
CRC32C(crc32, buffer[i]);
return crc32;
}
__u32 sctp_end_cksum(__u32 crc32)
{
__u32 result;
__u8 byte0, byte1, byte2, byte3;
result = ~crc32;
/* result now holds the negated polynomial remainder;
......@@ -183,5 +201,3 @@ __u32 count_crc(__u8 *buffer, __u16 length)
byte3);
return crc32;
}
......@@ -148,22 +148,11 @@ const char *sctp_status_tbl[] = {
/* Printable forms of primitives */
static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = {
"PRIMITIVE_INITIALIZE",
"PRIMITIVE_ASSOCIATE",
"PRIMITIVE_SHUTDOWN",
"PRIMITIVE_ABORT",
"PRIMITIVE_SEND",
"PRIMITIVE_SETPRIMARY",
"PRIMITIVE_RECEIVE",
"PRIMITIVE_STATUS",
"PRIMITIVE_CHANGEHEARTBEAT",
"PRIMITIVE_REQUESTHEARTBEAT",
"PRIMITIVE_GETSRTTREPORT",
"PRIMITIVE_SETFAILURETHRESHOLD",
"PRIMITIVE_SETPROTOPARAMETERS",
"PRIMITIVE_RECEIVE_UNSENT",
"PRIMITIVE_RECEIVE_UNACKED",
"PRIMITIVE_DESTROY"
};
/* Lookup primitive debug name. */
......@@ -178,7 +167,6 @@ const char *sctp_pname(const sctp_subtype_t id)
static const char *sctp_other_tbl[] = {
"NO_PENDING_TSN",
"ICMP_UNREACHFRAG"
};
/* Lookup "other" debug name. */
......@@ -197,12 +185,10 @@ static const char *sctp_timer_tbl[] = {
"TIMEOUT_T1_INIT",
"TIMEOUT_T2_SHUTDOWN",
"TIMEOUT_T3_RTX",
"TIMEOUT_T4_RTO",
"TIMEOUT_T5_SHUTDOWN_GUARD",
"TIMEOUT_HEARTBEAT",
"TIMEOUT_SACK",
"TIMEOUT_AUTOCLOSE",
"TIMEOUT_PMTU_RAISE",
};
/* Lookup timer debug name. */
......
......@@ -137,7 +137,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
sp->rtoinfo.srto_initial;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
/* sctpimpguide-05 Section 2.12.2
* If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
......@@ -152,8 +151,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
SCTP_DEFAULT_TIMEOUT_SACK;
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ;
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] =
SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
/* Set up the default send/receive buffer space. */
......@@ -264,7 +261,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
sctp_association_t *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint,
const union sctp_addr *paddr,
sctp_transport_t **transport)
struct sctp_transport **transport)
{
int rport;
sctp_association_t *asoc;
......@@ -289,9 +286,10 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
}
/* Lookup association on an endpoint based on a peer address. BH-safe. */
sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
sctp_association_t *sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *ep,
const union sctp_addr *paddr,
sctp_transport_t **transport)
struct sctp_transport **transport)
{
sctp_association_t *asoc;
......@@ -333,7 +331,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
{
sctp_association_t *asoc;
struct sock *sk;
sctp_transport_t *transport;
struct sctp_transport *transport;
sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue;
sctp_subtype_t subtype;
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, 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 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
......@@ -53,6 +53,9 @@
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/time.h> /* For struct timeval */
#include <net/ip.h>
#include <net/icmp.h>
#include <net/snmp.h>
#include <net/sock.h>
#include <net/xfrm.h>
#include <net/sctp/sctp.h>
......@@ -63,7 +66,7 @@ static int sctp_rcv_ootb(struct sk_buff *);
sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *laddr,
const union sctp_addr *paddr,
sctp_transport_t **transportp);
struct sctp_transport **transportp);
sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
......@@ -72,10 +75,19 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
{
struct sctphdr *sh;
__u32 cmp, val;
struct sk_buff *list = skb_shinfo(skb)->frag_list;
sh = (struct sctphdr *) skb->h.raw;
cmp = ntohl(sh->checksum);
val = count_crc((__u8 *)sh, skb->len);
val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
for (; list; list = list->next)
val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list),
val);
val = sctp_end_cksum(val);
if (val != cmp) {
/* CRC failure, dump it. */
return -1;
......@@ -92,7 +104,7 @@ int sctp_rcv(struct sk_buff *skb)
sctp_association_t *asoc;
sctp_endpoint_t *ep = NULL;
sctp_endpoint_common_t *rcvr;
sctp_transport_t *transport = NULL;
struct sctp_transport *transport = NULL;
sctp_chunk_t *chunk;
struct sctphdr *sh;
union sctp_addr src;
......@@ -248,6 +260,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
/* Handle icmp frag needed error. */
static inline void sctp_icmp_frag_needed(struct sock *sk,
sctp_association_t *asoc,
struct sctp_transport *transport,
__u32 pmtu)
{
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
printk(KERN_WARNING "%s: Reported pmtu %d too low, "
"using default minimum of %d\n", __FUNCTION__, pmtu,
SCTP_DEFAULT_MINSEGMENT);
pmtu = SCTP_DEFAULT_MINSEGMENT;
}
if (!sock_owned_by_user(sk) && transport && (transport->pmtu != pmtu)) {
transport->pmtu = pmtu;
sctp_assoc_sync_pmtu(asoc);
sctp_retransmit(&asoc->outqueue, transport,
SCTP_RETRANSMIT_PMTU_DISCOVERY );
}
}
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
......@@ -263,9 +296,109 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* is probably better.
*
*/
void sctp_v4_err(struct sk_buff *skb, u32 info)
void sctp_v4_err(struct sk_buff *skb, __u32 info)
{
/* This should probably involve a call to SCTPhandleICMP(). */
struct iphdr *iph = (struct iphdr *)skb->data;
struct sctphdr *sh = (struct sctphdr *)(skb->data + (iph->ihl <<2));
int type = skb->h.icmph->type;
int code = skb->h.icmph->code;
union sctp_addr saddr, daddr;
struct inet_opt *inet;
struct sock *sk = NULL;
sctp_endpoint_t *ep = NULL;
sctp_association_t *asoc = NULL;
struct sctp_transport *transport;
int err;
if (skb->len < ((iph->ihl << 2) + 8)) {
ICMP_INC_STATS_BH(IcmpInErrors);
return;
}
saddr.v4.sin_family = AF_INET;
saddr.v4.sin_port = ntohs(sh->source);
memcpy(&saddr.v4.sin_addr.s_addr, &iph->saddr, sizeof(struct in_addr));
daddr.v4.sin_family = AF_INET;
daddr.v4.sin_port = ntohs(sh->dest);
memcpy(&daddr.v4.sin_addr.s_addr, &iph->daddr, sizeof(struct in_addr));
/* Look for an association that matches the incoming ICMP error
* packet.
*/
asoc = __sctp_lookup_association(&saddr, &daddr, &transport);
if (!asoc) {
/* If there is no matching association, see if it matches any
* endpoint. This may happen for an ICMP error generated in
* response to an INIT_ACK.
*/
ep = __sctp_rcv_lookup_endpoint(&daddr);
if (!ep) {
ICMP_INC_STATS_BH(IcmpInErrors);
return;
}
}
if (asoc) {
if (ntohl(sh->vtag) != asoc->c.peer_vtag) {
ICMP_INC_STATS_BH(IcmpInErrors);
goto out;
}
sk = asoc->base.sk;
} else
sk = ep->base.sk;
sctp_bh_lock_sock(sk);
/* If too many ICMPs get dropped on busy
* servers this needs to be solved differently.
*/
if (sock_owned_by_user(sk))
NET_INC_STATS_BH(LockDroppedIcmps);
switch (type) {
case ICMP_PARAMETERPROB:
err = EPROTO;
break;
case ICMP_DEST_UNREACH:
if (code > NR_ICMP_UNREACH)
goto out_unlock;
/* PMTU discovery (RFC1191) */
if (ICMP_FRAG_NEEDED == code) {
sctp_icmp_frag_needed(sk, asoc, transport, info);
goto out_unlock;
}
err = icmp_err_convert[code].errno;
break;
case ICMP_TIME_EXCEEDED:
/* Ignore any time exceeded errors due to fragment reassembly
* timeouts.
*/
if (ICMP_EXC_FRAGTIME == code)
goto out_unlock;
err = EHOSTUNREACH;
break;
default:
goto out_unlock;
}
inet = inet_sk(sk);
if (!sock_owned_by_user(sk) && inet->recverr) {
sk->err = err;
sk->error_report(sk);
} else { /* Only an error on timeout */
sk->err_soft = err;
}
out_unlock:
sctp_bh_unlock_sock(sk);
out:
sock_put(sk);
if (asoc)
sctp_association_put(asoc);
if (ep)
sctp_endpoint_put(ep);
}
/*
......@@ -303,17 +436,17 @@ int sctp_rcv_ootb(struct sk_buff *skb)
* chunk, the receiver should silently discard the packet
* and take no further action.
*/
if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE)
if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type)
goto discard;
/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
* or a COOKIE ACK the SCTP Packet should be silently
* discarded.
*/
if (ch->type == SCTP_CID_COOKIE_ACK)
if (SCTP_CID_COOKIE_ACK == ch->type)
goto discard;
if (ch->type == SCTP_CID_ERROR) {
if (SCTP_CID_ERROR == ch->type) {
err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t));
if (SCTP_ERROR_STALE_COOKIE == err->cause)
goto discard;
......@@ -485,12 +618,12 @@ void __sctp_unhash_established(sctp_association_t *asoc)
/* Look up an association. */
sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr,
sctp_transport_t **transportp)
struct sctp_transport **transportp)
{
sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb;
sctp_association_t *asoc;
sctp_transport_t *transport;
struct sctp_transport *transport;
int hash;
/* Optimize here for direct hit, only listening connections can
......@@ -521,7 +654,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
/* Look up an association. BH-safe. */
sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr,
sctp_transport_t **transportp)
struct sctp_transport **transportp)
{
sctp_association_t *asoc;
......@@ -537,7 +670,7 @@ int sctp_has_association(const union sctp_addr *laddr,
const union sctp_addr *paddr)
{
sctp_association_t *asoc;
sctp_transport_t *transport;
struct sctp_transport *transport;
if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
sock_put(asoc->base.sk);
......@@ -567,7 +700,7 @@ int sctp_has_association(const union sctp_addr *laddr,
*
*/
static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
const union sctp_addr *laddr, sctp_transport_t **transportp)
const union sctp_addr *laddr, struct sctp_transport **transportp)
{
sctp_association_t *asoc;
union sctp_addr addr;
......@@ -627,7 +760,7 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr,
sctp_transport_t **transportp)
struct sctp_transport **transportp)
{
sctp_association_t *asoc;
......
......@@ -98,43 +98,22 @@ static inline void sctp_v6_err(struct sk_buff *skb,
}
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
static inline int sctp_v6_xmit(struct sk_buff *skb)
static inline int sctp_v6_xmit(struct sk_buff *skb,
struct sctp_transport *transport, int ipfragok)
{
struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl;
struct dst_entry *dst = skb->dst;
struct rt6_info *rt6 = (struct rt6_info *)dst;
struct in6_addr saddr;
int err;
fl.proto = sk->protocol;
fl.fl6_dst = &rt6->rt6i_dst.addr;
/* FIXME: Currently, ip6_route_output() doesn't fill in the source
* address in the returned route entry. So we call ipv6_get_saddr()
* to get an appropriate source address. It is possible that this address
* may not be part of the bind address list of the association.
* Once ip6_route_ouput() is fixed so that it returns a route entry
* with an appropriate source address, the following if condition can
* be removed. With ip6_route_output() returning a source address filled
* route entry, sctp_transport_route() can do real source address
* selection for v6.
/* Fill in the dest address from the route entry passed with the skb
* and the source address from the transport.
*/
if (ipv6_addr_any(&rt6->rt6i_src.addr)) {
err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr);
if (err) {
printk(KERN_ERR "%s: No saddr available for "
"DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
__FUNCTION__, NIP6(fl.fl6_src));
return err;
}
fl.fl6_src = &saddr;
} else {
fl.fl6_src = &rt6->rt6i_src.addr;
}
fl.fl6_dst = &rt6->rt6i_dst.addr;
fl.fl6_src = &transport->saddr.v6.sin6_addr;
fl.fl6_flowlabel = np->flow_label;
IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
......@@ -147,20 +126,26 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
fl.nl_u.ip6_u.daddr = rt0->addr;
}
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
"dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
__FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
NIP6(fl.fl6_dst));
return ip6_xmit(sk, skb, &fl, np->opt);
}
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
struct dst_entry *sctp_v6_get_dst(sctp_association_t *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct dst_entry *dst;
struct flowi fl = {
.nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
__FUNCTION__, NIP6(fl.fl6_dst));
......@@ -181,12 +166,96 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
NIP6(&rt->rt6i_dst.addr), NIP6(&rt->rt6i_src.addr));
} else {
SCTP_DEBUG_PRINTK("NO ROUTE\n");
return NULL;
}
return dst;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
* addresses.
*/
static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
union sctp_addr *s2)
{
struct in6_addr *a1 = &s1->v6.sin6_addr;
struct in6_addr *a2 = &s2->v6.sin6_addr;
int i, j;
for (i = 0; i < 4 ; i++) {
__u32 a1xora2;
a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
if ((j = fls(ntohl(a1xora2))))
return (i * 32 + 32 - j);
}
return (i*32);
}
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst,
union sctp_addr *daddr, union sctp_addr *saddr)
{
sctp_bind_addr_t *bp;
rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr;
struct list_head *pos;
sctp_scope_t scope;
union sctp_addr *baddr = NULL;
__u8 matchlen = 0;
__u8 bmatchlen;
SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
"daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
__FUNCTION__, asoc, dst, NIP6(&daddr->v6.sin6_addr));
if (!asoc) {
ipv6_get_saddr(dst, &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
NIP6(&saddr->v6.sin6_addr));
return;
}
scope = sctp_scope(daddr);
bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;
/* Go through the bind address list and find the best source address
* that matches the scope of the destination address.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list);
if ((laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
baddr = &laddr->a;
matchlen = bmatchlen;
}
}
}
if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
SCTP_DEBUG_PRINTK("saddr: "
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
NIP6(&saddr->v6.sin6_addr));
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
"address for the "
"dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
__FUNCTION__, asoc, NIP6(&daddr->v6.sin6_addr));
}
sctp_read_unlock(addr_lock);
}
/* Make a copy of all potential local addresses. */
static void sctp_v6_copy_addrlist(struct list_head *addrlist,
struct net_device *dev)
......@@ -257,10 +326,12 @@ static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk)
}
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
unsigned short port)
{
struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
}
......@@ -527,10 +598,11 @@ static struct inet6_protocol sctpv6_protocol = {
};
static struct sctp_af sctp_ipv6_specific = {
.queue_xmit = sctp_v6_xmit,
.sctp_xmit = sctp_v6_xmit,
.setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt,
.get_dst = sctp_v6_get_dst,
.get_saddr = sctp_v6_get_saddr,
.copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb,
.from_sk = sctp_v6_from_sk,
......
......@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap);
/* An array to make it easy to pretty print the debug information
* to the proc fs.
......@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(chunk),
SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap),
};
/* Callback from procfs to read out objcount information.
......
/* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001-2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -62,7 +62,6 @@
#include <net/sctp/sm.h>
/* Forward declarations for private helpers. */
__u32 count_crc(__u8 *ptr, __u16 count);
static void sctp_packet_reset(sctp_packet_t *packet);
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
sctp_chunk_t *chunk);
......@@ -81,6 +80,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler;
packet->has_cookie_echo = 0;
packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */
if (packet_empty)
......@@ -90,7 +90,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
/* Initialize the packet structure. */
sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
sctp_transport_t *transport,
struct sctp_transport *transport,
__u16 sport,
__u16 dport)
{
......@@ -102,6 +102,7 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL;
packet->has_cookie_echo = 0;
packet->ipfragok = 0;
packet->malloced = 0;
sctp_packet_reset(packet);
return packet;
......@@ -193,6 +194,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
* transmit and rely on IP
* fragmentation.
*/
packet->ipfragok = 1;
goto append;
}
} else { /* !packet_empty */
......@@ -228,13 +230,13 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
}
/* All packets are sent to the network through this function from
* sctp_push_outqueue().
* sctp_outq_tail().
*
* The return value is a normal kernel error return value.
*/
int sctp_packet_transmit(sctp_packet_t *packet)
{
sctp_transport_t *transport = packet->transport;
struct sctp_transport *transport = packet->transport;
sctp_association_t *asoc = transport->asoc;
struct sctphdr *sh;
__u32 crc32;
......@@ -358,22 +360,14 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
*/
crc32 = count_crc((__u8 *)sh, nskb->len);
crc32 = sctp_start_cksum((__u8 *)sh, nskb->len);
crc32 = sctp_end_cksum(crc32);
/* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged.
*/
sh->checksum = htonl(crc32);
/* FIXME: Delete the rest of this switch statement once phase 2
* of address selection (ipv6 support) drops in.
*/
switch (transport->ipaddr.sa.sa_family) {
case AF_INET6:
SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;)
break;
};
/* IP layer ECN support
* From RFC 2481
* "The ECN-Capable Transport (ECT) bit would be set by the
......@@ -423,8 +417,10 @@ int sctp_packet_transmit(sctp_packet_t *packet)
}
dst = transport->dst;
if (!dst || dst->obsolete) {
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if (!dst || (dst->obsolete > 1)) {
sctp_transport_route(transport, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc);
}
nskb->dst = dst_clone(transport->dst);
......@@ -433,14 +429,22 @@ int sctp_packet_transmit(sctp_packet_t *packet)
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
nskb->len);
(*transport->af_specific->queue_xmit)(nskb);
(*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok);
out:
packet->size = SCTP_IP_OVERHEAD;
return err;
no_route:
kfree_skb(nskb);
IP_INC_STATS_BH(IpOutNoRoutes);
err = -EHOSTUNREACH;
/* FIXME: Returning the 'err' will effect all the associations
* associated with a socket, although only one of the paths of the
* association is unreachable.
* The real failure of a transport or association can be passed on
* to the user via notifications. So setting this error may not be
* required.
*/
/* err = -EHOSTUNREACH; */
goto out;
}
......@@ -473,7 +477,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
{
sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight;
sctp_transport_t *transport = packet->transport;
struct sctp_transport *transport = packet->transport;
__u32 max_burst_bytes;
/* RFC 2960 6.1 Transmission of DATA Chunks
......
This diff is collapsed.
......@@ -203,23 +203,3 @@ DECLARE_PRIMITIVE(SEND);
*/
DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
/* COMMENT BUG. Find out where this is mentioned in the spec. */
int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg)
{
int error = 0;
sctp_event_t event_type;
sctp_subtype_t subtype;
sctp_state_t state;
sctp_endpoint_t *ep;
event_type = SCTP_EVENT_T_OTHER;
subtype = SCTP_ST_OTHER(SCTP_EVENT_ICMP_UNREACHFRAG);
state = asoc ? asoc->state : SCTP_STATE_CLOSED;
ep = asoc ? asoc->ep : NULL;
error = sctp_do_sm(event_type, subtype, state, ep,
asoc, arg, GFP_ATOMIC);
return error;
}
......@@ -82,7 +82,7 @@ struct sock *sctp_get_ctl_sock(void)
}
/* Set up the proc fs entry for the SCTP protocol. */
void sctp_proc_init(void)
__init void sctp_proc_init(void)
{
if (!proc_net_sctp) {
struct proc_dir_entry *ent;
......@@ -223,37 +223,6 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
return error;
}
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct rtable *rt;
struct flowi fl;
memset(&fl, 0x0, sizeof(struct flowi));
fl.fl4_dst = daddr->v4.sin_addr.s_addr;
fl.proto = IPPROTO_SCTP;
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)) {
SCTP_DEBUG_PRINTK("NO ROUTE\n");
return NULL;
}
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;
}
/* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr)
......@@ -292,10 +261,12 @@ static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk)
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst)
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
unsigned short port)
{
struct rtable *rt = (struct rtable *)dst;
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = port;
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
......@@ -394,6 +365,108 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
return retval;
}
/* Returns a valid dst cache entry for the given source and destination ip
* addresses. If an association is passed, trys to get a dst entry with a
* source adddress that matches an address in the bind address list.
*/
struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct rtable *rt;
struct flowi fl;
sctp_bind_addr_t *bp;
rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr;
struct list_head *pos;
struct dst_entry *dst = NULL;
union sctp_addr dst_saddr;
memset(&fl, 0x0, sizeof(struct flowi));
fl.fl4_dst = daddr->v4.sin_addr.s_addr;
fl.proto = IPPROTO_SCTP;
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)) {
dst = &rt->u.dst;
}
/* If there is no association or if a source address is passed, no
* more validation is required.
*/
if (!asoc || saddr)
goto out;
bp = &asoc->base.bind_addr;
addr_lock = &asoc->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);
sctp_v4_dst_saddr(&dst_saddr, dst, bp->port);
if (sctp_v4_cmp_addr(&dst_saddr, &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);
dst = NULL;
}
/* 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);
if (AF_INET == laddr->a.sa.sa_family) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
dst = sctp_v4_get_dst(asoc, daddr, &laddr->a);
if (!ip_route_output_key(&rt, &fl)) {
dst = &rt->u.dst;
goto out_unlock;
}
}
}
out_unlock:
sctp_read_unlock(addr_lock);
out:
if (dst)
SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_src));
else
SCTP_DEBUG_PRINTK("NO ROUTE\n");
return dst;
}
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
void sctp_v4_get_saddr(sctp_association_t *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
}
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
*/
......@@ -545,6 +618,19 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return sctp_v4_available(addr);
}
/* Wrapper routine that calls the ip transmit routine. */
static inline int sctp_v4_xmit(struct sk_buff *skb,
struct sctp_transport *transport, int ipfragok)
{
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
"src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
__FUNCTION__, skb, skb->len,
NIPQUAD(((struct rtable *)skb->dst)->rt_src),
NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
return ip_queue_xmit(skb, ipfragok);
}
struct sctp_af sctp_ipv4_specific;
static struct sctp_pf sctp_pf_inet = {
......@@ -601,10 +687,11 @@ static struct inet_protocol sctp_protocol = {
/* IPv4 address related functions. */
struct sctp_af sctp_ipv4_specific = {
.queue_xmit = ip_queue_xmit,
.sctp_xmit = sctp_v4_xmit,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
.get_dst = sctp_v4_get_dst,
.get_saddr = sctp_v4_get_saddr,
.copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb,
.from_sk = sctp_v4_from_sk,
......@@ -688,7 +775,7 @@ static void cleanup_sctp_mibs(void)
}
/* Initialize the universe into something sensible. */
int sctp_init(void)
__init int sctp_init(void)
{
int i;
int status = 0;
......@@ -750,13 +837,9 @@ int sctp_init(void)
/* Implementation specific variables. */
/* Initialize default stream count setup information.
* Note: today the stream accounting data structures are very
* fixed size, so one really does need to make sure that these have
* upper/lower limits when changing.
*/
sctp_proto.max_instreams = SCTP_MAX_STREAM;
sctp_proto.max_outstreams = SCTP_MAX_STREAM;
/* Initialize default stream count setup information. */
sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS;
sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
/* Allocate and initialize the association hash table. */
sctp_proto.assoc_hashsize = 4096;
......@@ -829,6 +912,7 @@ int sctp_init(void)
sctp_get_local_addr_list(&sctp_proto);
__unsafe(THIS_MODULE);
return 0;
err_ctl_sock_init:
......@@ -852,7 +936,7 @@ int sctp_init(void)
}
/* Exit handler for the SCTP protocol. */
void sctp_exit(void)
__exit void sctp_exit(void)
{
/* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory.
......@@ -889,4 +973,3 @@ module_exit(sctp_exit);
MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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