Commit 4f232ae0 authored by David S. Miller's avatar David S. Miller

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

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents c271bc7e a0065b2f
/* SCTP kernel reference Implementation Copyright (C) 1999-2001 /* SCTP kernel reference Implementation Copyright (C) 1999-2001
* Cisco, Motorola, and IBM * Cisco, Motorola, and IBM
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* These are the definitions needed for the command object. * These are the definitions needed for the command object.
* *
* 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 one of the * Please send any bug reports or fixes you make to one of the
* following email addresses: * following email addresses:
* *
* 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> * 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.
*/ */
...@@ -69,11 +69,11 @@ typedef enum { ...@@ -69,11 +69,11 @@ typedef enum {
SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */
SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */
SCTP_CMD_REPORT_BIGGAP, /* Narc on a TSN (it was too high). */ 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_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_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_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. */
...@@ -112,7 +112,7 @@ typedef union { ...@@ -112,7 +112,7 @@ typedef union {
void *ptr; void *ptr;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_transport_t *transport; struct sctp_transport *transport;
sctp_bind_addr_t *bp; sctp_bind_addr_t *bp;
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
sctp_ulpevent_t *ulpevent; sctp_ulpevent_t *ulpevent;
...@@ -160,7 +160,7 @@ SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) ...@@ -160,7 +160,7 @@ SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to)
SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr)
SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk) SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk)
SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) 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(BA, sctp_bind_addr_t *, bp)
SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent) SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent)
......
...@@ -3,33 +3,33 @@ ...@@ -3,33 +3,33 @@
* 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-2002 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This file is part of the implementation of the add-IP extension, * This file is part of the implementation of the add-IP extension,
* based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001, * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
* for the SCTP kernel reference Implementation. * for 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 warranty * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* ************************ * ************************
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to one of the following email * Please send any bug reports or fixes you make to one of the following email
* addresses: * addresses:
* *
* 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>
* Randall Stewart <randall@stewart.chicago.il.us> * Randall Stewart <randall@stewart.chicago.il.us>
...@@ -38,14 +38,14 @@ ...@@ -38,14 +38,14 @@
* Xingang Guo <xingang.guo@intel.com> * Xingang Guo <xingang.guo@intel.com>
* Sridhar Samudrala <samudrala@us.ibm.com> * Sridhar Samudrala <samudrala@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.
* *
* There are still LOTS of bugs in this code... I always run on the motto * There are still LOTS of bugs in this code... I always run on the motto
* "it is a wonder any code ever works :)" * "it is a wonder any code ever works :)"
* *
* *
*/ */
#ifndef __sctp_constants_h__ #ifndef __sctp_constants_h__
...@@ -56,17 +56,10 @@ ...@@ -56,17 +56,10 @@
#include <linux/ipv6.h> /* For ipv6hdr. */ #include <linux/ipv6.h> /* For ipv6hdr. */
#include <net/sctp/user.h> #include <net/sctp/user.h>
/* What a hack! Jiminy Cricket! */ /* Value used for stream negotiation. */
enum { SCTP_MAX_STREAM = 10 }; enum { SCTP_MAX_STREAM = 0xffff };
enum { SCTP_DEFAULT_OUTSTREAMS = 10 };
/* Define the amount of space to reserve for SCTP, IP, LL. enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
* 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))
/* Define the amount of space to reserve for SCTP, IP, LL. /* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating * There is a little bit of waste that we are always allocating
...@@ -105,57 +98,37 @@ typedef enum { ...@@ -105,57 +98,37 @@ typedef enum {
*/ */
typedef enum { typedef enum {
SCTP_EVENT_TIMEOUT_NONE = 0, SCTP_EVENT_TIMEOUT_NONE = 0,
SCTP_EVENT_TIMEOUT_T1_COOKIE, SCTP_EVENT_TIMEOUT_T1_COOKIE,
SCTP_EVENT_TIMEOUT_T1_INIT, SCTP_EVENT_TIMEOUT_T1_INIT,
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN,
SCTP_EVENT_TIMEOUT_T3_RTX, SCTP_EVENT_TIMEOUT_T3_RTX,
SCTP_EVENT_TIMEOUT_T4_RTO,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
SCTP_EVENT_TIMEOUT_HEARTBEAT, SCTP_EVENT_TIMEOUT_HEARTBEAT,
SCTP_EVENT_TIMEOUT_SACK, SCTP_EVENT_TIMEOUT_SACK,
SCTP_EVENT_TIMEOUT_AUTOCLOSE, SCTP_EVENT_TIMEOUT_AUTOCLOSE,
SCTP_EVENT_TIMEOUT_PMTU_RAISE,
} sctp_event_timeout_t; } 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) #define SCTP_NUM_TIMEOUT_TYPES (SCTP_EVENT_TIMEOUT_MAX + 1)
typedef enum { typedef enum {
SCTP_EVENT_NO_PENDING_TSN = 0, SCTP_EVENT_NO_PENDING_TSN = 0,
SCTP_EVENT_ICMP_UNREACHFRAG,
} sctp_event_other_t; } 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) #define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1)
/* These are primitive requests from the ULP. */ /* These are primitive requests from the ULP. */
typedef enum { typedef enum {
SCTP_PRIMITIVE_ASSOCIATE = 0,
SCTP_PRIMITIVE_INITIALIZE = 0,
SCTP_PRIMITIVE_ASSOCIATE,
SCTP_PRIMITIVE_SHUTDOWN, SCTP_PRIMITIVE_SHUTDOWN,
SCTP_PRIMITIVE_ABORT, SCTP_PRIMITIVE_ABORT,
SCTP_PRIMITIVE_SEND, SCTP_PRIMITIVE_SEND,
SCTP_PRIMITIVE_SETPRIMARY,
SCTP_PRIMITIVE_RECEIVE,
SCTP_PRIMITIVE_STATUS,
SCTP_PRIMITIVE_CHANGEHEARTBEAT,
SCTP_PRIMITIVE_REQUESTHEARTBEAT, 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; } 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) #define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1)
/* We define here a utility type for manipulating subtypes. /* 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[]; ...@@ -268,8 +241,13 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[];
#define SCTP_ADDR_REACHABLE 2 #define SCTP_ADDR_REACHABLE 2
#define SCTP_ADDR_NOT_REACHABLE 1 #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. /* Guess at how big to make the TSN mapping array.
* We guarantee that we can handle at least this big a gap between the * 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[]; ...@@ -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 * is enough room for 131 duplicate reports. Round down to the
* nearest power of 2. * nearest power of 2.
*/ */
#define SCTP_MAX_DUP_TSNS 128 enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 128 };
typedef enum { typedef enum {
SCTP_COUNTER_INIT_ERROR, SCTP_COUNTER_INIT_ERROR,
...@@ -298,7 +277,6 @@ typedef enum { ...@@ -298,7 +277,6 @@ typedef enum {
/* How many counters does an association need? */ /* How many counters does an association need? */
#define SCTP_NUMBER_COUNTERS 5 #define SCTP_NUMBER_COUNTERS 5
/* Here we define the default timers. */ /* Here we define the default timers. */
/* cookie timer def = ? seconds */ /* cookie timer def = ? seconds */
...@@ -317,10 +295,6 @@ typedef enum { ...@@ -317,10 +295,6 @@ typedef enum {
#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000) #define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000)
#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000) /* 500 ms */ #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.Initial - 3 seconds
* RTO.Min - 1 second * RTO.Min - 1 second
* RTO.Max - 60 seconds * RTO.Max - 60 seconds
...@@ -439,6 +413,13 @@ typedef enum { ...@@ -439,6 +413,13 @@ typedef enum {
#define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by #define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by
peer */ 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. */ /* Reasons to lower cwnd. */
typedef enum { typedef enum {
SCTP_LOWER_CWND_T3_RTX, SCTP_LOWER_CWND_T3_RTX,
...@@ -448,4 +429,3 @@ typedef enum { ...@@ -448,4 +429,3 @@ typedef enum {
} sctp_lower_cwnd_t; } sctp_lower_cwnd_t;
#endif /* __sctp_constants_h__ */ #endif /* __sctp_constants_h__ */
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001-2003 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -36,7 +36,9 @@ ...@@ -36,7 +36,9 @@
* 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>
* 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.
...@@ -147,7 +149,9 @@ extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg); ...@@ -147,7 +149,9 @@ extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
/* /*
* sctp_crc32c.c * 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 * sctp_input.c
...@@ -162,6 +166,9 @@ extern void sctp_hash_endpoint(sctp_endpoint_t *); ...@@ -162,6 +166,9 @@ extern void sctp_hash_endpoint(sctp_endpoint_t *);
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 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 * sctp_hashdriver.c
...@@ -266,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_transport; ...@@ -266,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_transport;
extern atomic_t sctp_dbg_objcnt_chunk; extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_bind_addr;
extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap;
/* Macros to atomically increment/decrement objcnt counters. */ /* Macros to atomically increment/decrement objcnt counters. */
#define SCTP_DBG_OBJCNT_INC(name) \ #define SCTP_DBG_OBJCNT_INC(name) \
...@@ -418,6 +426,23 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) ...@@ -418,6 +426,23 @@ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
return retval; 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 /* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on * individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure * 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 *, ...@@ -256,7 +256,7 @@ sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
const sctp_chunk_t *, const sctp_chunk_t *,
const struct msghdr *); 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 struct sctp_transport *,
const void *payload, const void *payload,
const size_t paylen); const size_t paylen);
sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, 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 *, ...@@ -269,6 +269,11 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *,
const void *payload, const void *payload,
size_t paylen); size_t paylen);
void sctp_chunk_assign_tsn(sctp_chunk_t *); void sctp_chunk_assign_tsn(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. */ /* Prototypes for statetable processing. */
......
This diff is collapsed.
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* These are the definitions needed for the sctp_ulpqueue type. The * These are the definitions needed for the sctp_ulpq type. The
* sctp_ulpqueue is the interface between the Upper Layer Protocol, or ULP, * sctp_ulpq is the interface between the Upper Layer Protocol, or ULP,
* and the core SCTP state machine. This is the component which handles * and the core SCTP state machine. This is the component which handles
* reassembly and ordering. * reassembly and ordering.
* *
* 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 one of the * Please send any bug reports or fixes you make to the
* following email addresses: * email addresses:
* * lksctp developers <lksctp-developers@lists.sourceforge.net>
* Jon Grimm <jgrimm@us.ibm.com> *
* La Monte H.P. Yarroll <piggy@acm.org> * 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>
*
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -42,46 +47,26 @@ ...@@ -42,46 +47,26 @@
#define __sctp_ulpqueue_h__ #define __sctp_ulpqueue_h__
/* A structure to carry information to the ULP (e.g. Sockets API) */ /* A structure to carry information to the ULP (e.g. Sockets API) */
typedef struct sctp_ulpqueue { struct sctp_ulpq {
int malloced; int malloced;
spinlock_t lock;
sctp_association_t *asoc; sctp_association_t *asoc;
struct sk_buff_head reasm; struct sk_buff_head reasm;
struct sk_buff_head lobby; 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. */ /* Add a new DATA chunk for processing. */
int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, int sctp_ulpq_tail_data(struct sctp_ulpq *, sctp_chunk_t *chunk, int priority);
sctp_chunk_t *chunk,
int priority);
/* Add a new event for propogation to the ULP. */ /* Add a new event for propogation to the ULP. */
int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *, int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
sctp_ulpevent_t *event);
/* Is the ulpqueue empty. */ /* Is the ulpqueue empty. */
int sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); int sctp_ulpqueue_is_empty(struct sctp_ulpq *);
int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
#endif /* __sctp_ulpqueue_h__ */ #endif /* __sctp_ulpqueue_h__ */
...@@ -90,4 +75,4 @@ int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); ...@@ -90,4 +75,4 @@ int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
...@@ -100,6 +100,14 @@ enum sctp_optname { ...@@ -100,6 +100,14 @@ enum sctp_optname {
#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM
SCTP_SOCKOPT_PEELOFF, /* peel off association. */ SCTP_SOCKOPT_PEELOFF, /* peel off association. */
#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF #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 { ...@@ -576,6 +584,15 @@ struct sctp_setstrm_timeout {
__u16 ssto_streamid_end; __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. */ /* 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. */ /* On user space Linux, these live in <bits/socket.h> as an enum. */
......
...@@ -6,7 +6,7 @@ menu "SCTP Configuration (EXPERIMENTAL)" ...@@ -6,7 +6,7 @@ menu "SCTP Configuration (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL depends on INET && EXPERIMENTAL
config IPV6_SCTP__ config IPV6_SCTP__
bool tristate
default y if IPV6=n default y if IPV6=n
default IPV6 if IPV6 default IPV6 if IPV6
......
...@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ ...@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o \ inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \ tsnmap.o bind_addr.o socket.o primitive.o \
output.o input.o hashdriver.o sla1.o \ output.o input.o hashdriver.o sla1.o \
debug.o debug.o ssnmap.o
ifeq ($(CONFIG_SCTP_ADLER32), y) ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o sctp-y += adler32.o
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
* Randall Stewart <rstewar1@email.mot.com> * Randall Stewart <rstewar1@email.mot.com>
* Ken Morneau <kmorneau@cisco.com> * Ken Morneau <kmorneau@cisco.com>
* Qiaobing Xie <qxie1@email.mot.com> * Qiaobing Xie <qxie1@email.mot.com>
* Sridhar Samudrala <sri@us.ibm.com>
* *
* 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.
...@@ -122,7 +124,7 @@ unsigned long update_adler32(unsigned long adler, ...@@ -122,7 +124,7 @@ unsigned long update_adler32(unsigned long adler,
return (s2 << 16) + s1; 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 * Update a running Adler-32 checksum with the bytes
...@@ -146,3 +148,15 @@ __u32 count_crc(__u8 *ptr, __u16 count) ...@@ -146,3 +148,15 @@ __u32 count_crc(__u8 *ptr, __u16 count)
return adler; 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,8 +47,8 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) ...@@ -47,8 +47,8 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority)
{ {
sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, 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); sctp_init_cmd_seq(retval);
return retval; return retval;
} }
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* Written or modified by: * Written or modified by:
* Dinakaran Joseph * Dinakaran Joseph
* Jon Grimm <jgrimm@us.ibm.com> * 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 * 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.
...@@ -135,11 +136,10 @@ __u32 crc_c[256] = { ...@@ -135,11 +136,10 @@ __u32 crc_c[256] = {
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
}; };
__u32 count_crc(__u8 *buffer, __u16 length) __u32 sctp_start_cksum(__u8 *buffer, __u16 length)
{ {
__u32 crc32 = ~(__u32) 0; __u32 crc32 = ~(__u32) 0;
__u32 i, result; __u32 i;
__u8 byte0, byte1, byte2, byte3;
/* Optimize this routine to be SCTP specific, knowing how /* Optimize this routine to be SCTP specific, knowing how
* to skip the checksum field of the SCTP header. * to skip the checksum field of the SCTP header.
...@@ -157,6 +157,24 @@ __u32 count_crc(__u8 *buffer, __u16 length) ...@@ -157,6 +157,24 @@ __u32 count_crc(__u8 *buffer, __u16 length)
for (i = sizeof(struct sctphdr); i < length ; i++) for (i = sizeof(struct sctphdr); i < length ; i++)
CRC32C(crc32, buffer[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 = ~crc32;
/* result now holds the negated polynomial remainder; /* result now holds the negated polynomial remainder;
...@@ -183,5 +201,3 @@ __u32 count_crc(__u8 *buffer, __u16 length) ...@@ -183,5 +201,3 @@ __u32 count_crc(__u8 *buffer, __u16 length)
byte3); byte3);
return crc32; return crc32;
} }
...@@ -148,22 +148,11 @@ const char *sctp_status_tbl[] = { ...@@ -148,22 +148,11 @@ const char *sctp_status_tbl[] = {
/* Printable forms of primitives */ /* Printable forms of primitives */
static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = { static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = {
"PRIMITIVE_INITIALIZE",
"PRIMITIVE_ASSOCIATE", "PRIMITIVE_ASSOCIATE",
"PRIMITIVE_SHUTDOWN", "PRIMITIVE_SHUTDOWN",
"PRIMITIVE_ABORT", "PRIMITIVE_ABORT",
"PRIMITIVE_SEND", "PRIMITIVE_SEND",
"PRIMITIVE_SETPRIMARY",
"PRIMITIVE_RECEIVE",
"PRIMITIVE_STATUS",
"PRIMITIVE_CHANGEHEARTBEAT",
"PRIMITIVE_REQUESTHEARTBEAT", "PRIMITIVE_REQUESTHEARTBEAT",
"PRIMITIVE_GETSRTTREPORT",
"PRIMITIVE_SETFAILURETHRESHOLD",
"PRIMITIVE_SETPROTOPARAMETERS",
"PRIMITIVE_RECEIVE_UNSENT",
"PRIMITIVE_RECEIVE_UNACKED",
"PRIMITIVE_DESTROY"
}; };
/* Lookup primitive debug name. */ /* Lookup primitive debug name. */
...@@ -178,7 +167,6 @@ const char *sctp_pname(const sctp_subtype_t id) ...@@ -178,7 +167,6 @@ const char *sctp_pname(const sctp_subtype_t id)
static const char *sctp_other_tbl[] = { static const char *sctp_other_tbl[] = {
"NO_PENDING_TSN", "NO_PENDING_TSN",
"ICMP_UNREACHFRAG"
}; };
/* Lookup "other" debug name. */ /* Lookup "other" debug name. */
...@@ -197,12 +185,10 @@ static const char *sctp_timer_tbl[] = { ...@@ -197,12 +185,10 @@ static const char *sctp_timer_tbl[] = {
"TIMEOUT_T1_INIT", "TIMEOUT_T1_INIT",
"TIMEOUT_T2_SHUTDOWN", "TIMEOUT_T2_SHUTDOWN",
"TIMEOUT_T3_RTX", "TIMEOUT_T3_RTX",
"TIMEOUT_T4_RTO",
"TIMEOUT_T5_SHUTDOWN_GUARD", "TIMEOUT_T5_SHUTDOWN_GUARD",
"TIMEOUT_HEARTBEAT", "TIMEOUT_HEARTBEAT",
"TIMEOUT_SACK", "TIMEOUT_SACK",
"TIMEOUT_AUTOCLOSE", "TIMEOUT_AUTOCLOSE",
"TIMEOUT_PMTU_RAISE",
}; };
/* Lookup timer debug name. */ /* Lookup timer debug name. */
......
...@@ -137,7 +137,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ...@@ -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] = ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
sp->rtoinfo.srto_initial; sp->rtoinfo.srto_initial;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
/* sctpimpguide-05 Section 2.12.2 /* sctpimpguide-05 Section 2.12.2
* If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the * 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, ...@@ -152,8 +151,6 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
SCTP_DEFAULT_TIMEOUT_SACK; SCTP_DEFAULT_TIMEOUT_SACK;
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ; sp->autoclose * HZ;
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] =
SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
/* Set up the default send/receive buffer space. */ /* Set up the default send/receive buffer space. */
...@@ -264,7 +261,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -264,7 +261,7 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
sctp_association_t *__sctp_endpoint_lookup_assoc( sctp_association_t *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint, const sctp_endpoint_t *endpoint,
const union sctp_addr *paddr, const union sctp_addr *paddr,
sctp_transport_t **transport) struct sctp_transport **transport)
{ {
int rport; int rport;
sctp_association_t *asoc; sctp_association_t *asoc;
...@@ -289,9 +286,10 @@ sctp_association_t *__sctp_endpoint_lookup_assoc( ...@@ -289,9 +286,10 @@ sctp_association_t *__sctp_endpoint_lookup_assoc(
} }
/* Lookup association on an endpoint based on a peer address. BH-safe. */ /* Lookup association on an endpoint based on a peer address. BH-safe. */
sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_association_t *sctp_endpoint_lookup_assoc(
const union sctp_addr *paddr, const sctp_endpoint_t *ep,
sctp_transport_t **transport) const union sctp_addr *paddr,
struct sctp_transport **transport)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
...@@ -333,7 +331,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -333,7 +331,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
struct sock *sk; struct sock *sk;
sctp_transport_t *transport; struct sctp_transport *transport;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue; sctp_inqueue_t *inqueue;
sctp_subtype_t subtype; sctp_subtype_t subtype;
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
...@@ -53,6 +53,9 @@ ...@@ -53,6 +53,9 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/time.h> /* For struct timeval */ #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/sock.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
...@@ -63,7 +66,7 @@ static int sctp_rcv_ootb(struct sk_buff *); ...@@ -63,7 +66,7 @@ static int sctp_rcv_ootb(struct sk_buff *);
sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *laddr, const union sctp_addr *laddr,
const union sctp_addr *paddr, 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); 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) ...@@ -72,10 +75,19 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
{ {
struct sctphdr *sh; struct sctphdr *sh;
__u32 cmp, val; __u32 cmp, val;
struct sk_buff *list = skb_shinfo(skb)->frag_list;
sh = (struct sctphdr *) skb->h.raw; sh = (struct sctphdr *) skb->h.raw;
cmp = ntohl(sh->checksum); 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) { if (val != cmp) {
/* CRC failure, dump it. */ /* CRC failure, dump it. */
return -1; return -1;
...@@ -92,7 +104,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -92,7 +104,7 @@ int sctp_rcv(struct sk_buff *skb)
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_endpoint_t *ep = NULL; sctp_endpoint_t *ep = NULL;
sctp_endpoint_common_t *rcvr; sctp_endpoint_common_t *rcvr;
sctp_transport_t *transport = NULL; struct sctp_transport *transport = NULL;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
struct sctphdr *sh; struct sctphdr *sh;
union sctp_addr src; union sctp_addr src;
...@@ -248,6 +260,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -248,6 +260,27 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
return 0; 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 * This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should * 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) ...@@ -263,9 +296,109 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* is probably better. * 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) ...@@ -303,17 +436,17 @@ int sctp_rcv_ootb(struct sk_buff *skb)
* chunk, the receiver should silently discard the packet * chunk, the receiver should silently discard the packet
* and take no further action. * and take no further action.
*/ */
if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE) if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type)
goto discard; goto discard;
/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
* or a COOKIE ACK the SCTP Packet should be silently * or a COOKIE ACK the SCTP Packet should be silently
* discarded. * discarded.
*/ */
if (ch->type == SCTP_CID_COOKIE_ACK) if (SCTP_CID_COOKIE_ACK == ch->type)
goto discard; goto discard;
if (ch->type == SCTP_CID_ERROR) { if (SCTP_CID_ERROR == ch->type) {
err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t)); err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t));
if (SCTP_ERROR_STALE_COOKIE == err->cause) if (SCTP_ERROR_STALE_COOKIE == err->cause)
goto discard; goto discard;
...@@ -485,12 +618,12 @@ void __sctp_unhash_established(sctp_association_t *asoc) ...@@ -485,12 +618,12 @@ void __sctp_unhash_established(sctp_association_t *asoc)
/* Look up an association. */ /* Look up an association. */
sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr, sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr, const union sctp_addr *paddr,
sctp_transport_t **transportp) struct sctp_transport **transportp)
{ {
sctp_hashbucket_t *head; sctp_hashbucket_t *head;
sctp_endpoint_common_t *epb; sctp_endpoint_common_t *epb;
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_transport_t *transport; struct sctp_transport *transport;
int hash; int hash;
/* Optimize here for direct hit, only listening connections can /* Optimize here for direct hit, only listening connections can
...@@ -521,7 +654,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr, ...@@ -521,7 +654,7 @@ sctp_association_t *__sctp_lookup_association(const union sctp_addr *laddr,
/* Look up an association. BH-safe. */ /* Look up an association. BH-safe. */
sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr, const union sctp_addr *paddr,
sctp_transport_t **transportp) struct sctp_transport **transportp)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
...@@ -537,7 +670,7 @@ int sctp_has_association(const union sctp_addr *laddr, ...@@ -537,7 +670,7 @@ int sctp_has_association(const union sctp_addr *laddr,
const union sctp_addr *paddr) const union sctp_addr *paddr)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_transport_t *transport; struct sctp_transport *transport;
if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
sock_put(asoc->base.sk); sock_put(asoc->base.sk);
...@@ -567,7 +700,7 @@ int sctp_has_association(const union sctp_addr *laddr, ...@@ -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, 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; sctp_association_t *asoc;
union sctp_addr addr; union sctp_addr addr;
...@@ -627,7 +760,7 @@ static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -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, sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *paddr, const union sctp_addr *paddr,
const union sctp_addr *laddr, const union sctp_addr *laddr,
sctp_transport_t **transportp) struct sctp_transport **transportp)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
......
...@@ -98,43 +98,22 @@ static inline void sctp_v6_err(struct sk_buff *skb, ...@@ -98,43 +98,22 @@ static inline void sctp_v6_err(struct sk_buff *skb,
} }
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ /* 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 sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl; struct flowi fl;
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct rt6_info *rt6 = (struct rt6_info *)dst; struct rt6_info *rt6 = (struct rt6_info *)dst;
struct in6_addr saddr;
int err;
fl.proto = sk->protocol; fl.proto = sk->protocol;
fl.fl6_dst = &rt6->rt6i_dst.addr;
/* FIXME: Currently, ip6_route_output() doesn't fill in the source /* Fill in the dest address from the route entry passed with the skb
* address in the returned route entry. So we call ipv6_get_saddr() * and the source address from the transport.
* 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.
*/ */
if (ipv6_addr_any(&rt6->rt6i_src.addr)) { fl.fl6_dst = &rt6->rt6i_dst.addr;
err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); fl.fl6_src = &transport->saddr.v6.sin6_addr;
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_flowlabel = np->flow_label; fl.fl6_flowlabel = np->flow_label;
IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
...@@ -147,20 +126,26 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -147,20 +126,26 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
fl.nl_u.ip6_u.daddr = rt0->addr; 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); return ip6_xmit(sk, skb, &fl, np->opt);
} }
/* Returns the dst cache entry for the given source and destination ip /* Returns the dst cache entry for the given source and destination ip
* addresses. * addresses.
*/ */
struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, struct dst_entry *sctp_v6_get_dst(sctp_association_t *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr) union sctp_addr *saddr)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl = { struct flowi fl = {
.nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } }; .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
__FUNCTION__, NIP6(fl.fl6_dst)); __FUNCTION__, NIP6(fl.fl6_dst));
...@@ -181,12 +166,96 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, ...@@ -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)); NIP6(&rt->rt6i_dst.addr), NIP6(&rt->rt6i_src.addr));
} else { } else {
SCTP_DEBUG_PRINTK("NO ROUTE\n"); SCTP_DEBUG_PRINTK("NO ROUTE\n");
return NULL;
} }
return dst; 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. */ /* Make a copy of all potential local addresses. */
static void sctp_v6_copy_addrlist(struct list_head *addrlist, static void sctp_v6_copy_addrlist(struct list_head *addrlist,
struct net_device *dev) struct net_device *dev)
...@@ -257,10 +326,12 @@ static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk) ...@@ -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. */ /* 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; struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6; addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
} }
...@@ -527,10 +598,11 @@ static struct inet6_protocol sctpv6_protocol = { ...@@ -527,10 +598,11 @@ static struct inet6_protocol sctpv6_protocol = {
}; };
static struct sctp_af sctp_ipv6_specific = { static struct sctp_af sctp_ipv6_specific = {
.queue_xmit = sctp_v6_xmit, .sctp_xmit = sctp_v6_xmit,
.setsockopt = ipv6_setsockopt, .setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt, .getsockopt = ipv6_getsockopt,
.get_dst = sctp_v6_get_dst, .get_dst = sctp_v6_get_dst,
.get_saddr = sctp_v6_get_saddr,
.copy_addrlist = sctp_v6_copy_addrlist, .copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb, .from_skb = sctp_v6_from_skb,
.from_sk = sctp_v6_from_sk, .from_sk = sctp_v6_from_sk,
...@@ -572,7 +644,7 @@ int sctp_v6_init(void) ...@@ -572,7 +644,7 @@ int sctp_v6_init(void)
/* Register the SCTP specfic AF_INET6 functions. */ /* Register the SCTP specfic AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific); sctp_register_af(&sctp_ipv6_specific);
/* Register notifier for inet6 address additions/deletions. */ /* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inetaddr_notifier); register_inet6addr_notifier(&sctp_inetaddr_notifier);
return 0; return 0;
......
...@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc); ...@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT(bind_addr); SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap);
/* An array to make it easy to pretty print the debug information /* An array to make it easy to pretty print the debug information
* to the proc fs. * to the proc fs.
...@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { ...@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(chunk), SCTP_DBG_OBJCNT_ENTRY(chunk),
SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap),
}; };
/* Callback from procfs to read out objcount information. /* Callback from procfs to read out objcount information.
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Forward declarations for private helpers. */ /* Forward declarations for private helpers. */
__u32 count_crc(__u8 *ptr, __u16 count);
static void sctp_packet_reset(sctp_packet_t *packet); static void sctp_packet_reset(sctp_packet_t *packet);
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
sctp_chunk_t *chunk); sctp_chunk_t *chunk);
...@@ -81,6 +80,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, ...@@ -81,6 +80,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
packet->ecn_capable = ecn_capable; packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler; packet->get_prepend_chunk = prepend_handler;
packet->has_cookie_echo = 0; packet->has_cookie_echo = 0;
packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */ /* We might need to call the prepend_handler right away. */
if (packet_empty) if (packet_empty)
...@@ -90,7 +90,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, ...@@ -90,7 +90,7 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
/* Initialize the packet structure. */ /* Initialize the packet structure. */
sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
sctp_transport_t *transport, struct sctp_transport *transport,
__u16 sport, __u16 sport,
__u16 dport) __u16 dport)
{ {
...@@ -102,6 +102,7 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, ...@@ -102,6 +102,7 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
packet->ecn_capable = 0; packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL; packet->get_prepend_chunk = NULL;
packet->has_cookie_echo = 0; packet->has_cookie_echo = 0;
packet->ipfragok = 0;
packet->malloced = 0; packet->malloced = 0;
sctp_packet_reset(packet); sctp_packet_reset(packet);
return packet; return packet;
...@@ -193,6 +194,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -193,6 +194,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
* transmit and rely on IP * transmit and rely on IP
* fragmentation. * fragmentation.
*/ */
packet->ipfragok = 1;
goto append; goto append;
} }
} else { /* !packet_empty */ } else { /* !packet_empty */
...@@ -228,13 +230,13 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -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 /* 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. * The return value is a normal kernel error return value.
*/ */
int sctp_packet_transmit(sctp_packet_t *packet) 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; sctp_association_t *asoc = transport->asoc;
struct sctphdr *sh; struct sctphdr *sh;
__u32 crc32; __u32 crc32;
...@@ -358,22 +360,14 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -358,22 +360,14 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* Note: Adler-32 is no longer applicable, as has been replaced * Note: Adler-32 is no longer applicable, as has been replaced
* by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>. * 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 /* 3) Put the resultant value into the checksum field in the
* common header, and leave the rest of the bits unchanged. * common header, and leave the rest of the bits unchanged.
*/ */
sh->checksum = htonl(crc32); sh->checksum = htonl(crc32);
/* FIXME: Delete the rest of this switch statement once phase 2
* of address selection (ipv6 support) drops in.
*/
switch (transport->ipaddr.sa.sa_family) {
case AF_INET6:
SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;)
break;
};
/* IP layer ECN support /* IP layer ECN support
* From RFC 2481 * From RFC 2481
* "The ECN-Capable Transport (ECT) bit would be set by the * "The ECN-Capable Transport (ECT) bit would be set by the
...@@ -423,8 +417,10 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -423,8 +417,10 @@ int sctp_packet_transmit(sctp_packet_t *packet)
} }
dst = transport->dst; 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_transport_route(transport, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc);
} }
nskb->dst = dst_clone(transport->dst); nskb->dst = dst_clone(transport->dst);
...@@ -433,14 +429,22 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -433,14 +429,22 @@ int sctp_packet_transmit(sctp_packet_t *packet)
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->sctp_xmit)(nskb, transport, packet->ipfragok);
out: out:
packet->size = SCTP_IP_OVERHEAD; packet->size = SCTP_IP_OVERHEAD;
return err; return err;
no_route: no_route:
kfree_skb(nskb); kfree_skb(nskb);
IP_INC_STATS_BH(IpOutNoRoutes); 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; goto out;
} }
...@@ -473,7 +477,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, ...@@ -473,7 +477,7 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight; size_t datasize, rwnd, inflight;
sctp_transport_t *transport = packet->transport; struct sctp_transport *transport = packet->transport;
__u32 max_burst_bytes; __u32 max_burst_bytes;
/* RFC 2960 6.1 Transmission of DATA Chunks /* RFC 2960 6.1 Transmission of DATA Chunks
......
This diff is collapsed.
...@@ -203,23 +203,3 @@ DECLARE_PRIMITIVE(SEND); ...@@ -203,23 +203,3 @@ DECLARE_PRIMITIVE(SEND);
*/ */
DECLARE_PRIMITIVE(REQUESTHEARTBEAT); 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) ...@@ -82,7 +82,7 @@ struct sock *sctp_get_ctl_sock(void)
} }
/* Set up the proc fs entry for the SCTP protocol. */ /* 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) { if (!proc_net_sctp) {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
...@@ -223,37 +223,6 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, ...@@ -223,37 +223,6 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
return error; 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. */ /* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr) int is_saddr)
...@@ -292,10 +261,12 @@ static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk) ...@@ -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. */ /* 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; struct rtable *rt = (struct rtable *)dst;
saddr->v4.sin_family = AF_INET; saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = port;
saddr->v4.sin_addr.s_addr = rt->rt_src; saddr->v4.sin_addr.s_addr = rt->rt_src;
} }
...@@ -394,6 +365,108 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) ...@@ -394,6 +365,108 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
return retval; 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. /* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list. * 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) ...@@ -545,6 +618,19 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return sctp_v4_available(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; struct sctp_af sctp_ipv4_specific;
static struct sctp_pf sctp_pf_inet = { static struct sctp_pf sctp_pf_inet = {
...@@ -601,10 +687,11 @@ static struct inet_protocol sctp_protocol = { ...@@ -601,10 +687,11 @@ static struct inet_protocol sctp_protocol = {
/* IPv4 address related functions. */ /* IPv4 address related functions. */
struct sctp_af sctp_ipv4_specific = { struct sctp_af sctp_ipv4_specific = {
.queue_xmit = ip_queue_xmit, .sctp_xmit = sctp_v4_xmit,
.setsockopt = ip_setsockopt, .setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt, .getsockopt = ip_getsockopt,
.get_dst = sctp_v4_get_dst, .get_dst = sctp_v4_get_dst,
.get_saddr = sctp_v4_get_saddr,
.copy_addrlist = sctp_v4_copy_addrlist, .copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb, .from_skb = sctp_v4_from_skb,
.from_sk = sctp_v4_from_sk, .from_sk = sctp_v4_from_sk,
...@@ -688,7 +775,7 @@ static void cleanup_sctp_mibs(void) ...@@ -688,7 +775,7 @@ static void cleanup_sctp_mibs(void)
} }
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
int sctp_init(void) __init int sctp_init(void)
{ {
int i; int i;
int status = 0; int status = 0;
...@@ -750,13 +837,9 @@ int sctp_init(void) ...@@ -750,13 +837,9 @@ int sctp_init(void)
/* Implementation specific variables. */ /* Implementation specific variables. */
/* Initialize default stream count setup information. /* Initialize default stream count setup information. */
* Note: today the stream accounting data structures are very sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS;
* fixed size, so one really does need to make sure that these have sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
* upper/lower limits when changing.
*/
sctp_proto.max_instreams = SCTP_MAX_STREAM;
sctp_proto.max_outstreams = SCTP_MAX_STREAM;
/* Allocate and initialize the association hash table. */ /* Allocate and initialize the association hash table. */
sctp_proto.assoc_hashsize = 4096; sctp_proto.assoc_hashsize = 4096;
...@@ -829,6 +912,7 @@ int sctp_init(void) ...@@ -829,6 +912,7 @@ int sctp_init(void)
sctp_get_local_addr_list(&sctp_proto); sctp_get_local_addr_list(&sctp_proto);
__unsafe(THIS_MODULE);
return 0; return 0;
err_ctl_sock_init: err_ctl_sock_init:
...@@ -852,7 +936,7 @@ int sctp_init(void) ...@@ -852,7 +936,7 @@ int sctp_init(void)
} }
/* Exit handler for the SCTP protocol. */ /* Exit handler for the SCTP protocol. */
void sctp_exit(void) __exit void sctp_exit(void)
{ {
/* BUG. This should probably do something useful like clean /* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory. * up all the remaining associations and all that memory.
...@@ -889,4 +973,3 @@ module_exit(sctp_exit); ...@@ -889,4 +973,3 @@ module_exit(sctp_exit);
MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>"); MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)"); MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* These functions manipulate sctp SSN tracker.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Storage size needed for map includes 2 headers and then the
* specific needs of in or out streams.
*/
static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
{
return sizeof(struct sctp_ssnmap) + (in + out) * sizeof(__u16);
}
/* Create a new sctp_ssnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority)
{
struct sctp_ssnmap *retval;
retval = kmalloc(sctp_ssnmap_size(in, out), priority);
if (!retval)
goto fail;
if (!sctp_ssnmap_init(retval, in, out))
goto fail_map;
retval->malloced = 1;
SCTP_DBG_OBJCNT_INC(ssnmap);
return retval;
fail_map:
kfree(retval);
fail:
return NULL;
}
/* Initialize a block of memory as a ssnmap. */
struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
__u16 out)
{
memset(map, 0x00, sctp_ssnmap_size(in, out));
/* Start 'in' stream just after the map header. */
map->in.ssn = (__u16 *)&map[1];
map->in.len = in;
/* Start 'out' stream just after 'in'. */
map->out.ssn = &map->in.ssn[in];
map->out.len = out;
return map;
}
/* Clear out the ssnmap streams. */
void sctp_ssnmap_clear(struct sctp_ssnmap *map)
{
size_t size;
size = (map->in.len + map->out.len) * sizeof(__u16);
memset(map->in.ssn, 0x00, size);
}
/* Dispose of a ssnmap. */
void sctp_ssnmap_free(struct sctp_ssnmap *map)
{
if (map && map->malloced) {
kfree(map);
SCTP_DBG_OBJCNT_DEC(ssnmap);
}
}
This diff is collapsed.
...@@ -606,9 +606,9 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( ...@@ -606,9 +606,9 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_chunk_t *chunk, int priority) sctp_chunk_t *chunk, int priority)
{ {
sctp_ulpevent_t *event; sctp_ulpevent_t *event, *levent;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *info;
struct sk_buff *skb; struct sk_buff *skb, *list;
size_t padding, len; size_t padding, len;
/* Clone the original skb, sharing the data. */ /* Clone the original skb, sharing the data. */
...@@ -647,6 +647,16 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -647,6 +647,16 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
event->malloced = 1; event->malloced = 1;
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
sctp_ulpevent_set_owner_r(list, asoc);
/* Initialize event with flags 0. */
levent = sctp_ulpevent_init(event, skb, 0);
if (!levent)
goto fail_init;
levent->malloced = 1;
}
info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo;
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
...@@ -762,8 +772,6 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -762,8 +772,6 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_ulpevent_t *event; sctp_ulpevent_t *event;
sctp_chunk_t *sack;
struct timer_list *timer;
/* Current stack structures assume that the rcv buffer is /* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as * per socket. For UDP style sockets this is not true as
...@@ -773,50 +781,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -773,50 +781,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
*/ */
event = (sctp_ulpevent_t *) skb->cb; event = (sctp_ulpevent_t *) skb->cb;
asoc = event->asoc; asoc = event->asoc;
if (asoc->rwnd_over) { sctp_assoc_rwnd_increase(asoc, skb_headlen(skb));
if (asoc->rwnd_over >= skb->len) {
asoc->rwnd_over -= skb->len;
} else {
asoc->rwnd += (skb->len - asoc->rwnd_over);
asoc->rwnd_over = 0;
}
} else {
asoc->rwnd += skb->len;
}
SCTP_DEBUG_PRINTK("rwnd increased by %d to (%u, %u) - %u\n",
skb->len, asoc->rwnd, asoc->rwnd_over, asoc->a_rwnd);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in Section 4.2.3.3
* of RFC 1122.
*/
if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
(asoc->rwnd > asoc->a_rwnd) &&
((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) {
SCTP_DEBUG_PRINTK("Sending window update SACK- rwnd: %u "
"a_rwnd: %u\n", asoc->rwnd, asoc->a_rwnd);
sack = sctp_make_sack(asoc);
if (!sack)
goto out;
/* Update the last advertised rwnd value. */
asoc->a_rwnd = asoc->rwnd;
asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0;
sctp_push_outqueue(&asoc->outqueue, sack);
/* Stop the SACK timer. */
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
if (timer_pending(timer) && del_timer(timer))
sctp_association_put(asoc);
}
out:
sctp_association_put(asoc); sctp_association_put(asoc);
} }
...@@ -838,16 +803,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a ...@@ -838,16 +803,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
skb->destructor = sctp_rcvmsg_rfree; skb->destructor = sctp_rcvmsg_rfree;
SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);
if (asoc->rwnd >= skb->len) {
asoc->rwnd -= skb->len;
} else {
asoc->rwnd_over = skb->len - asoc->rwnd;
asoc->rwnd = 0;
}
SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n",
skb->len, asoc->rwnd, asoc->rwnd_over);
} }
/* A simple destructor to give up the reference to the association. */ /* A simple destructor to give up the reference to the association. */
......
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