From 08707d5482df32631fb94f956e4bc3e0e0c89bac Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Mon, 19 Aug 2002 06:54:29 -0500 Subject: lksctp-2_5_31-0_5_1.patch --- Documentation/networking/sctp.txt | 38 + include/linux/in.h | 5 +- include/linux/net.h | 1 + include/linux/sctp.h | 590 ++++++ include/linux/socket.h | 1 + include/linux/sysctl.h | 16 + include/net/inet_common.h | 8 + include/net/ipv6.h | 10 +- include/net/sctp/sctp.h | 543 ++++++ include/net/sctp/sctp_command.h | 216 +++ include/net/sctp/sctp_constants.h | 454 +++++ include/net/sctp/sctp_sla1.h | 87 + include/net/sctp/sctp_sm.h | 430 +++++ include/net/sctp/sctp_structs.h | 1561 +++++++++++++++ include/net/sctp/sctp_tsnmap.h | 163 ++ include/net/sctp/sctp_ulpevent.h | 147 ++ include/net/sctp/sctp_ulpqueue.h | 102 + include/net/sctp/sctp_user.h | 609 ++++++ net/Config.in | 3 + net/Makefile | 1 + net/ipv4/af_inet.c | 6 +- net/ipv6/af_inet6.c | 10 +- net/ipv6/ipv6_syms.c | 14 + net/netsyms.c | 14 +- net/sctp/Config.help | 44 + net/sctp/Config.in | 20 + net/sctp/Makefile | 28 + net/sctp/sctp_adler32.c | 151 ++ net/sctp/sctp_associola.c | 1118 +++++++++++ net/sctp/sctp_bind_addr.c | 587 ++++++ net/sctp/sctp_command.c | 123 ++ net/sctp/sctp_crc32c.c | 199 ++ net/sctp/sctp_debug.c | 241 +++ net/sctp/sctp_endpointola.c | 417 ++++ net/sctp/sctp_hashdriver.c | 135 ++ net/sctp/sctp_input.c | 725 +++++++ net/sctp/sctp_inqueue.c | 219 +++ net/sctp/sctp_ipv6.c | 288 +++ net/sctp/sctp_objcnt.c | 142 ++ net/sctp/sctp_output.c | 600 ++++++ net/sctp/sctp_outqueue.c | 1515 +++++++++++++++ net/sctp/sctp_primitive.c | 195 ++ net/sctp/sctp_protocol.c | 646 +++++++ net/sctp/sctp_sla1.c | 285 +++ net/sctp/sctp_sm_make_chunk.c | 1859 ++++++++++++++++++ net/sctp/sctp_sm_sideeffect.c | 1280 +++++++++++++ net/sctp/sctp_sm_statefuns.c | 3825 +++++++++++++++++++++++++++++++++++++ net/sctp/sctp_sm_statetable.c | 1527 +++++++++++++++ net/sctp/sctp_socket.c | 2923 ++++++++++++++++++++++++++++ net/sctp/sctp_sysctl.c | 110 ++ net/sctp/sctp_transport.c | 476 +++++ net/sctp/sctp_tsnmap.c | 443 +++++ net/sctp/sctp_ulpevent.c | 927 +++++++++ net/sctp/sctp_ulpqueue.c | 542 ++++++ net/socket.c | 2 +- 55 files changed, 26607 insertions(+), 14 deletions(-) create mode 100644 Documentation/networking/sctp.txt create mode 100644 include/linux/sctp.h create mode 100644 include/net/sctp/sctp.h create mode 100644 include/net/sctp/sctp_command.h create mode 100644 include/net/sctp/sctp_constants.h create mode 100644 include/net/sctp/sctp_sla1.h create mode 100644 include/net/sctp/sctp_sm.h create mode 100644 include/net/sctp/sctp_structs.h create mode 100644 include/net/sctp/sctp_tsnmap.h create mode 100644 include/net/sctp/sctp_ulpevent.h create mode 100644 include/net/sctp/sctp_ulpqueue.h create mode 100644 include/net/sctp/sctp_user.h create mode 100644 net/sctp/Config.help create mode 100644 net/sctp/Config.in create mode 100644 net/sctp/Makefile create mode 100644 net/sctp/sctp_adler32.c create mode 100644 net/sctp/sctp_associola.c create mode 100644 net/sctp/sctp_bind_addr.c create mode 100644 net/sctp/sctp_command.c create mode 100644 net/sctp/sctp_crc32c.c create mode 100644 net/sctp/sctp_debug.c create mode 100644 net/sctp/sctp_endpointola.c create mode 100644 net/sctp/sctp_hashdriver.c create mode 100644 net/sctp/sctp_input.c create mode 100644 net/sctp/sctp_inqueue.c create mode 100644 net/sctp/sctp_ipv6.c create mode 100644 net/sctp/sctp_objcnt.c create mode 100644 net/sctp/sctp_output.c create mode 100644 net/sctp/sctp_outqueue.c create mode 100644 net/sctp/sctp_primitive.c create mode 100644 net/sctp/sctp_protocol.c create mode 100644 net/sctp/sctp_sla1.c create mode 100644 net/sctp/sctp_sm_make_chunk.c create mode 100644 net/sctp/sctp_sm_sideeffect.c create mode 100644 net/sctp/sctp_sm_statefuns.c create mode 100644 net/sctp/sctp_sm_statetable.c create mode 100644 net/sctp/sctp_socket.c create mode 100644 net/sctp/sctp_sysctl.c create mode 100644 net/sctp/sctp_transport.c create mode 100644 net/sctp/sctp_tsnmap.c create mode 100644 net/sctp/sctp_ulpevent.c create mode 100644 net/sctp/sctp_ulpqueue.c diff --git a/Documentation/networking/sctp.txt b/Documentation/networking/sctp.txt new file mode 100644 index 000000000000..0c790a76910e --- /dev/null +++ b/Documentation/networking/sctp.txt @@ -0,0 +1,38 @@ +Linux Kernel SCTP + +This is the current BETA release of the Linux Kernel SCTP reference +implementation. + +SCTP (Stream Control Transmission Protocol) is a IP based, message oriented, +reliable transport protocol, with congestion control, support for +transparent multi-homing, and multiple ordered streams of messages. +RFC2960 defines the core protocol. The IETF SIGTRAN working group originally +developed the SCTP protocol and later handed the protocol over to the +Transport Area (TSVWG) working group for the continued evolvement of SCTP as a +general purpose transport. + +See the IETF website (http://www.ietf.org) for further documents on SCTP. +See http://www.ietf.org/rfc/rfc2960.txt + +The initial project goal is to create an Linux kernel reference implementation +of SCTP that is RFC 2960 compliant and provides an programming interface +referred to as the UDP-style API of the Sockets Extensions for SCTP, as +proposed in IETF Internet-Drafts. + + +Caveats: + +-lksctp can be built as statically or as a module. However, be aware that +module removal of lksctp is not yet a safe activity. + +-There is tentative support for IPv6, but most work has gone towards +implementation and testing lksctp on IPv4. + + +For more information, please visit the lksctp project website: + http://www.sf.net/projects/lksctp + +Or contact the lksctp developers through the mailing list: + + + diff --git a/include/linux/in.h b/include/linux/in.h index f41a61dce932..eebfb0306d1b 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -37,11 +37,12 @@ enum { IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ - IPPROTO_PIM = 103, /* Protocol Independent Multicast */ - IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ IPPROTO_AH = 51, /* Authentication Header protocol */ + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ + IPPROTO_COMP = 108, /* Compression Header protocol */ + IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX diff --git a/include/linux/net.h b/include/linux/net.h index 8cd440ce36d6..c84c7033fed1 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -137,6 +137,7 @@ extern int sock_sendmsg(struct socket *, struct msghdr *m, int len); extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags); extern int sock_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * iov, long count, long size); +extern int sock_map_fd(struct socket *sock); extern int net_ratelimit(void); extern unsigned long net_random(void); diff --git a/include/linux/sctp.h b/include/linux/sctp.h new file mode 100644 index 000000000000..bca0f0f0682b --- /dev/null +++ b/include/linux/sctp.h @@ -0,0 +1,590 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/linux/sctp.h,v 1.7 2002/07/17 16:13:50 jgrimm Exp $ + * + * Various protocol defined structures. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * randall@sctp.chicago.il.us + * kmorneau@cisco.com + * qxie1@email.mot.com + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#ifndef __LINUX_SCTP_H__ +#define __LINUX_SCTP_H__ + +#include /* We need in_addr. */ +#include /* We need in6_addr. */ + + +/* Section 3.1. SCTP Common Header Format */ +typedef struct sctphdr { + uint16_t source; + uint16_t dest; + uint32_t vtag; + uint32_t checksum; +} sctp_sctphdr_t __attribute__((packed)); + +/* Section 3.2. Chunk Field Descriptions. */ +typedef struct sctp_chunkhdr { + uint8_t type; + uint8_t flags; + uint16_t length; +} sctp_chunkhdr_t __attribute__((packed)); + + +/* Section 3.2. Chunk Type Values. + * [Chunk Type] identifies the type of information contained in the Chunk + * Value field. It takes a value from 0 to 254. The value of 255 is + * reserved for future use as an extension field. + */ +typedef enum { + SCTP_CID_DATA = 0, + SCTP_CID_INIT = 1, + SCTP_CID_INIT_ACK = 2, + SCTP_CID_SACK = 3, + SCTP_CID_HEARTBEAT = 4, + SCTP_CID_HEARTBEAT_ACK = 5, + SCTP_CID_ABORT = 6, + SCTP_CID_SHUTDOWN = 7, + SCTP_CID_SHUTDOWN_ACK = 8, + SCTP_CID_ERROR = 9, + SCTP_CID_COOKIE_ECHO = 10, + SCTP_CID_COOKIE_ACK = 11, + SCTP_CID_ECN_ECNE = 12, + SCTP_CID_ECN_CWR = 13, + SCTP_CID_SHUTDOWN_COMPLETE = 14, + + /* Use hex, as defined in ADDIP sec. 3.1 */ + SCTP_CID_ASCONF = 0xC1, + SCTP_CID_ASCONF_ACK = 0x80, +} sctp_cid_t; /* enum */ + + +/* Section 3.2 + * Chunk Types are encoded such that the highest-order two bits specify + * the action that must be taken if the processing endpoint does not + * recognize the Chunk Type. + */ +typedef enum { + SCTP_CID_ACTION_DISCARD = 0x00, + SCTP_CID_ACTION_DISCARD_ERR = 0x40, + SCTP_CID_ACTION_SKIP = 0x80, + SCTP_CID_ACTION_SKIP_ERR = 0xc0, +} sctp_cid_action_t; + +enum { SCTP_CID_ACTION_MASK = 0xc0, }; + +/* This flag is used in Chunk Flags for ABORT and SHUTDOWN COMPLETE. + * + * 3.3.7 Abort Association (ABORT) (6): + * The T bit is set to 0 if the sender had a TCB that it destroyed. + * If the sender did not have a TCB it should set this bit to 1. + */ +enum { SCTP_CHUNK_FLAG_T = 0x01 }; + +/* + * Set the T bit + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 14 |Reserved |T| Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bits + * + * Reserved: 7 bits + * Set to 0 on transmit and ignored on receipt. + * + * T bit: 1 bit + * The T bit is set to 0 if the sender had a TCB that it destroyed. If + * the sender did NOT have a TCB it should set this bit to 1. + * + * Note: Special rules apply to this chunk for verification, please + * see Section 8.5.1 for details. + */ + +#define sctp_test_T_bit(c) ((c)->chunk_hdr->flags & SCTP_CHUNK_FLAG_T) + +/* RFC 2960 + * Section 3.2.1 Optional/Variable-length Parmaeter Format. + */ + +typedef struct sctp_paramhdr { + uint16_t type; + uint16_t length; +} sctp_paramhdr_t __attribute((packed)); + +typedef enum { + + /* RFC 2960 Section 3.3.5 */ + SCTP_PARAM_HEATBEAT_INFO = __constant_htons(1), + /* RFC 2960 Section 3.3.2.1 */ + SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), + SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), + SCTP_PARAM_STATE_COOKIE = __constant_htons(7), + SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8), + SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9), + SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11), + SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), + SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), + + /* Add-IP Extension. Section 3.2 */ + SCTP_PARAM_ADD_IP = __constant_htons(0xc001), + SCTP_PARAM_DEL_IP = __constant_htons(0xc002), + SCTP_PARAM_ERR_CAUSE = __constant_htons(0xc003), + SCTP_PARAM_SET_PRIMARY = __constant_htons(0xc004), + SCTP_PARAM_SUCCESS_REPORT = __constant_htons(0xc005), + SCTP_PARAM_ADAPTION_LAYER_IND = __constant_htons(0xc006), + +} sctp_param_t; /* enum */ + + +/* RFC 2960 Section 3.2.1 + * The Parameter Types are encoded such that the highest-order two bits + * specify the action that must be taken if the processing endpoint does + * not recognize the Parameter Type. + * + */ +typedef enum { + SCTP_PARAM_ACTION_DISCARD = __constant_htons(0x0000), + SCTP_PARAM_ACTION_DISCARD_ERR = __constant_htons(0x4000), + SCTP_PARAM_ACTION_SKIP = __constant_htons(0x8000), + SCTP_PARAM_ACTION_SKIP_ERR = __constant_htons(0xc000), +} sctp_param_action_t; + + +/* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ + +typedef struct sctp_datahdr { + uint32_t tsn; + uint16_t stream; + uint16_t ssn; + uint32_t ppid; + uint8_t payload[0]; +} sctp_datahdr_t __attribute__((packed)); + +typedef struct sctp_data_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_datahdr_t data_hdr; +} sctp_data_chunk_t __attribute__((packed)); + +/* DATA Chuck Specific Flags */ +enum { + SCTP_DATA_MIDDLE_FRAG = 0x00, + SCTP_DATA_LAST_FRAG = 0x01, + SCTP_DATA_FIRST_FRAG = 0x02, + SCTP_DATA_NOT_FRAG = 0x03, + SCTP_DATA_UNORDERED = 0x04, +}; +enum { SCTP_DATA_FRAG_MASK = 0x03, }; + + +/* RFC 2960 Section 3.3.2 Initiation (INIT) (1) + * + * This chunk is used to initiate a SCTP association between two + * endpoints. + */ +typedef struct sctp_inithdr { + uint32_t init_tag; + uint32_t a_rwnd; + uint16_t num_outbound_streams; + uint16_t num_inbound_streams; + uint32_t initial_tsn; + uint8_t params[0]; +} sctp_inithdr_t __attribute__((packed)); + +typedef struct sctp_init_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_inithdr_t init_hdr; +} sctp_init_chunk_t __attribute__((packed)); + + +/* Section 3.3.2.1. IPv4 Address Parameter (5) */ +typedef struct sctp_ipv4addr_param { + sctp_paramhdr_t param_hdr; + struct in_addr addr; +} sctp_ipv4addr_param_t __attribute__((packed)); + +/* Section 3.3.2.1. IPv6 Address Parameter (6) */ +typedef struct sctp_ipv6addr_param { + sctp_paramhdr_t param_hdr; + struct in6_addr addr; +} sctp_ipv6addr_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Cookie Preservative (9) */ +typedef struct sctp_cookie_preserve_param { + sctp_paramhdr_t param_hdr; + uint32_t lifespan_increment; +} sctp_cookie_preserve_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Host Name Address (11) */ +typedef struct sctp_hostname_param { + sctp_paramhdr_t param_hdr; + uint8_t hostname[0]; +} sctp_hostname_param_t __attribute__((packed)); + +/* Section 3.3.2.1 Supported Address Types (12) */ +typedef struct sctp_supported_addrs_param { + sctp_paramhdr_t param_hdr; + uint16_t types[0]; +} sctp_supported_addrs_param_t __attribute__((packed)); + +/* Appendix A. ECN Capable (32768) */ +typedef struct sctp_ecn_capable_param { + sctp_paramhdr_t param_hdr; +} sctp_ecn_capable_param_t __attribute__((packed)); + + + +/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): + * The INIT ACK chunk is used to acknowledge the initiation of an SCTP + * association. + */ +typedef sctp_init_chunk_t sctp_initack_chunk_t; + +/* Section 3.3.3.1 State Cookie (7) */ +typedef struct sctp_cookie_param { + sctp_paramhdr_t p; + uint8_t body[0]; +} sctp_cookie_param_t __attribute__((packed)); + +/* Section 3.3.3.1 Unrecognized Parameters (8) */ +typedef struct sctp_unrecognized_param { + sctp_paramhdr_t param_hdr; + sctp_paramhdr_t unrecognized; +} sctp_unrecognized_param_t __attribute__((packed)); + + + +/* + * 3.3.4 Selective Acknowledgement (SACK) (3): + * + * This chunk is sent to the peer endpoint to acknowledge received DATA + * chunks and to inform the peer endpoint of gaps in the received + * subsequences of DATA chunks as represented by their TSNs. + */ + +typedef struct sctp_gap_ack_block { + uint16_t start; + uint16_t end; +} sctp_gap_ack_block_t __attribute__((packed)); + +typedef uint32_t sctp_dup_tsn_t; + +typedef union { + sctp_gap_ack_block_t gab; + sctp_dup_tsn_t dup; +} sctp_sack_variable_t; + +typedef struct sctp_sackhdr { + uint32_t cum_tsn_ack; + uint32_t a_rwnd; + uint16_t num_gap_ack_blocks; + uint16_t num_dup_tsns; + sctp_sack_variable_t variable[0]; +} sctp_sackhdr_t __attribute__((packed)); + +typedef struct sctp_sack_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_sackhdr_t sack_hdr; +} sctp_sack_chunk_t __attribute__((packed)); + + +/* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4): + * + * An endpoint should send this chunk to its peer endpoint to probe the + * reachability of a particular destination transport address defined in + * the present association. + */ + +typedef struct sctp_heartbeathdr { + sctp_paramhdr_t info; +} sctp_heartbeathdr_t __attribute__((packed)); + +typedef struct sctp_heartbeat_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_heartbeathdr_t hb_hdr; +} sctp_heartbeat_chunk_t __attribute__((packed)); + + +/* For the abort and shutdown ACK we must carry the init tag in the + * common header. Just the common header is all that is needed with a + * chunk descriptor. + */ +typedef struct sctp_abort_chunk { + sctp_chunkhdr_t uh; +} sctp_abort_chunkt_t __attribute__((packed)); + + +/* For the graceful shutdown we must carry the tag (in common header) + * and the highest consecutive acking value. + */ +typedef struct sctp_shutdownhdr { + uint32_t cum_tsn_ack; +} sctp_shutdownhdr_t __attribute__((packed)); + +struct sctp_shutdown_chunk_t { + sctp_chunkhdr_t chunk_hdr; + sctp_shutdownhdr_t shutdown_hdr; +} __attribute__((packed)); + + + +/* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ + +typedef struct sctp_errhdr { + uint16_t cause; + uint16_t length; + uint8_t variable[0]; +} sctp_errhdr_t __attribute__((packed)); + +typedef struct sctp_operr_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_errhdr_t err_hdr; +} sctp_operr_chunk_t __attribute__((packed)); + +/* RFC 2960 3.3.10 - Operation Error + * + * Cause Code: 16 bits (unsigned integer) + * + * Defines the type of error conditions being reported. + * Cause Code + * Value Cause Code + * --------- ---------------- + * 1 Invalid Stream Identifier + * 2 Missing Mandatory Parameter + * 3 Stale Cookie Error + * 4 Out of Resource + * 5 Unresolvable Address + * 6 Unrecognized Chunk Type + * 7 Invalid Mandatory Parameter + * 8 Unrecognized Parameters + * 9 No User Data + * 10 Cookie Received While Shutting Down + */ +typedef enum { + + SCTP_ERROR_NO_ERROR = __constant_htons(0x00), + SCTP_ERROR_INV_STRM = __constant_htons(0x01), + SCTP_ERROR_MISS_PARAM = __constant_htons(0x02), + SCTP_ERROR_STALE_COOKIE = __constant_htons(0x03), + SCTP_ERROR_NO_RESOURCE = __constant_htons(0x04), + SCTP_ERROR_DNS_FAILED = __constant_htons(0x05), + SCTP_ERROR_UNKNOWN_CHUNK = __constant_htons(0x06), + SCTP_ERROR_INV_PARAM = __constant_htons(0x07), + SCTP_ERROR_UNKNOWN_PARAM = __constant_htons(0x08), + SCTP_ERROR_NO_DATA = __constant_htons(0x09), + SCTP_ERROR_COOKIE_IN_SHUTDOWN = __constant_htons(0x0a), + + + /* SCTP Implementation Guide: + * 11 Restart of an association with new addresses + * 12 User Initiated Abort + */ + + SCTP_ERROR_RESTART = __constant_htons(0x0b), + SCTP_ERROR_USER_ABORT = __constant_htons(0x0c), + + /* ADDIP Section 3.3 New Error Causes + * + * Four new Error Causes are added to the SCTP Operational Errors, + * primarily for use in the ASCONF-ACK chunk. + * + * Value Cause Code + * --------- ---------------- + * 0x0100 Request to Delete Last Remaining IP Address. + * 0x0101 Operation Refused Due to Resource Shortage. + * 0x0102 Request to Delete Source IP Address. + * 0x0103 Association Aborted due to illegal ASCONF-ACK + */ + SCTP_ERROR_DEL_LAST_IP = __constant_htons(0x0100), + SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101), + SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102), + SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103), + +} sctp_error_t; + + + +/* RFC 2960. Appendix A. Explicit Congestion Notification. + * Explicit Congestion Notification Echo (ECNE) (12) + */ +typedef struct sctp_ecnehdr { + uint32_t lowest_tsn; +} sctp_ecnehdr_t; + +typedef struct sctp_ecne_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_ecnehdr_t ence_hdr; +} sctp_ecne_chunk_t __attribute__((packed)); + +/* RFC 2960. Appendix A. Explicit Congestion Notification. + * Congestion Window Reduced (CWR) (13) + */ +typedef struct sctp_cwrhdr { + uint32_t lowest_tsn; +} sctp_cwrhdr_t; + +typedef struct sctp_cwr_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_cwrhdr_t cwr_hdr; +} sctp_cwr_chunk_t __attribute__((packed)); + + +/* FIXME: Cleanup needs to continue below this line. */ + +/* + * ADDIP Section 3.1 New Chunk Types + */ + + +/* ADDIP Section 3.1.1 + * + * ASCONF-Request Correlation ID: 32 bits (unsigned integer) + * + * This is an opaque integer assigned by the sender to identify each + * request parameter. It is in host byte order and is only meaningful + * to the sender. The receiver of the ASCONF Chunk will copy this 32 + * bit value into the ASCONF Correlation ID field of the + * ASCONF-ACK. The sender of the ASCONF can use this same value in the + * ASCONF-ACK to find which request the response is for. + * + * ASCONF Parameter: TLV format + * + * Each Address configuration change is represented by a TLV parameter + * as defined in Section 3.2. One or more requests may be present in + * an ASCONF Chunk. + */ +typedef struct { + uint32_t correlation; + sctp_paramhdr_t p; + uint8_t payload[0]; +} sctpAsconfReq_t; + +/* ADDIP + * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * + * This chunk is used to communicate to the remote endpoint one of the + * configuration change requests that MUST be acknowledged. The + * information carried in the ASCONF Chunk uses the form of a + * Tag-Length-Value (TLV), as described in "3.2.1 + * Optional/Variable-length Parameter Format" in [RFC2960], for all + * variable parameters. + */ +typedef struct { + uint32_t serial; + uint8_t reserved[3]; + uint8_t addr_type; + uint32_t addr[4]; + sctpAsconfReq_t requests[0]; +} sctpAsconf_t; + +/* ADDIP + * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) + * + * ASCONF-Request Correlation ID: 32 bits (unsigned integer) + * + * This value is copied from the ASCONF Correlation ID received in the + * ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify + * which ASCONF parameter this response is associated with. + * + * ASCONF Parameter Response : TLV format + * + * The ASCONF Parameter Response is used in the ASCONF-ACK to report + * status of ASCONF processing. By default, if a responding endpoint + * does not include any Error Cause, a success is indicated. Thus a + * sender of an ASCONF-ACK MAY indicate complete success of all TLVs in + * an ASCONF by returning only the Chunk Type, Chunk Flags, Chunk Length + * (set to 8) and the Serial Number. + */ +typedef union { + struct { + uint32_t correlation; + sctp_paramhdr_t header; /* success report */ + } success; + struct { + uint32_t correlation; + sctp_paramhdr_t header; /* error cause indication */ + sctp_paramhdr_t errcause; + uint8_t request[0]; /* original request from ASCONF */ + } error; +#define __correlation success.correlation +#define __header success.header +#define __cause error.errcause +#define __request error.request +} sctpAsconfAckRsp_t; + +/* ADDIP + * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) + * + * This chunk is used by the receiver of an ASCONF Chunk to + * acknowledge the reception. It carries zero or more results for any + * ASCONF Parameters that were processed by the receiver. + */ +typedef struct { + uint32_t serial; + sctpAsconfAckRsp_t responses[0]; +} sctpAsconfAck_t; + +/********************************************************************* + * Internal structures + * + * These are data structures which never go out on the wire. + *********************************************************************/ + +/* What is this data structure for? The TLV isn't one--it is just a + * value. Perhaps this data structure ought to have a type--otherwise + * it is not unambigiously parseable. --piggy + */ +typedef struct { + struct list_head hook; + int length; /* length of the TLV */ + + /* the actually TLV to be copied into ASCONF_ACK */ + sctpAsconfAckRsp_t TLV; +} sctpAsconfAckRspNode_t; + + + + +#endif /* __LINUX_SCTP_H__ */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 74303f129fdd..f8e90303576d 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -227,6 +227,7 @@ struct ucred { #define SOL_UDP 17 #define SOL_IPV6 41 #define SOL_ICMPV6 58 +#define SOL_SCTP 132 #define SOL_RAW 255 #define SOL_IPX 256 #define SOL_AX25 257 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 07eed48ea3f8..4c598d745e2e 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -172,6 +172,7 @@ enum NET_TR=14, NET_DECNET=15, NET_ECONET=16, + NET_SCTP=17, }; /* /proc/sys/kernel/random */ @@ -516,6 +517,21 @@ enum { NET_DECNET_CONF_DEV_STATE = 7 }; +/* /proc/sys/net/sctp */ +enum { + NET_SCTP_RTO_INITIAL = 1, + NET_SCTP_RTO_MIN = 2, + NET_SCTP_RTO_MAX = 3, + NET_SCTP_RTO_ALPHA = 4, + NET_SCTP_RTO_BETA = 5, + NET_SCTP_VALID_COOKIE_LIFE = 6, + NET_SCTP_ASSOCIATION_MAX_RETRANS = 7, + NET_SCTP_PATH_MAX_RETRANS = 8, + NET_SCTP_MAX_INIT_RETRANSMITS = 9, + NET_SCTP_HB_INTERVAL = 10, + NET_SCTP_MAX_BURST = 11, +}; + /* CTL_PROC names: */ /* CTL_FS names: */ diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 87b3fd324347..bbb1fa70099e 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -43,6 +43,14 @@ extern void inet_sock_release(struct sock *sk); extern void inet_sock_destruct(struct sock *sk); extern atomic_t inet_sock_nr; +extern int inet_bind(struct socket *sock, + struct sockaddr *uaddr, int addr_len); +extern int inet_getname(struct socket *sock, + struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet_ioctl(struct socket *sock, + unsigned int cmd, unsigned long arg); + #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 55ca37370540..1c7a736a2796 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.23 2000/12/13 18:31:48 davem Exp $ + * $Id: ipv6.h,v 1.1 2002/05/20 15:13:07 jgrimm Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -336,6 +336,14 @@ extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, u16 u32 info, u8 *payload); extern void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info); +extern int inet6_release(struct socket *sock); +extern int inet6_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len); +extern int inet6_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer); +extern int inet6_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); + #endif /* __KERNEL__ */ #endif /* _NET_IPV6_H */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h new file mode 100644 index 000000000000..5875cc068e1b --- /dev/null +++ b/include/net/sctp/sctp.h @@ -0,0 +1,543 @@ +/* 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 Intel Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Id: sctp.h,v 1.39 2002/08/16 19:30:49 jgrimm Exp $ + * + * The base lksctp header. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Xingang Guo + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __net_sctp_h__ +#define __net_sctp_h__ + +/* Header Strategy. + * Start getting some control over the header file depencies: + * includes + * constants + * structs + * prototypes + * macros, externs, and inlines + * + * Move test_frame specific items out of the kernel headers + * and into the test frame headers. This is not perfect in any sense + * and will continue to evolve. + */ + + +#include + +#ifdef TEST_FRAME +#undef CONFIG_PROC_FS +#undef CONFIG_SCTP_DBG_OBJCNT +#undef CONFIG_SYSCTL +#endif /* TEST_FRAME */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + + +/* Set SCTP_DEBUG flag via config if not already set. */ +#ifndef SCTP_DEBUG +#ifdef CONFIG_SCTP_DBG_MSG +#define SCTP_DEBUG 1 +#else +#define SCTP_DEBUG 0 +#endif /* CONFIG_SCTP_DBG */ +#endif /* SCTP_DEBUG */ + +#ifdef CONFIG_IP_SCTP_MODULE +#define SCTP_PROTOSW_FLAG 0 +#else /* static! */ +#define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT +#endif + +/* + * Function declarations. + */ + +/* + * sctp_protocol.c + */ +extern sctp_protocol_t sctp_proto; +extern struct sock *sctp_get_ctl_sock(void); +extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, + sctp_scope_t, int priority, int flags); + + +/* + * sctp_socket.c + */ +extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +extern int sctp_inet_listen(struct socket *sock, int backlog); +extern int sctp_get_port(struct sock *sk, unsigned short snum); +extern void sctp_write_space(struct sock *sk); +extern unsigned int sctp_poll(struct file *file, struct socket *sock, + poll_table *wait); + +/* + * sctp_primitive.c + */ +extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); +extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); +extern int sctp_primitive_SEND(sctp_association_t *, void *arg); + + +/* + * sctp_crc32c.c + */ +extern uint32_t count_crc(uint8_t *ptr, uint16_t count); + +/* + * sctp_input.c + */ +extern int sctp_rcv(struct sk_buff *skb); +extern void sctp_v4_err(struct sk_buff *skb, u32 info); +extern void sctp_hash_established(sctp_association_t *); +extern void __sctp_hash_established(sctp_association_t *); +extern void sctp_unhash_established(sctp_association_t *); +extern void __sctp_unhash_established(sctp_association_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 *); + +/* + * sctp_hashdriver.c + */ +extern void sctp_hash_digest(const char *secret, const int secret_len, + const char *text, const int text_len, + uint8_t *digest); + +/* + * Section: Macros, externs, and inlines + */ + + +#ifdef TEST_FRAME + +#include + +#else + +/* spin lock wrappers. */ +#define sctp_spin_lock_irqsave(lock, flags) spin_lock_irqsave(lock, flags) +#define sctp_spin_unlock_irqrestore(lock, flags) \ + spin_unlock_irqrestore(lock, flags) +#define sctp_local_bh_disable() local_bh_disable() +#define sctp_local_bh_enable() local_bh_enable() +#define sctp_spin_lock(lock) spin_lock(lock) +#define sctp_spin_unlock(lock) spin_unlock(lock) +#define sctp_write_lock(lock) write_lock(lock) +#define sctp_write_unlock(lock) write_unlock(lock) +#define sctp_read_lock(lock) read_lock(lock) +#define sctp_read_unlock(lock) read_unlock(lock) + +/* sock lock wrappers. */ +#define sctp_lock_sock(sk) lock_sock(sk) +#define sctp_release_sock(sk) release_sock(sk) +#define sctp_bh_lock_sock(sk) bh_lock_sock(sk) +#define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk) +#define __sctp_sock_busy(sk) ((sk)->lock.users) +#define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk) +#define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) + + +/* Determine if this is a valid kernel address. + */ +static inline int +sctp_is_valid_kaddr(unsigned long addr) +{ + struct page *page; + + /* Make sure the address is not in the user address space. */ + if (addr < PAGE_OFFSET) { + return 0; + } + + page = virt_to_page(addr); + + /* Is this page valid? */ + if (!virt_addr_valid(addr) || PageReserved(page)) { + return 0; + } + + return 1; + +} /* sctp_is_valid_kaddr() */ + + +#endif /* !TEST_FRAME */ + + +/* Print debugging messages. */ +#if SCTP_DEBUG +extern int sctp_debug_flag; +#define SCTP_DEBUG_PRINTK(whatever...) \ + ((void) (sctp_debug_flag && printk(KERN_DEBUG whatever))) +#define SCTP_ENABLE_DEBUG { sctp_debug_flag = 1; } +#define SCTP_DISABLE_DEBUG { sctp_debug_flag = 0; } + +#define SCTP_ASSERT(expr, str, func) \ + if (!(expr)) { \ + SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \ + str, (#expr), __FILE__, __FUNCTION__, __LINE__); \ + func; \ + } + +#else /* SCTP_DEBUG */ + +#define SCTP_DEBUG_PRINTK(whatever...) +#define SCTP_ENABLE_DEBUG +#define SCTP_DISABLE_DEBUG +#define SCTP_ASSERT(expr, str, func) + +#endif /* SCTP_DEBUG */ + + +/* + * Macros for keeping a global reference of object allocations. + */ +#ifdef CONFIG_SCTP_DBG_OBJCNT + +extern atomic_t sctp_dbg_objcnt_sock; +extern atomic_t sctp_dbg_objcnt_ep; +extern atomic_t sctp_dbg_objcnt_assoc; +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; + +/* Macros to atomically increment/decrement objcnt counters. +*/ +#define SCTP_DBG_OBJCNT_INC(name) \ +atomic_inc(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT_DEC(name) \ +atomic_dec(&sctp_dbg_objcnt_## name) +#define SCTP_DBG_OBJCNT(name) \ +atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) + +/* Macro to help create new entries in in the global array of + * objcnt counters. + */ +#define SCTP_DBG_OBJCNT_ENTRY(name) \ +{.label= #name, .counter= &sctp_dbg_objcnt_## name} + +extern void sctp_dbg_objcnt_init(void); +extern void sctp_dbg_objcnt_exit(void); + +#else + +#define SCTP_DBG_OBJCNT_INC(name) +#define SCTP_DBG_OBJCNT_DEC(name) + +static inline void sctp_dbg_objcnt_init(void) { return; } +static inline void sctp_dbg_objcnt_exit(void) { return; } + +#endif /* CONFIG_SCTP_DBG_OBJCOUNT */ + +#if defined CONFIG_SYSCTL +extern void sctp_sysctl_register(void); +extern void sctp_sysctl_unregister(void); +#else +static inline void sctp_sysctl_register(void) { return; } +static inline void sctp_sysctl_unregister(void) { return; } +#endif + + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +extern int sctp_v6_init(void); +extern void sctp_v6_exit(void); + +static inline int +sctp_ipv6_addr_type(const struct in6_addr* addr) +{ + return(ipv6_addr_type((struct in6_addr*)addr)); +} + +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(uint16_t)) + +/* Note: These V6 macros are obsolescent. */ +/* Use this macro to enclose code fragments which are V6-dependent. */ +#define SCTP_V6(m...) m +#define SCTP_V6_SUPPORT 1 + +#else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ + +#define sctp_ipv6_addr_type(a) 0 +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(uint16_t)) +#define SCTP_V6(m...) /* Do nothing. */ +#undef SCTP_V6_SUPPORT + +static inline int sctp_v6_init(void) { return 0; } +static inline void sctp_v6_exit(void) {return; } + +#endif /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ + + +/* Map an association to an assoc_id. */ +static inline sctp_assoc_t +sctp_assoc2id(const sctp_association_t *asoc) +{ + return ((sctp_assoc_t)asoc); + +} /* sctp_assoc2id() */ + + +/* Look up the association by its id. + */ +static inline sctp_association_t * +sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) +{ + sctp_association_t *asoc = NULL; + + /* First, verify that this is a kernel address. */ + if (sctp_is_valid_kaddr((unsigned long)id)) { + sctp_association_t *temp; + temp = (sctp_association_t *)id; + + /* Verify that this _is_ an sctp_association_t + * data structure and if so, that the socket matches. + */ + if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) + && (temp->base.sk == sk)) { + asoc = temp; + } + } + + return(asoc); + +} /* sctp_id2assoc() */ + +/* A macro to walk a list of skbs. */ +#define sctp_skb_for_each(pos, head, tmp) \ +for (pos = (head)->next;\ + tmp = (pos)->next, pos != ((struct sk_buff *)(head));\ + pos = tmp) + + +/* A helper to append an entire skb list (list) to another (head). */ +static inline void +sctp_skb_list_tail(struct sk_buff_head *list, + struct sk_buff_head *head) +{ + int flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&head->lock, flags); + sctp_spin_lock(&list->lock); + + list_splice((struct list_head *)list, (struct list_head *)head->prev); + + head->qlen += list->qlen; + list->qlen = 0; + + sctp_spin_unlock(&list->lock); + sctp_spin_unlock_irqrestore(&head->lock, flags); + +} /* sctp_skb_list_tail() */ + +/** + * sctp_list_dequeue - remove from the head of the queue + * @list: list to dequeue from + * + * Remove the head of the list. The head item is + * returned or %NULL if the list is empty. + */ + +static inline struct list_head * +sctp_list_dequeue(struct list_head *list) +{ + struct list_head *result; + + result = (void *) 0; + if ( list->next != list ) { + result = list->next; + list->next = result->next; + list->next->prev = list; + INIT_LIST_HEAD(result); + } + return result; + +} /* sctp_list_dequeue() */ + + +/* Calculate the size (in bytes) occupied by the data of an iovec. */ +static inline size_t +get_user_iov_size(struct iovec *iov, int iovlen) { + size_t retval; + + retval = 0; + + for (; iovlen > 0; --iovlen) { + retval += iov->iov_len; + iov++; + } + + return(retval); + +} /* get_user_iov_size() */ + + +/* Round an int up to the next multiple of 4. */ +#define WORD_ROUND(s) (((s)+3)&~3) + +/* Make a new instance of type. */ +#define t_new(type, flags) (type *)kmalloc(sizeof(type), flags) + +/* Compare two timevals. */ +#define tv_lt(s, t) \ + (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec)) + +/* Stolen from net/profile.h. Using it from there is more grief than + * it is worth. + */ +static inline void +tv_add(const struct timeval *entered, struct timeval *leaved) +{ + time_t usecs = leaved->tv_usec + entered->tv_usec; + time_t secs = leaved->tv_sec + entered->tv_sec; + + if (usecs >= 1000000) { + usecs -= 1000000; + secs++; + } + leaved->tv_sec = secs; + leaved->tv_usec = usecs; + +} /* tv_add() */ + + +/* External references. */ + +extern struct proto sctp_prot; +extern struct proc_dir_entry *proc_net_sctp; +extern void sctp_put_port(struct sock *sk); + +/* Static inline functions. */ + +/* Return the SCTP protocol structure. */ +static inline sctp_protocol_t *sctp_get_protocol(void) +{ + return(&sctp_proto); + +} /* sctp_get_protocol() */ + + +/* Warning: The following hash functions assume a power of two 'size'. */ +/* This is the hash function for the SCTP port hash table. */ +static inline int sctp_phashfn(uint16_t lport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + return (lport & (sctp_proto->port_hashsize - 1)); + +} /* sctp_phashfn() */ + +/* This is the hash function for the endpoint hash table. */ +static inline int sctp_ep_hashfn(uint16_t lport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + return (lport & (sctp_proto->ep_hashsize - 1)); + +} /* sctp_ep_hashfn() */ + +/* This is the hash function for the association hash table. */ +static inline int sctp_assoc_hashfn(uint16_t lport, uint16_t rport) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + int h = (lport << 16) + rport; + h ^= h>>8; + return (h & (sctp_proto->assoc_hashsize-1)); + +} /* sctp_ep_hashfn() */ + +/* This is the hash function for the association hash table. This is + * not used yet, but could be used as a better hash function when + * we have a vtag. +*/ +static inline int sctp_vtag_hashfn(uint16_t lport, uint16_t rport, + uint32_t vtag) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + int h = (lport << 16) + rport; + h ^= vtag; + return (h & (sctp_proto->assoc_hashsize-1)); + +} /* sctp_vtag_hashfn() */ + +/* WARNING: Do not change the layout of the members in sctp_sock! */ +struct sctp_sock { + struct sock sk; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct ipv6_pinfo *pinet6; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + struct inet_opt inet; + struct sctp_opt sctp; +}; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +struct sctp6_sock { + struct sock sk; + struct ipv6_pinfo *pinet6; + struct inet_opt inet; + struct sctp_opt sctp; + struct ipv6_pinfo inet6; +}; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + +#define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) + +#endif /* __net_sctp_h__ */ diff --git a/include/net/sctp/sctp_command.h b/include/net/sctp/sctp_command.h new file mode 100644 index 000000000000..86f23e7dca00 --- /dev/null +++ b/include/net/sctp/sctp_command.h @@ -0,0 +1,216 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, and IBM + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_command.h,v 1.19 2002/08/16 19:30:49 jgrimm Exp $ + * + * These are the definitions needed for the command object. + * + * 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 one of the + * following email addresses: + * + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#ifndef __net_sctp_command_h__ +#define __net_sctp_command_h__ + +#include +#include + + +typedef enum { + SCTP_CMD_NOP = 0, /* Do nothing. */ + SCTP_CMD_NEW_ASOC, /* Register a new association. */ + SCTP_CMD_DELETE_TCB, /* Delete the current association. */ + SCTP_CMD_NEW_STATE, /* Enter a new state. */ + SCTP_CMD_REPORT_TSN, /* Record the arrival of a TSN. */ + SCTP_CMD_GEN_SACK, /* Send a Selective ACK (maybe). */ + SCTP_CMD_PROCESS_SACK, /* Process an inbound SACK. */ + SCTP_CMD_GEN_INIT_ACK, /* Generate an INIT ACK chunk. */ + SCTP_CMD_PEER_INIT, /* Process a INIT from the peer. */ + SCTP_CMD_GEN_COOKIE_ECHO, /* Generate a COOKIE ECHO chunk. */ + SCTP_CMD_CHUNK_ULP, /* Send a chunk to the sockets layer. */ + SCTP_CMD_EVENT_ULP, /* Send a notification to the sockets layer. */ + SCTP_CMD_REPLY, /* Send a chunk to our peer. */ + SCTP_CMD_SEND_PKT, /* Send a full packet to our peer. */ + SCTP_CMD_RETRAN, /* Mark a transport for retransmission. */ + SCTP_CMD_ECN_CE, /* Do delayed CE processing. */ + SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */ + SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */ + SCTP_CMD_TIMER_START, /* Start a timer. */ + SCTP_CMD_TIMER_RESTART, /* Restart a timer. */ + SCTP_CMD_TIMER_STOP, /* Stop a timer. */ + SCTP_CMD_COUNTER_RESET, /* Reset a counter. */ + SCTP_CMD_COUNTER_INC, /* Increment a counter. */ + SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */ + 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_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. */ + SCTP_CMD_REPORT_BAD_TAG, /* Verification tags didn't match. */ + SCTP_CMD_PROCESS_CTSN, /* Sideeffect from shutdown. */ + SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ + SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */ + SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ + SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ + SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ + SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ + + SCTP_CMD_LAST +} sctp_verb_t; /* enum */ + +#define SCTP_CMD_MAX (SCTP_CMD_LAST - 1) +#define SCTP_CMD_NUM_VERBS (SCTP_CMD_MAX + 1) + +/* How many commands can you put in an sctp_cmd_seq_t? + * This is a rather arbitrary number, ideally derived from a careful + * analysis of the state functions, but in reality just taken from + * thin air in the hopes othat we don't trigger a kernel panic. + */ +#define SCTP_MAX_NUM_COMMANDS 14 + +typedef union { + int32_t i32; + uint32_t u32; + uint16_t u16; + uint8_t u8; + int error; + sctp_state_t state; + sctp_event_timeout_t to; + sctp_counter_t counter; + void *ptr; + sctp_chunk_t *chunk; + sctp_association_t *asoc; + sctp_transport_t *transport; + sctp_bind_addr_t *bp; + sctp_init_chunk_t *init; + sctp_ulpevent_t *ulpevent; + sctp_packet_t *packet; + sctp_sackhdr_t *sackh; +} sctp_arg_t; + +/* We are simulating ML type constructors here. + * + * SCTP_ARG_CONSTRUCTOR(NAME, TYPE, ELT) builds a function called + * SCTP_NAME() which takes an argument of type TYPE and returns an + * sctp_arg_t. It does this by inserting the sole argument into the + * ELT union element of a local sctp_arg_t. + * + * E.g., SCTP_ARG_CONSTRUCTOR(I32, int32_t, i32) builds SCTP_I32(arg), + * which takes an int32_t and returns a sctp_arg_t containing the + * int32_t. So, after foo = SCTP_I32(arg), foo.i32 == arg. + */ +static inline sctp_arg_t +SCTP_NULL(void) +{ + sctp_arg_t retval; retval.ptr = NULL; return(retval); +} +static inline sctp_arg_t +SCTP_NOFORCE(void) +{ + sctp_arg_t retval; retval.i32 = 0; return(retval); +} +static inline sctp_arg_t +SCTP_FORCE(void) +{ + sctp_arg_t retval; retval.i32 = 1; return(retval); +} + +#define SCTP_ARG_CONSTRUCTOR(name, type, elt) \ +static inline sctp_arg_t \ +SCTP_## name (type arg) \ +{ sctp_arg_t retval; retval.elt = arg; return(retval); } + +SCTP_ARG_CONSTRUCTOR(I32, int32_t, i32) +SCTP_ARG_CONSTRUCTOR(U32, int32_t, u32) +SCTP_ARG_CONSTRUCTOR(U16, int32_t, u16) +SCTP_ARG_CONSTRUCTOR(U8, int32_t, u8) +SCTP_ARG_CONSTRUCTOR(ERROR, int, error) +SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) +SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) +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(BA, sctp_bind_addr_t *, bp) +SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) +SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent) +SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet) +SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) + +typedef struct { + sctp_arg_t obj; + sctp_verb_t verb; +} sctp_cmd_t; + +typedef struct { + sctp_cmd_t cmds[SCTP_MAX_NUM_COMMANDS]; + uint8_t next_free_slot; + uint8_t next_cmd; +} sctp_cmd_seq_t; + + +/* Create a new sctp_command_sequence. + * Return NULL if creating a new sequence fails. + */ +sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); + +/* Initialize a block of memory as a command sequence. + * Return 0 if the initialization fails. + */ +int sctp_init_cmd_seq(sctp_cmd_seq_t *seq); + +/* Add a command to an sctp_cmd_seq_t. + * Return 0 if the command sequence is full. + * + * Use the SCTP_* constructors defined by SCTP_ARG_CONSTRUCTOR() above + * to wrap data which goes in the obj argument. + */ +int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); + +/* Rewind an sctp_cmd_seq_t to iterate from the start. + * Return 0 if the rewind fails. + */ +int sctp_rewind_sequence(sctp_cmd_seq_t *seq); + +/* Return the next command structure in an sctp_cmd_seq. + * Return NULL at the end of the sequence. + */ +sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq); + +/* Dispose of a command sequence. */ +void sctp_free_cmd_seq(sctp_cmd_seq_t *seq); + +#endif /* __net_sctp_command_h__ */ + diff --git a/include/net/sctp/sctp_constants.h b/include/net/sctp/sctp_constants.h new file mode 100644 index 000000000000..03675a7f6b6a --- /dev/null +++ b/include/net/sctp/sctp_constants.h @@ -0,0 +1,454 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel 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 implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_constants.h,v 1.11 2002/07/26 22:52:32 jgrimm Exp $ + * + * 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 one of the following email + * addresses: + * + * La Monte H.P. Yarroll + * Karl Knutson + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * Xingang Guo + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + * + * There are still LOTS of bugs in this code... I always run on the motto + * "it is a wonder any code ever works :)" + * + * + */ + +#ifndef __sctp_constants_h__ +#define __sctp_constants_h__ + +#include /* For TCP states used in sctp_sock_state_t */ +#include +#include /* For ipv6hdr. */ +#include + +/* 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)) + +/* 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)) + +/* Since CIDs are sparse, we need all four of the following + * symbols. CIDs are dense through SCTP_CID_BASE_MAX. + */ +#define SCTP_CID_BASE_MAX SCTP_CID_SHUTDOWN_COMPLETE +#define SCTP_CID_MAX SCTP_CID_ASCONF_ACK + +#define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) +#define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2) + + +/* These are the different flavours of event. */ +typedef enum { + + SCTP_EVENT_T_CHUNK = 1, + SCTP_EVENT_T_TIMEOUT, + SCTP_EVENT_T_OTHER, + SCTP_EVENT_T_PRIMITIVE + +} sctp_event_t; + +#define SCTP_EVENT_T_MAX SCTP_EVENT_T_PRIMITIVE +#define SCTP_EVENT_T_NUM (SCTP_EVENT_T_MAX + 1) + +/* As a convenience for the state machine, we append SCTP_EVENT_* and + * SCTP_ULP_* to the list of possible chunks. + */ + +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_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_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_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_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_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1) + +/* We define here a utility type for manipulating subtypes. + * The subtype constructors all work like this: + * + * sctp_subtype_t foo = SCTP_ST_CHUNK(SCTP_CID_INIT); + */ + +typedef union { + + sctp_cid_t chunk; + sctp_event_timeout_t timeout; + sctp_event_other_t other; + sctp_event_primitive_t primitive; + +} sctp_subtype_t; + +#define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \ +static inline sctp_subtype_t \ +SCTP_ST_## _name (_type _arg) \ +{ sctp_subtype_t _retval; _retval._elt = _arg; return(_retval); } + +SCTP_SUBTYPE_CONSTRUCTOR(CHUNK, sctp_cid_t, chunk) +SCTP_SUBTYPE_CONSTRUCTOR(TIMEOUT, sctp_event_timeout_t, timeout) +SCTP_SUBTYPE_CONSTRUCTOR(OTHER, sctp_event_other_t, other) +SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, sctp_event_primitive_t, primitive) + + +#define sctp_chunk_is_control(a) (a->chunk_hdr->type != SCTP_CID_DATA) +#define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA) + +/* Calculate the actual data size in a data chunk */ +#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end)\ + - (unsigned long)(c->chunk_hdr)\ + - sizeof(sctp_data_chunk_t))) + +/* This is a table of printable names of sctp_param_t's. */ +extern const char *sctp_param_tbl[]; + + +#define SCTP_MAX_ERROR_CAUSE SCTP_ERROR_NONEXIST_IP +#define SCTP_NUM_ERROR_CAUSE 10 + +/* Internal error codes */ +typedef enum { + + SCTP_IERROR_NO_ERROR = 0, + SCTP_IERROR_BASE = 1000, + SCTP_IERROR_NO_COOKIE, + SCTP_IERROR_BAD_SIG, + SCTP_IERROR_STALE_COOKIE, + SCTP_IERROR_NOMEM, + SCTP_IERROR_MALFORMED, + SCTP_IERROR_BAD_TAG, + SCTP_IERROR_BIG_GAP, + SCTP_IERROR_DUP_TSN, + +} sctp_ierror_t; /* enum */ + + + +/* SCTP state defines for internal state machine */ +typedef enum { + + SCTP_STATE_EMPTY = 0, + SCTP_STATE_CLOSED = 1, + SCTP_STATE_COOKIE_WAIT = 2, + SCTP_STATE_COOKIE_ECHOED = 3, + SCTP_STATE_ESTABLISHED = 4, + SCTP_STATE_SHUTDOWN_PENDING = 5, + SCTP_STATE_SHUTDOWN_SENT = 6, + SCTP_STATE_SHUTDOWN_RECEIVED = 7, + SCTP_STATE_SHUTDOWN_ACK_SENT = 8, + +} sctp_state_t; /* enum */ + +#define SCTP_STATE_MAX SCTP_STATE_SHUTDOWN_ACK_SENT +#define SCTP_STATE_NUM_STATES (SCTP_STATE_MAX + 1) + +/* These are values for sk->state. + * For a UDP-style SCTP socket, the states are defined as follows + * (at this point of time, may change later after more discussions: FIXME) + * A socket in SCTP_SS_UNCONNECTED state indicates that it is not willing + * to accept new associations, but it can initiate the creation of new + * ones. + * A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations and can initiate the creation of new ones. + * A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off + * socket with one association. + */ +typedef enum { + SCTP_SS_CLOSED = TCP_CLOSE, + SCTP_SS_LISTENING = TCP_LISTEN, + SCTP_SS_ESTABLISHING = TCP_SYN_SENT, + SCTP_SS_ESTABLISHED = TCP_ESTABLISHED, + SCTP_SS_DISCONNECTING = TCP_CLOSING, +} sctp_sock_state_t; + +/* These functions map various type to printable names. */ +const char *sctp_cname(const sctp_subtype_t); /* chunk types */ +const char *sctp_oname(const sctp_subtype_t); /* other events */ +const char *sctp_tname(const sctp_subtype_t); /* timeouts */ +const char *sctp_pname(const sctp_subtype_t); /* primitives */ + +/* This is a table of printable names of sctp_state_t's. */ +extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; + +/* SCTP reachability state for each address */ +#define SCTP_ADDR_NOHB 4 +#define SCTP_ADDR_REACHABLE 2 +#define SCTP_ADDR_NOT_REACHABLE 1 + + + + +/* Guess at how big to make the TSN mapping array. + * We guarantee that we can handle at least this big a gap between the + * cumulative ACK and the highest TSN. In practice, we can often + * handle up to twice this value. + * + * NEVER make this more than 32767 (2^15-1). The Gap Ack Blocks in a + * SACK (see section 3.3.4) are only 16 bits, so 2*SCTP_TSN_MAP_SIZE + * must be less than 65535 (2^16 - 1), or we will have overflow + * problems creating SACK's. + */ +#define SCTP_TSN_MAP_SIZE 2048 +#define SCTP_TSN_MAX_GAP 65535 + +/* We will not record more than this many duplicate TSNs between two + * SACKs. The minimum PMTU is 576. Remove all the headers and there + * is enough room for 131 duplicate reports. Round down to the + * nearest power of 2. + */ +#define SCTP_MAX_DUP_TSNS 128 + +typedef enum { + SCTP_COUNTER_INIT_ERROR, +} sctp_counter_t; + +/* How many counters does an association need? */ +#define SCTP_NUMBER_COUNTERS 5 + + +/* Here we define the default timers. + */ + +/* cookie timer def = ? seconds */ +#define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ) + +/* init timer def = 3 seconds */ +#define SCTP_DEFAULT_TIMEOUT_T1_INIT (3 * HZ) + +/* shutdown timer def = 300 ms */ +#define SCTP_DEFAULT_TIMEOUT_T2_SHUTDOWN ((300 * HZ) / 1000) + +/* 0 seconds + RTO */ +#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (10 * HZ) + +/* recv timer def = 200ms (in usec) */ +#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 + * RTO.Alpha - 1/8 + * RTO.Beta - 1/4 + */ +#define SCTP_RTO_INITIAL (3 * HZ) +#define SCTP_RTO_MIN (1 * HZ) +#define SCTP_RTO_MAX (60 * HZ) + +#define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ +#define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ + +/* Maximum number of new data packets that can be sent in a burst. */ +#define SCTP_MAX_BURST 4 + +#define SCTP_CLOCK_GRANULARITY 1 /* 1 jiffy */ + +#define SCTP_DEF_MAX_INIT 6 +#define SCTP_DEF_MAX_SEND 10 + +#define SCTP_DEFAULT_COOKIE_LIFE_SEC 60 /* seconds */ +#define SCTP_DEFAULT_COOKIE_LIFE_USEC 0 /* microseconds */ + +#define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ +#define SCTP_DEFAULT_MAXWINDOW 32768 /* default rwnd size */ +#define SCTP_DEFAULT_MAXSEGMENT 1500 /* MTU size, this is the limit + * to which we will raise the P-MTU. + */ +#define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */ +#define SCTP_HOW_MANY_SECRETS 2 /* How many secrets I keep */ +#define SCTP_HOW_LONG_COOKIE_LIVE 3600 /* How many seconds the current + * secret will live? + */ +#define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */ + +#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ + +#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash + * functions simpler to write. + */ + +/* These return values describe the success or failure of a number of + * routines which form the lower interface to SCTP_outqueue. + */ +typedef enum { + SCTP_XMIT_OK, + SCTP_XMIT_PMTU_FULL, + SCTP_XMIT_RWND_FULL, + SCTP_XMIT_MUST_FRAG, +} sctp_xmit_t; + +/* These are the commands for manipulating transports. */ +typedef enum { + SCTP_TRANSPORT_UP, + SCTP_TRANSPORT_DOWN, +} sctp_transport_cmd_t; + +/* These are the address scopes defined mainly for IPv4 addresses + * based on draft of SCTP IPv4 scoping . + * These scopes are hopefully generic enough to be used on scoping both + * IPv4 and IPv6 addresses in SCTP. + * At this point, the IPv6 scopes will be mapped to these internal scopes + * as much as possible. + */ +typedef enum { + SCTP_SCOPE_GLOBAL, /* IPv4 global addresses */ + SCTP_SCOPE_PRIVATE, /* IPv4 private addresses */ + SCTP_SCOPE_LINK, /* IPv4 link local address */ + SCTP_SCOPE_LOOPBACK, /* IPv4 loopback address */ + SCTP_SCOPE_UNUSABLE, /* IPv4 unusable addresses */ +} sctp_scope_t; + +/* Based on IPv4 scoping , + * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, + * 192.88.99.0/24. + * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP + * addresses. + */ +#define IS_IPV4_UNUSABLE_ADDRESS(a) \ + ((INADDR_BROADCAST == *a) || \ + (MULTICAST(*a)) || \ + (((unsigned char *)(a))[0] == 0) || \ + ((((unsigned char *)(a))[0] == 198) && \ + (((unsigned char *)(a))[1] == 18) && \ + (((unsigned char *)(a))[2] == 0)) || \ + ((((unsigned char *)(a))[0] == 192) && \ + (((unsigned char *)(a))[1] == 88) && \ + (((unsigned char *)(a))[2] == 99))) + +/* IPv4 Link-local addresses: 169.254.0.0/16. */ +#define IS_IPV4_LINK_ADDRESS(a) \ + ((((unsigned char *)(a))[0] == 169) && \ + (((unsigned char *)(a))[1] == 254)) + +/* RFC 1918 "Address Allocation for Private Internets" defines the IPv4 + * private address space as the following: + * + * 10.0.0.0 - 10.255.255.255 (10/8 prefix) + * 172.16.0.0.0 - 172.31.255.255 (172.16/12 prefix) + * 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + */ +#define IS_IPV4_PRIVATE_ADDRESS(a) \ + ((((unsigned char *)(a))[0] == 10) || \ + ((((unsigned char *)(a))[0] == 172) && \ + (((unsigned char *)(a))[1] >= 16) && \ + (((unsigned char *)(a))[1] < 32)) || \ + ((((unsigned char *)(a))[0] == 192) && \ + (((unsigned char *)(a))[1] == 168))) + +/* Flags used for the bind address copy functions. */ +#define SCTP_ADDR6_ALLOWED 0x00000001 /* IPv6 address is allowed by + local sock family */ +#define SCTP_ADDR4_PEERSUPP 0x00000002 /* IPv4 address is supported by + peer */ +#define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by + peer */ + +/* Reasons to lower cwnd. */ +typedef enum { + SCTP_LOWER_CWND_T3_RTX, + SCTP_LOWER_CWND_FAST_RTX, + SCTP_LOWER_CWND_ECNE, + SCTP_LOWER_CWND_INACTIVE, +} sctp_lower_cwnd_t; + +#endif /* __sctp_constants_h__ */ + diff --git a/include/net/sctp/sctp_sla1.h b/include/net/sctp/sctp_sla1.h new file mode 100644 index 000000000000..964da227c796 --- /dev/null +++ b/include/net/sctp/sctp_sla1.h @@ -0,0 +1,87 @@ +/* SCTP reference Implementation + * Copyright (C) 1999 Cisco, Inc. + * Copyright (C) 1999 Motorola, Inc. + * + * This file originates from Randy Stewart's SCTP reference Implementation. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randy Stewart + * Ken Morneau + * Qiaobing Xie + */ + +#ifndef __SLA1_h__ +#define __SLA1_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct SLA_1_Context{ + unsigned int A; + unsigned int B; + unsigned int C; + unsigned int D; + unsigned int E; + unsigned int H0; + unsigned int H1; + unsigned int H2; + unsigned int H3; + unsigned int H4; + unsigned int words[80]; + unsigned int TEMP; + /* block I am collecting to process */ + char SLAblock[64]; + /* collected so far */ + int howManyInBlock; + unsigned int runningTotal; +}; + + +#define F1(B,C,D) (((B & C) | ((~B) & D))) /* 0 <= t <= 19 */ +#define F2(B,C,D) (B ^ C ^ D) /* 20 <= t <= 39 */ +#define F3(B,C,D) ((B & C) | (B & D) | (C & D)) /* 40 <= t <= 59 */ +#define F4(B,C,D) (B ^ C ^ D) /*600 <= t <= 79 */ +/* circular shift */ + +#define CSHIFT(A,B) ((B << A) | (B >> (32-A))) + +#define K1 0x5a827999 /* 0 <= t <= 19 */ +#define K2 0x6ed9eba1 /* 20 <= t <= 39 */ +#define K3 0x8f1bbcdc /* 40 <= t <= 59 */ +#define K4 0xca62c1d6 /* 60 <= t <= 79 */ + +#define H0INIT 0x67452301 +#define H1INIT 0xefcdab89 +#define H2INIT 0x98badcfe +#define H3INIT 0x10325476 +#define H4INIT 0xc3d2e1f0 + +extern void SLA1_Init(struct SLA_1_Context *); +extern void SLA1_Process(struct SLA_1_Context *, const unsigned char *, int); +extern void SLA1_Final(struct SLA_1_Context *, unsigned char *); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/net/sctp/sctp_sm.h b/include/net/sctp/sctp_sm.h new file mode 100644 index 000000000000..f3eb7657701d --- /dev/null +++ b/include/net/sctp/sctp_sm.h @@ -0,0 +1,430 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel 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 implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_sm.h,v 1.33 2002/08/16 19:30:49 jgrimm Exp $ + * + * These are definitions needed by the state machine. + * + * 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 addresses: + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Dajiang Zhang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __sctp_sm_h__ +#define __sctp_sm_h__ + +/* + * Possible values for the disposition are: + */ +typedef enum { + SCTP_DISPOSITION_DISCARD, /* No further processing. */ + SCTP_DISPOSITION_CONSUME, /* Process return values normally. */ + SCTP_DISPOSITION_NOMEM, /* We ran out of memory--recover. */ + SCTP_DISPOSITION_DELETE_TCB, /* Close the association. */ + SCTP_DISPOSITION_ABORT, /* Close the association NOW. */ + SCTP_DISPOSITION_VIOLATION, /* The peer is misbehaving. */ + SCTP_DISPOSITION_NOT_IMPL, /* This entry is not implemented. */ + SCTP_DISPOSITION_ERROR, /* This is plain old user error. */ + SCTP_DISPOSITION_BUG, /* This is a bug. */ +} sctp_disposition_t; + +typedef struct { + int name; + int action; +} sctp_sm_command_t; + +typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, + const sctp_association_t *, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *); +typedef void (sctp_timer_event_t) (unsigned long); +typedef struct { + sctp_state_fn_t *fn; + char *name; +} sctp_sm_table_entry_t; + +/* A naming convention of "sctp_sf_xxx" applies to all the state functions + * currently in use. + */ + +/* Prototypes for generic state functions. */ +sctp_state_fn_t sctp_sf_not_impl; +sctp_state_fn_t sctp_sf_bug; + +/* Prototypes for gener timer state functions. */ +sctp_state_fn_t sctp_sf_timer_ignore; + +/* Prototypes for chunk state functions. */ +sctp_state_fn_t sctp_sf_do_9_1_abort; +sctp_state_fn_t sctp_sf_cookie_wait_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_abort; +sctp_state_fn_t sctp_sf_do_5_1B_init; +sctp_state_fn_t sctp_sf_do_5_1C_ack; +sctp_state_fn_t sctp_sf_do_5_1D_ce; +sctp_state_fn_t sctp_sf_do_5_1E_ca ; +sctp_state_fn_t sctp_sf_do_4_C; +sctp_state_fn_t sctp_sf_eat_data_6_2; +sctp_state_fn_t sctp_sf_eat_data_fast_4_4; +sctp_state_fn_t sctp_sf_eat_sack_6_2; +sctp_state_fn_t sctp_sf_tabort_8_4_8; +sctp_state_fn_t sctp_sf_operr_notify; +sctp_state_fn_t sctp_sf_t1_timer_expire; +sctp_state_fn_t sctp_sf_t2_timer_expire; +sctp_state_fn_t sctp_sf_sendbeat_8_3; +sctp_state_fn_t sctp_sf_beat_8_3; +sctp_state_fn_t sctp_sf_backbeat_8_3; +sctp_state_fn_t sctp_sf_do_9_2_final; +sctp_state_fn_t sctp_sf_do_9_2_shutdown; +sctp_state_fn_t sctp_sf_do_ecn_cwr; +sctp_state_fn_t sctp_sf_do_ecne; +sctp_state_fn_t sctp_sf_ootb; +sctp_state_fn_t sctp_sf_shut_8_4_5; +sctp_state_fn_t sctp_sf_pdiscard; +sctp_state_fn_t sctp_sf_violation; +sctp_state_fn_t sctp_sf_discard_chunk; +sctp_state_fn_t sctp_sf_do_5_2_1_siminit; +sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; +sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; + +/* Prototypes for primitive event state functions. */ +sctp_state_fn_t sctp_sf_do_prm_asoc; +sctp_state_fn_t sctp_sf_do_prm_send; +sctp_state_fn_t sctp_sf_do_9_2_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_wait_prm_shutdown; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; +sctp_state_fn_t sctp_sf_error_closed; +sctp_state_fn_t sctp_sf_error_shutdown; +sctp_state_fn_t sctp_sf_ignore_primitive; + +/* Prototypes for other event state functions. */ +sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; +sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack; +sctp_state_fn_t sctp_sf_ignore_other; + +/* Prototypes for timeout event state functions. */ +sctp_state_fn_t sctp_sf_do_6_3_3_rtx; +sctp_state_fn_t sctp_sf_do_6_2_sack; +sctp_state_fn_t sctp_sf_autoclose_timer_expire; + + +/* These are state functions which are either obsolete or not in use yet. + * If any of these functions needs to be revived, it should be renamed with + * the "sctp_sf_xxx" prefix, and be moved to the above prototype groups. + */ + +/* Prototypes for chunk state functions. Not in use. */ +sctp_state_fn_t sctp_sf_do_5_2_6_stale; +sctp_state_fn_t sctp_sf_do_9_2_reshutack; +sctp_state_fn_t sctp_sf_do_9_2_reshut; +sctp_state_fn_t sctp_sf_do_9_2_shutack; + +sctp_state_fn_t lucky; +sctp_state_fn_t other_stupid; + +/* Prototypes for timeout event state functions. Not in use. */ +sctp_state_fn_t sctp_do_4_2_reinit; +sctp_state_fn_t sctp_do_4_3_reecho; +sctp_state_fn_t sctp_do_9_2_reshut; +sctp_state_fn_t sctp_do_9_2_reshutack; +sctp_state_fn_t sctp_do_8_3_hb_err; +sctp_state_fn_t sctp_heartoff; + +/* Prototypes for addip related state functions. Not in use. */ +sctp_state_fn_t sctp_addip_do_asconf; +sctp_state_fn_t sctp_addip_do_asconf_ack; + +/* Prototypes for utility support functions. */ +uint8_t sctp_get_chunk_type(sctp_chunk_t *chunk); +sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, + sctp_state_t state, + sctp_subtype_t event_subtype); + +time_t timeval_sub(struct timeval *, struct timeval *); +sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, + sctp_chunk_t *, + const int priority); +uint32_t sctp_generate_verification_tag(void); +sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *, + const int priority, int *addrs_len); + +void sctp_populate_tie_tags(uint8_t *cookie, uint32_t curTag, uint32_t hisTag); + + + +/* Prototypes for chunk-building functions. */ +sctp_chunk_t *sctp_make_init(const sctp_association_t *, + const sctp_bind_addr_t *, + int priority); +sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, + const sctp_chunk_t *, + const int priority); +sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, + const uint32_t lowest_tsn, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const uint8_t *data, + uint8_t flags, uint16_t ssn); +sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const uint8_t flags, + uint16_t ssn); +sctp_chunk_t *sctp_make_data(sctp_association_t *, + const struct sctp_sndrcvinfo *sinfo, + int len, const uint8_t *data); +sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, + const struct sctp_sndrcvinfo *, int len); +sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, + const uint32_t); +sctp_chunk_t *sctp_make_sack(const sctp_association_t *); +sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); +sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, + const sctp_chunk_t *); +sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, + const sctp_chunk_t *); +void sctp_init_cause(sctp_chunk_t *, uint16_t cause, const void *, size_t); +sctp_chunk_t *sctp_make_abort(const sctp_association_t *, + const sctp_chunk_t *, + const size_t hint); +sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, + const sctp_chunk_t *, + uint32_t tsn); +sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, + const sctp_transport_t *, + const void *payload, + const size_t paylen); +sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, + const sctp_chunk_t *, + const void *payload, + const size_t paylen); +sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, + const sctp_chunk_t *chunk, + uint16_t cause_code, + const void *payload, + size_t paylen); +void sctp_chunk_assign_tsn(sctp_chunk_t *); + + +/* Prototypes for statetable processing. */ + +int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *, + sctp_association_t *asoc, + void *event_arg, + int priority); + +int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *commands, + int priority); + +/* 2nd level prototypes */ +int +sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *retval, + int priority); + + +int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *); +void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap); + +void sctp_generate_t3_rtx_event(unsigned long peer); +void sctp_generate_heartbeat_event(unsigned long peer); + +sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); + +sctp_cookie_param_t * +sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, + const sctp_chunk_t *, int *cookie_len, + const uint8_t *, int addrs_len); +sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, + const sctp_association_t *, + sctp_chunk_t *, int priority, int *err); +int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, + struct sockaddr_storage*, int); + +/* 3rd level prototypes */ +uint32_t sctp_generate_tag(const sctp_endpoint_t *); +uint32_t sctp_generate_tsn(const sctp_endpoint_t *); + +/* 4th level prototypes */ +void sctp_param2sockaddr(sockaddr_storage_t *addr, const sctpParam_t param, + uint16_t port); +int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); +int sockaddr2sctp_addr(const sockaddr_storage_t *, sctpParam_t); + +/* Extern declarations for major data structures. */ +sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); +extern sctp_sm_table_entry_t +primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_sm_table_entry_t +other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_sm_table_entry_t +timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES]; +extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; + +/* These are some handy utility macros... */ + + +/* Get the size of a DATA chunk payload. */ +static inline uint16_t +sctp_data_size(sctp_chunk_t *chunk) +{ + uint16_t size; + + size = ntohs(chunk->chunk_hdr->length); + size -= sizeof(sctp_data_chunk_t); + + return(size); + +} /* sctp_data_size( ) */ + +/* Compare two TSNs */ + +/* RFC 1982 - Serial Number Arithmetic + * + * 2. Comparison + * Then, s1 is said to be equal to s2 if and only if i1 is equal to i2, + * in all other cases, s1 is not equal to s2. + * + * s1 is said to be less than s2 if, and only if, s1 is not equal to s2, + * and + * + * (i1 < i2 and i2 - i1 < 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 > 2^(SERIAL_BITS - 1)) + * + * s1 is said to be greater than s2 if, and only if, s1 is not equal to + * s2, and + * + * (i1 < i2 and i2 - i1 > 2^(SERIAL_BITS - 1)) or + * (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1)) + */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on TSNs in this document SHOULD use Serial + * Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32. + */ + +enum { + TSN_SIGN_BIT = (1<<31) +}; + +static inline int +TSN_lt(__u32 s, __u32 t) +{ + return (((s) - (t)) & TSN_SIGN_BIT); +} + +static inline int +TSN_lte(__u32 s, __u32 t) +{ + return (((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT)); +} + +/* Compare two SSNs */ + +/* + * RFC 2960 + * 1.6 Serial Number Arithmetic + * + * Comparisons and arithmetic on Stream Sequence Numbers in this document + * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where + * SERIAL_BITS = 16. + */ +enum { + SSN_SIGN_BIT = (1<<15) +}; + +static inline int +SSN_lt(__u16 s, __u16 t) +{ + return (((s) - (t)) & SSN_SIGN_BIT); +} + +static inline int +SSN_lte(__u16 s, __u16 t) +{ + return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); +} + +/* Run sctp_add_cmd() generating a BUG() if there is a failure. */ +static inline void +sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +{ + if (unlikely(!sctp_add_cmd(seq, verb, obj))) { + BUG(); + } + +} /* sctp_add_cmd_sf() */ + + +#endif /* __sctp_sm_h__ */ diff --git a/include/net/sctp/sctp_structs.h b/include/net/sctp/sctp_structs.h new file mode 100644 index 000000000000..12a92f1a732b --- /dev/null +++ b/include/net/sctp/sctp_structs.h @@ -0,0 +1,1561 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_structs.h,v 1.21 2002/08/16 19:30:49 jgrimm Exp $ + * + * 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 addresses: + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Daisy Chang + * Dajiang Zhang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_structs_h__ +#define __sctp_structs_h__ + +#include /* We get struct timespec. */ +#include /* linux/in.h needs this!! */ +#include /* We get struct sockaddr_in. */ +#include /* We get struct in6_addr */ +#include /* We get MAXHOSTNAMELEN. */ +#include /* This gets us atomic counters. */ +#include /* We need sk_buff_head. */ +#include /* We need tq_struct. */ +#include /* We need sctp* header structs. */ + +/* + * This is (almost) a direct quote from RFC 2553. + */ + +/* + * Desired design of maximum size and alignment + */ +#define _SS_MAXSIZE 128 /* Implementation specific max size */ +#define _SS_ALIGNSIZE (sizeof (int64_t)) + /* Implementation specific desired alignment */ +/* + * Definitions used for sockaddr_storage structure paddings design. + */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t)+ \ + _SS_PAD1SIZE + _SS_ALIGNSIZE)) + +struct sockaddr_storage { + sa_family_t __ss_family; /* address family */ + /* Following fields are implementation specific */ + char __ss_pad1[_SS_PAD1SIZE]; + /* 6 byte pad, to make implementation */ + /* specific pad up to alignment field that */ + /* follows explicit in the data structure */ + int64_t __ss_align; /* field to force desired structure */ + /* storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; + /* 112 byte pad to achieve desired size, */ + /* _SS_MAXSIZE value minus size of ss_family */ + /* __ss_pad1, __ss_align fields is 112 */ +}; + +/* A convenience structure for handling sockaddr structures. + * We should wean ourselves off this. + */ +typedef union { + struct sockaddr_in v4; + struct sockaddr_in6 v6; + struct sockaddr sa; +} sockaddr_storage_t; + + +/* Forward declarations for data structures. */ +struct SCTP_protocol; +struct SCTP_endpoint; +struct SCTP_association; +struct SCTP_transport; +struct SCTP_packet; +struct SCTP_chunk; +struct SCTP_inqueue; +struct SCTP_outqueue; +struct SCTP_bind_addr; +struct sctp_opt; +struct sctp_endpoint_common; + + +typedef struct SCTP_protocol sctp_protocol_t; +typedef struct SCTP_endpoint sctp_endpoint_t; +typedef struct SCTP_association sctp_association_t; +typedef struct SCTP_transport sctp_transport_t; +typedef struct SCTP_packet sctp_packet_t; +typedef struct SCTP_chunk sctp_chunk_t; +typedef struct SCTP_inqueue sctp_inqueue_t; +typedef struct SCTP_outqueue sctp_outqueue_t; +typedef struct SCTP_bind_addr sctp_bind_addr_t; +typedef struct sctp_opt sctp_opt_t; +typedef struct sctp_endpoint_common sctp_endpoint_common_t; + +#include +#include +#include + + +/* Structures useful for managing bind/connect. */ + +typedef struct sctp_bind_bucket { + unsigned short port; + unsigned short fastreuse; + struct sctp_bind_bucket *next; + struct sctp_bind_bucket **pprev; + struct sock *sk; +} sctp_bind_bucket_t; + +typedef struct sctp_bind_hashbucket { + spinlock_t lock; + struct sctp_bind_bucket *chain; +} sctp_bind_hashbucket_t; + +/* Used for hashing all associations. + */ +typedef struct sctp_hashbucket { + rwlock_t lock; + sctp_endpoint_common_t *chain; +} sctp_hashbucket_t __attribute__((__aligned__(8))); + + +/* The SCTP protocol structure. */ +struct SCTP_protocol { + /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values + * + * The following protocol parameters are RECOMMENDED: + * + * RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 (3 when converted to right shifts.) + * RTO.Beta - 1/4 (2 when converted to right shifts.) + */ + uint32_t rto_initial; + uint32_t rto_min; + uint32_t rto_max; + + /* Note: rto_alpha and rto_beta are really defined as inverse + * powers of two to facilitate integer operations. + */ + int rto_alpha; + int rto_beta; + + /* Max.Burst - 4 */ + int max_burst; + + /* Valid.Cookie.Life - 60 seconds + */ + int valid_cookie_life; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + int max_retrans_association; + int max_retrans_path; + int max_retrans_init; + + /* HB.interval - 30 seconds + */ + int hb_interval; + + /* + * The following variables are implementation specific. + */ + + /* Default initialization values to be applied to new associations. */ + uint16_t max_instreams; + uint16_t max_outstreams; + + /* This is a list of groups of functions for each address + * family that we support. + */ + list_t address_families; + + /* This is the hash of all endpoints. */ + int ep_hashsize; + sctp_hashbucket_t *ep_hashbucket; + + /* This is the hash of all associations. */ + int assoc_hashsize; + sctp_hashbucket_t *assoc_hashbucket; + + /* This is the sctp port control hash. */ + int port_hashsize; + int port_rover; + spinlock_t port_alloc_lock; /* Protects port_rover. */ + sctp_bind_hashbucket_t *port_hashtable; + + /* This is the global local address list. + * We actively maintain this complete list of interfaces on + * the system by catching routing events. + * + * It is a list of struct sockaddr_storage_list. + */ + list_t local_addr_list; + spinlock_t local_addr_lock; + +}; /* struct SCTP_protocol */ + + +/* + * Pointers to address related SCTP functions. + * (i.e. things that depend on the address family.) + */ +typedef struct sctp_func { + int (*queue_xmit) (struct sk_buff *skb); + int (*setsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int optlen); + int (*getsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int *optlen); + int (*get_dst_mtu) (const sockaddr_storage_t *address); + uint16_t net_header_len; + int sockaddr_len; + sa_family_t sa_family; + list_t list; +} sctp_func_t; + +sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); + +/* SCTP Socket type: UDP or TCP style. */ +typedef enum { + SCTP_SOCKET_UDP = 0, + SCTP_SOCKET_UDP_HIGH_BANDWIDTH, + SCTP_SOCKET_TCP +} sctp_socket_type_t; + +/* Per socket SCTP information. */ +struct sctp_opt { + /* What kind of a socket is this? */ + sctp_socket_type_t type; + + /* What is our base endpointer? */ + sctp_endpoint_t *ep; + + /* Various Socket Options. */ + uint16_t default_stream; + uint32_t default_ppid; + struct sctp_initmsg initmsg; + struct sctp_rtoinfo rtoinfo; + struct sctp_paddrparams paddrparam; + struct sctp_event_subscribe subscribe; + uint32_t autoclose; + uint8_t nodelay; + uint8_t disable_fragments; + +}; /* struct sctp_opt */ + + + +/* This is our APPLICATION-SPECIFIC state cookie. + * THIS IS NOT DICTATED BY THE SPECIFICATION. + */ +/* These are the parts of an association which we send in the cookie. + * Most of these are straight out of: + * RFC2960 12.2 Parameters necessary per association (i.e. the TCB) + * + */ + +typedef struct sctp_cookie { + + /* My : Tag expected in every inbound packet and sent + * Verification: in the INIT or INIT ACK chunk. + * Tag : + */ + uint32_t my_vtag; + + /* Peer's : Tag expected in every outbound packet except + * Verification: in the INIT chunk. + * Tag : + */ + uint32_t peer_vtag; + + /* The rest of these are not from the spec, but really need to + * be in the cookie. + */ + + /* My Tie Tag : Assist in discovering a restarting association. */ + uint32_t my_ttag; + + /* Peer's Tie Tag: Assist in discovering a restarting association. */ + uint32_t peer_ttag; + + /* When does this cookie expire? */ + struct timeval expiration; + + /* Number of inbound/outbound streams which are set + * and negotiated during the INIT process. */ + uint16_t sinit_num_ostreams; + uint16_t sinit_max_instreams; + + /* This is the first sequence number I used. */ + uint32_t initial_tsn; + + /* This holds the originating address of the INIT packet. */ + sockaddr_storage_t peer_addr; + + /* This is a shim for my peer's INIT packet, followed by + * a copy of the raw address list of the association. + * The length of the raw address list is saved in the + * raw_addr_list_len field, which will be used at the time when + * the association TCB is re-constructed from the cookie. + */ + uint32_t raw_addr_list_len; + sctp_init_chunk_t peer_init[0]; +} sctp_cookie_t; + + +/* The format of our cookie that we send to our peer. */ +typedef struct sctp_signed_cookie { + uint8_t signature[SCTP_SECRET_SIZE]; + sctp_cookie_t c; +} sctp_signed_cookie_t ; + + +/* This convenience type allows us to avoid casting when walking + * through a parameter list. + */ +typedef union { + uint8_t *v; + sctp_paramhdr_t *p; + + sctp_cookie_preserve_param_t *bht; + sctp_hostname_param_t *dns; + sctp_cookie_param_t *cookie; + sctp_supported_addrs_param_t *sat; + sctp_ipv4addr_param_t *v4; + sctp_ipv6addr_param_t *v6; +} sctpParam_t; + +/* This is another convenience type to allocate memory for address + * params for the maximum size and pass such structures around + * internally. + */ +typedef union { + sctp_ipv4addr_param_t v4; + sctp_ipv6addr_param_t v6; +} sctpIpAddress_t; + +/* RFC 2960. Section 3.3.5 Heartbeat. + * Heartbeat Information: variable length + * The Sender-specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent (see Section 8.3). + */ +typedef struct sctp_sender_hb_info { + sctp_paramhdr_t param_hdr; + sockaddr_storage_t daddr; + unsigned long sent_at; +} sctp_sender_hb_info_t __attribute__((packed)); + + + +/* RFC2960 1.4 Key Terms + * + * o Chunk: A unit of information within an SCTP packet, consisting of + * a chunk header and chunk-specific content. + * + * As a matter of convenience, we remember the SCTP common header for + * each chunk as well as a few other header pointers... + */ +struct SCTP_chunk { + /* These first three elements MUST PRECISELY match the first + * three elements of struct sk_buff. This allows us to reuse + * all the skb_* queue management functions. + */ + sctp_chunk_t *next; + sctp_chunk_t *prev; + struct sk_buff_head *list; + + /* This is our link to the per-transport transmitted list. */ + struct list_head transmitted_list; + + /* This field is used by chunks that hold fragmented data. + * For the first fragment this is the list that holds the rest of + * fragments. For the remaining fragments, this is the link to the + * frag_list maintained in the first fragment. + */ + struct list_head frag_list; + + /* This points to the sk_buff containing the actual data. */ + struct sk_buff *skb; + + /* These are the SCTP headers by reverse order in a packet. + * Note that some of these may happen more than once. In that + * case, we point at the "current" one, whatever that means + * for that level of header. + */ + + /* We point this at the FIRST TLV parameter to chunk_hdr. */ + sctpParam_t param_hdr; + union { + uint8_t *v; + sctp_datahdr_t *data_hdr; + sctp_inithdr_t *init_hdr; + sctp_sackhdr_t *sack_hdr; + sctp_heartbeathdr_t *hb_hdr; + sctp_sender_hb_info_t *hbs_hdr; + sctp_shutdownhdr_t *shutdown_hdr; + sctp_signed_cookie_t *cookie_hdr; + sctp_ecnehdr_t *ecne_hdr; + sctp_cwrhdr_t *ecn_cwr_hdr; + sctp_errhdr_t *err_hdr; + } subh; + + uint8_t *chunk_end; + + sctp_chunkhdr_t *chunk_hdr; + + sctp_sctphdr_t *sctp_hdr; + + /* This needs to be recoverable for SCTP_SEND_FAILED events. */ + struct sctp_sndrcvinfo sinfo; + + /* Which association does this belong to? */ + sctp_association_t *asoc; + + /* What endpoint received this chunk? */ + sctp_endpoint_common_t *rcvr; + + /* We fill this in if we are calculating RTT. */ + unsigned long sent_at; + + uint8_t rtt_in_progress; /* Is this chunk used for RTT calculation? */ + uint8_t num_times_sent; /* How man times did we send this? */ + uint8_t has_tsn; /* Does this chunk have a TSN yet? */ + uint8_t singleton; /* Was this the only chunk in the packet? */ + uint8_t end_of_packet; /* Was this the last chunk in the packet? */ + uint8_t ecn_ce_done; /* Have we processed the ECN CE bit? */ + uint8_t pdiscard; /* Discard the whole packet now? */ + uint8_t tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + uint8_t fast_retransmit; /* Is this chunk fast retransmitted? */ + uint8_t tsn_missing_report; /* Data chunk missing counter. */ + + /* What is the origin IP address for this chunk? */ + sockaddr_storage_t source; + + /* For an inbound chunk, this tells us where it came from. + * For an outbound chunk, it tells us where we'd like it to + * go. It is NULL if we have no preference. + */ + sctp_transport_t *transport; +}; /* struct SCTP_chunk */ + +sctp_chunk_t *sctp_make_chunk(const sctp_association_t *, uint8_t type, + uint8_t flags, int size); +void sctp_free_chunk(sctp_chunk_t *); +sctp_chunk_t *sctp_copy_chunk(sctp_chunk_t *, int flags); +void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); +int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data); +sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *, + struct sock *); +void sctp_init_source(sctp_chunk_t *chunk); +const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); + +/* This is a structure for holding either an IPv6 or an IPv4 address. */ +/* sin_family -- AF_INET or AF_INET6 + * sin_port -- ordinary port number + * sin_addr -- cast to either (struct in_addr) or (struct in6_addr) + */ +struct sockaddr_storage_list { + list_t list; + sockaddr_storage_t a; +}; /* struct sockaddr_storage_list */ + +typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); + +/* This structure holds lists of chunks as we are assembling for + * transmission. + */ +struct SCTP_packet { + /* These are the SCTP header values (host order) for the packet. */ + uint16_t source_port; + uint16_t destination_port; + uint32_t vtag; + + /* This contains the payload chunks. */ + struct sk_buff_head chunks; + /* This is the total size of all chunks INCLUDING padding. */ + size_t size; + + /* The packet is destined for this transport address. + * The function we finally use to pass down to the next lower + * layer lives in the transport structure. + */ + sctp_transport_t *transport; + + /* Allow a callback for getting a high priority chunk + * bundled early into the packet (This is used for ECNE). + */ + sctp_packet_phandler_t *get_prepend_chunk; + + /* This packet should advertise ECN capability to the network + * via the ECT bit. + */ + int ecn_capable; + + /* This packet contains a COOKIE-ECHO chunk. */ + int has_cookie_echo; + + int malloced; + +}; /* struct SCTP_packet */ + +typedef int (sctp_outqueue_thandler_t)(sctp_outqueue_t *, void *); +typedef int (sctp_outqueue_ehandler_t)(sctp_outqueue_t *); +typedef sctp_packet_t *(sctp_outqueue_ohandler_init_t) + (sctp_packet_t *, + sctp_transport_t *, + uint16_t sport, + uint16_t dport); +typedef sctp_packet_t *(sctp_outqueue_ohandler_config_t) + (sctp_packet_t *, + uint32_t vtag, + int ecn_capable, + sctp_packet_phandler_t *get_prepend_chunk); +typedef sctp_xmit_t (sctp_outqueue_ohandler_t)(sctp_packet_t *, + sctp_chunk_t *); +typedef int (sctp_outqueue_ohandler_force_t)(sctp_packet_t *); + +sctp_outqueue_ohandler_init_t sctp_packet_init; +sctp_outqueue_ohandler_config_t sctp_packet_config; +sctp_outqueue_ohandler_t sctp_packet_append_chunk; +sctp_outqueue_ohandler_t sctp_packet_transmit_chunk; +sctp_outqueue_ohandler_force_t sctp_packet_transmit; +void sctp_packet_free(sctp_packet_t *); + + +/* This represents a remote transport address. + * For local transport addresses, we just use sockaddr_storage_t. + * + * RFC2960 Section 1.4 Key Terms + * + * o Transport address: A Transport Address is traditionally defined + * by Network Layer address, Transport Layer protocol and Transport + * Layer port number. In the case of SCTP running over IP, a + * transport address is defined by the combination of an IP address + * and an SCTP port number (where SCTP is the Transport protocol). + * + * RFC2960 Section 7.1 SCTP Differences from TCP Congestion control + * + * o The sender keeps a separate congestion control parameter set for + * each of the destination addresses it can send to (not each + * source-destination pair but for each destination). The parameters + * should decay if the address is not used for a long enough time + * period. + * + */ +struct SCTP_transport { + /* A list of transports. */ + list_t transports; + + /* Reference counting. */ + atomic_t refcnt; + int dead; + + /* This is the peer's IP address and port. */ + sockaddr_storage_t ipaddr; + + /* These are the functions we call to handle LLP stuff. */ + sctp_func_t *af_specific; + + /* Which association do we belong to? */ + sctp_association_t *asoc; + + /* RFC2960 + * + * 12.3 Per Transport Address Data + * + * For each destination transport address in the peer's + * address list derived from the INIT or INIT ACK chunk, a + * number of data elements needs to be maintained including: + */ + uint32_t rtt; /* This is the most recent RTT. */ + + /* RTO : The current retransmission timeout value. */ + uint32_t rto; + + /* RTTVAR : The current RTT variation. */ + uint32_t rttvar; + + /* SRTT : The current smoothed round trip time. */ + uint32_t srtt; + + /* RTO-Pending : A flag used to track if one of the DATA + * chunks sent to this address is currently being + * used to compute a RTT. If this flag is 0, + * the next DATA chunk sent to this destination + * should be used to compute a RTT and this flag + * should be set. Every time the RTT + * calculation completes (i.e. the DATA chunk + * is SACK'd) clear this flag. + */ + int rto_pending; + + + /* + * These are the congestion stats. + */ + /* cwnd : The current congestion window. */ + uint32_t cwnd; /* This is the actual cwnd. */ + + /* ssthresh : The current slow start threshold value. */ + uint32_t ssthresh; + + /* partial : The tracking method for increase of cwnd when in + * bytes acked : congestion avoidance mode (see Section 6.2.2) + */ + uint32_t partial_bytes_acked; + + /* Data that has been sent, but not acknowledged. */ + uint32_t flight_size; + + /* PMTU : The current known path MTU. */ + uint32_t pmtu; + + /* When was the last time(in jiffies) that a data packet was sent on + * this transport? This is used to adjust the cwnd when the transport + * becomes inactive. + */ + unsigned long last_time_used; + + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to + * the destination address every heartbeat interval. + */ + int hb_interval; + + /* When was the last time (in jiffies) that we heard from this + * transport? We use this to pick new active and retran paths. + */ + unsigned long last_time_heard; + + /* Last time(in jiffies) when cwnd is reduced due to the congestion + * indication based on ECNE chunk. + */ + unsigned long last_time_ecne_reduced; + + /* state : The current state of this destination, + * : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. + */ + struct { + int active; + int hb_allowed; + } state; + + /* These are the error stats for this destination. */ + + /* Error count : The current error count for this destination. */ + unsigned short error_count; + + /* Error : Current error threshold for this destination + * Threshold : i.e. what value marks the destination down if + * : errorCount reaches this value. + */ + unsigned short error_threshold; + + /* This is the max_retrans value for the transport and will + * be initialized to proto.max_retrans.path. This can be changed + * using SCTP_SET_PEER_ADDR_PARAMS socket option. + */ + int max_retrans; + + /* We use this name for debugging output... */ + char *debug_name; + + /* Per : A timer used by each destination. + * Destination : + * Timer : + * + * [Everywhere else in the text this is called T3-rtx. -ed] + */ + struct timer_list T3_rtx_timer; + + /* Heartbeat timer is per destination. */ + struct timer_list hb_timer; + + /* Since we're using per-destination retransmission timers + * (see above), we're also using per-destination "transmitted" + * queues. This probably ought to be a private struct + * accessible only within the outqueue, but it's not, yet. + */ + struct list_head transmitted; + + /* We build bundle-able packets for this transport here. */ + sctp_packet_t packet; + + /* This is the list of transports that have chunks to send. */ + struct list_head send_ready; + + int malloced; /* Is this structure kfree()able? */ +}; /* struct SCTP_transport */ + +extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); +extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, + const sockaddr_storage_t *, int); +extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); +extern void sctp_transport_free(sctp_transport_t *); +extern void sctp_transport_destroy(sctp_transport_t *); +extern void sctp_transport_reset_timers(sctp_transport_t *); +extern void sctp_transport_hold(sctp_transport_t *); +extern void sctp_transport_put(sctp_transport_t *); +extern void sctp_transport_update_rto(sctp_transport_t *, uint32_t); +extern void sctp_transport_raise_cwnd(sctp_transport_t *, uint32_t, uint32_t); +extern void sctp_transport_lower_cwnd(sctp_transport_t *, sctp_lower_cwnd_t); + +/* This is the structure we use to queue packets as they come into + * SCTP. We write packets to it and read chunks from it. It handles + * fragment reassembly and chunk unbundling. + */ +struct SCTP_inqueue { + /* This is actually a queue of sctp_chunk_t each + * containing a partially decoded packet. + */ + struct sk_buff_head in; + /* This is the packet which is currently off the in queue and is + * being worked on through the inbound chunk processing. + */ + sctp_chunk_t *in_progress; + + /* This is the delayed task to finish delivering inbound + * messages. + */ + struct tq_struct immediate; + + int malloced; /* Is this structure kfree()able? */ +}; /* struct SCTP_inqueue */ + +sctp_inqueue_t *sctp_inqueue_new(void); +void sctp_inqueue_init(sctp_inqueue_t *); +void sctp_inqueue_free(sctp_inqueue_t *); +void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet); +sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *); +void sctp_inqueue_set_th_handler(sctp_inqueue_t *, + void (*)(void *), void *); + + +/* This is the structure we use to hold outbound chunks. You push + * chunks in and they automatically pop out the other end as bundled + * packets (it calls (*output_handler)()). + * + * This structure covers sections 6.3, 6.4, 6.7, 6.8, 6.10, 7., 8.1, + * and 8.2 of the v13 draft. + * + * It handles retransmissions. The connection to the timeout portion + * of the state machine is through sctp_..._timeout() and timeout_handler. + * + * If you feed it SACKs, it will eat them. + * + * If you give it big chunks, it will fragment them. + * + * It assigns TSN's to data chunks. This happens at the last possible + * instant before transmission. + * + * When free()'d, it empties itself out via output_handler(). + */ +struct SCTP_outqueue { + sctp_association_t *asoc; + + /* BUG: This really should be an array of streams. + * This really holds a list of chunks (one stream). + * FIXME: If true, why so? + */ + struct sk_buff_head out; + + /* These are control chunks we want to send. */ + struct sk_buff_head control; + + /* These are chunks that have been sacked but are above the + * CTSN, or cumulative tsn ack point. + */ + struct list_head sacked; + + /* Put chunks on this list to schedule them for + * retransmission. + */ + struct list_head retransmit; + + /* Call these functions to send chunks down to the next lower + * layer. This is always SCTP_packet, but we separate the two + * structures to make testing simpler. + */ + sctp_outqueue_ohandler_init_t *init_output; + sctp_outqueue_ohandler_config_t *config_output; + sctp_outqueue_ohandler_t *append_output; + sctp_outqueue_ohandler_t *build_output; + sctp_outqueue_ohandler_force_t *force_output; + + /* How many unackd bytes do we have in-flight? */ + uint32_t outstanding_bytes; + + /* Is this structure empty? */ + int empty; + + /* Are we kfree()able? */ + int malloced; +}; /* struct SCTP_outqueue */ + +sctp_outqueue_t *sctp_outqueue_new(sctp_association_t *); +void sctp_outqueue_init(sctp_association_t *, sctp_outqueue_t *); +void sctp_outqueue_teardown(sctp_outqueue_t *); +void sctp_outqueue_free(sctp_outqueue_t*); +void sctp_force_outqueue(sctp_outqueue_t *); +int sctp_push_outqueue(sctp_outqueue_t *, sctp_chunk_t *chunk); +int sctp_flush_outqueue(sctp_outqueue_t *, int); +int sctp_sack_outqueue(sctp_outqueue_t *, sctp_sackhdr_t *); +int sctp_outqueue_is_empty(const sctp_outqueue_t *); +int sctp_outqueue_set_output_handlers(sctp_outqueue_t *, + sctp_outqueue_ohandler_init_t init, + sctp_outqueue_ohandler_config_t config, + sctp_outqueue_ohandler_t append, + sctp_outqueue_ohandler_t build, + sctp_outqueue_ohandler_force_t force); +void sctp_outqueue_restart(sctp_outqueue_t *); +void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, uint8_t); + + +/* These bind address data fields common between endpoints and associations */ +struct SCTP_bind_addr { + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * SCTP Port: The local SCTP port number the endpoint is + * bound to. + */ + uint16_t port; + + /* RFC 2960 12.1 Parameters necessary for the SCTP instance + * + * Address List: The list of IP addresses that this instance + * has bound. This information is passed to one's + * peer(s) in INIT and INIT ACK chunks. + */ + list_t address_list; + + int malloced; /* Are we kfree()able? */ +}; /* struct SCTP_bind_addr */ + +sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); +void sctp_bind_addr_init(sctp_bind_addr_t *, uint16_t port); +void sctp_bind_addr_free(sctp_bind_addr_t *); +int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, + sctp_scope_t scope, int priority,int flags); +int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, + int priority); +int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); +int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); +sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, + int *addrs_len, + int priority); +int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, + uint8_t *raw_addr_list, + int addrs_len, + unsigned short port, + int priority); + +sctp_scope_t sctp_scope(const sockaddr_storage_t *); +int sctp_in_scope(const sockaddr_storage_t *addr, const sctp_scope_t scope); +int sctp_is_any(const sockaddr_storage_t *addr); +int sctp_addr_is_valid(const sockaddr_storage_t *addr); + + +/* What type of sctp_endpoint_common? */ +typedef enum { + SCTP_EP_TYPE_SOCKET, + SCTP_EP_TYPE_ASSOCIATION, +} sctp_endpoint_type_t; + +/* + * A common base class to bridge the implmentation view of a + * socket (usually listening) endpoint versus an association's + * local endpoint. + * This common structure is useful for several purposes: + * 1) Common interface for lookup routines. + * a) Subfunctions work for either endpoint or association + * b) Single interface to lookup allows hiding the lookup lock rather + * than acquiring it externally. + * 2) Common interface for the inbound chunk handling/state machine. + * 3) Common object handling routines for reference counting, etc. + * 4) Disentangle association lookup from endpoint lookup, where we + * do not have to find our endpoint to find our association. + * + */ + +struct sctp_endpoint_common { + /* Fields to help us manage our entries in the hash tables. */ + sctp_endpoint_common_t *next; + sctp_endpoint_common_t **pprev; + int hashent; + + /* Runtime type information. What kind of endpoint is this? */ + sctp_endpoint_type_t type; + + /* Some fields to help us manage this object. + * refcnt - Reference count access to this object. + * dead - Do not attempt to use this object. + * malloced - Do we need to kfree this object? + */ + atomic_t refcnt; + char dead; + char malloced; + + /* What socket does this endpoint belong to? */ + struct sock *sk; + + /* This is where we receive inbound chunks. */ + sctp_inqueue_t inqueue; + + /* This substructure includes the defining parameters of the + * endpoint: + * bind_addr.port is our shared port number. + * bind_addr.address_list is our set of local IP addresses. + * + */ + sctp_bind_addr_t bind_addr; + + /* Protection during address list comparisons. */ + rwlock_t addr_lock; +}; /* sctp_endpoint_common_t */ + + +/* RFC Section 1.4 Key Terms + * + * o SCTP endpoint: The logical sender/receiver of SCTP packets. On a + * multi-homed host, an SCTP endpoint is represented to its peers as a + * combination of a set of eligible destination transport addresses to + * which SCTP packets can be sent and a set of eligible source + * transport addresses from which SCTP packets can be received. + * All transport addresses used by an SCTP endpoint must use the + * same port number, but can use multiple IP addresses. A transport + * address used by an SCTP endpoint must not be used by another + * SCTP endpoint. In other words, a transport address is unique + * to an SCTP endpoint. + * + * From an implementation perspective, each socket has one of these. + * A TCP-style socket will have exactly one association on one of + * these. An UDP-style socket will have multiple associations hanging + * off one of these. + */ + +struct SCTP_endpoint { + /* Common substructure for endpoint and association. */ + sctp_endpoint_common_t base; + + /* These are the system-wide defaults and other stuff which is + * endpoint-independent. + */ + sctp_protocol_t *proto; + + /* Associations: A list of current associations and mappings + * to the data consumers for each association. This + * may be in the form of a hash table or other + * implementation dependent structure. The data + * consumers may be process identification + * information such as file descriptors, named pipe + * pointer, or table pointers dependent on how SCTP + * is implemented. + */ + /* This is really a list of sctp_association_t entries. */ + list_t asocs; + + /* Secret Key: A secret key used by this endpoint to compute + * the MAC. This SHOULD be a cryptographic quality + * random number with a sufficient length. + * Discussion in [RFC1750] can be helpful in + * selection of the key. + */ + uint8_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; + int current_key; + int last_key; + int key_changed_at; + + /* Default timeouts. */ + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + + /* Various thresholds. */ + + /* Name for debugging output... */ + char *debug_name; +}; /* sctp_endpoint_t */ + +/* Recover the outter endpoint structure. */ +static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t* base) +{ + sctp_endpoint_t *ep; + + /* We are not really a list, but the list_entry() macro is + * really quite generic to find the address of an outter struct. + */ + ep = list_entry(base, sctp_endpoint_t, base); + return ep; + +} /* sctp_ep() */ + +/* These are function signatures for manipulating endpoints. */ +sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *, struct sock *, int); +sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *, sctp_protocol_t *, + struct sock *, int priority); +void sctp_endpoint_free(sctp_endpoint_t *); +void sctp_endpoint_put(sctp_endpoint_t *); +void sctp_endpoint_hold(sctp_endpoint_t *); +void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); +sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, + const sockaddr_storage_t *paddr, + sctp_transport_t **); +sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, + const sockaddr_storage_t *); + +void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, + const sockaddr_storage_t *peer_addr, + sctp_init_chunk_t *peer_init, int priority); +int sctp_process_param(sctp_association_t *asoc, + sctpParam_t param, + const sockaddr_storage_t *peer_addr, + sctp_cid_t cid, int priority); +uint32_t sctp_generate_tag(const sctp_endpoint_t *ep); +uint32_t sctp_generate_tsn(const sctp_endpoint_t *ep); + + +/* RFC2960 + * + * 12. Recommended Transmission Control Block (TCB) Parameters + * + * This section details a recommended set of parameters that should + * be contained within the TCB for an implementation. This section is + * for illustrative purposes and should not be deemed as requirements + * on an implementation or as an exhaustive list of all parameters + * inside an SCTP TCB. Each implementation may need its own additional + * parameters for optimization. + */ + + +/* Here we have information about each individual association. */ +struct SCTP_association { + + /* A base structure common to endpoint and association. + * In this context, it represents the associations's view + * of the local endpoint of the association. + */ + sctp_endpoint_common_t base; + + /* Associations on the same socket. */ + list_t asocs; + + /* This is a signature that lets us know that this is a + * sctp_association_t data structure. Used for mapping an + * association id to an association. + */ + uint32_t eyecatcher; + + /* This is our parent endpoint. */ + sctp_endpoint_t *ep; + + /* These are those association elements needed in the cookie. */ + sctp_cookie_t c; + + /* This is all information about our peer. */ + struct { + /* rwnd + * + * Peer Rwnd : Current calculated value of the peer's rwnd. + */ + uint32_t rwnd; + + /* transport_addr_list + * + * Peer : A list of SCTP transport addresses that the + * Transport : peer is bound to. This information is derived + * Address : from the INIT or INIT ACK and is used to + * List : associate an inbound packet with a given + * : association. Normally this information is + * : hashed or keyed for quick lookup and access + * : of the TCB. + * + * It is a list of SCTP_transport's. + */ + list_t transport_addr_list; + + /* port + * The transport layer port number. + */ + uint16_t port; + + /* primary_path + * + * Primary : This is the current primary destination + * Path : transport address of the peer endpoint. It + * : may also specify a source transport address + * : on this endpoint. + * + * All of these paths live on transport_addr_list. + * + * At the bakeoffs, we discovered that the intent of + * primaryPath is that it only changes when the ULP + * asks to have it changed. We add the activePath to + * designate the connection we are currently using to + * transmit new data and most control chunks. + */ + sctp_transport_t *primary_path; + + /* active_path + * The path that we are currently using to + * transmit new data and most control chunks. + */ + sctp_transport_t *active_path; + + /* retran_path + * + * RFC2960 6.4 Multi-homed SCTP Endpoints + * ... + * Furthermore, when its peer is multi-homed, an + * endpoint SHOULD try to retransmit a chunk to an + * active destination transport address that is + * different from the last destination address to + * which the DATA chunk was sent. + */ + sctp_transport_t *retran_path; + + /* Pointer to last transport I have sent on. */ + sctp_transport_t *last_sent_to; + + /* This is the last transport I have recieved DATA on. */ + sctp_transport_t *last_data_from; + + /* + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + * + * Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. This value is hidden + * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). + */ + sctp_tsnmap_t tsn_map; + uint8_t _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; + + /* We record duplicate TSNs here. We clear this after + * every SACK. + * FIXME: We should move this into the tsnmap? --jgrimm + */ + sctp_dup_tsn_t dup_tsns[SCTP_MAX_DUP_TSNS]; + int next_dup_tsn; + + /* Do we need to sack the peer? */ + int sack_needed; + + /* These are capabilities which our peer advertised. */ + uint8_t ecn_capable; /* Can peer do ECN? */ + uint8_t ipv4_address; /* Peer understands IPv4 addresses? */ + uint8_t ipv6_address; /* Peer understands IPv6 addresses? */ + uint8_t hostname_address;/* Peer understands DNS addresses? */ + sctp_inithdr_t i; + int cookie_len; + void *cookie; + + /* ADDIP Extention (ADDIP) --xguo */ + /* minus 1 (ADDIP sec. 4.2 C1) */ + uint32_t addip_serial; + } peer; + + /* State : A state variable indicating what state the + * : association is in, i.e. COOKIE-WAIT, + * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, + * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. + * + * Note: No "CLOSED" state is illustrated since if a + * association is "CLOSED" its TCB SHOULD be removed. + * + * In this implementation we DO have a CLOSED + * state which is used during initiation and shutdown. + * + * State takes values from SCTP_STATE_*. + */ + sctp_state_t state; + + /* When did we enter this state? */ + int state_timestamp; + + /* The cookie life I award for any cookie. */ + struct timeval cookie_life; + uint32_t cookie_preserve; + + /* Overall : The overall association error count. + * Error Count : [Clear this any time I get something.] + */ + int overall_error_count; + + /* Overall : The threshold for this association that if + * Error : the Overall Error Count reaches will cause + * Threshold : this association to be torn down. + */ + int overall_error_threshold; + + /* These are the association's initial, max, and min RTO values. + * These values will be initialized by system defaults, but can + * be modified via the SCTP_RTOINFO socket option. + */ + uint32_t rto_initial; + uint32_t rto_max; + uint32_t rto_min; + + /* Maximum number of new data packets that can be sent in a burst. */ + int max_burst; + + /* This is the max_retrans value for the association. This value will + * be initialized initialized from system defaults, but can be + * modified by the SCTP_ASSOCINFO socket option. + */ + int max_retrans; + + /* Maximum number of times the endpoint will retransmit INIT */ + uint16_t max_init_attempts; + + /* How many times have we resent an INIT? */ + uint16_t init_retries; + + /* The largest timeout or RTO value to use in attempting an INIT */ + uint16_t max_init_timeo; + + + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; + + /* Transport to which SHUTDOWN chunk was last sent. */ + sctp_transport_t *shutdown_last_sent_to; + + /* Next TSN : The next TSN number to be assigned to a new + * : DATA chunk. This is sent in the INIT or INIT + * : ACK chunk to the peer and incremented each + * : time a DATA chunk is assigned a TSN + * : (normally just prior to transmit or during + * : fragmentation). + */ + uint32_t next_tsn; + + /* + * Last Rcvd : This is the last TSN received in sequence. This value + * TSN : is set initially by taking the peer's Initial TSN, + * : received in the INIT or INIT ACK chunk, and + * : subtracting one from it. + * + * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. + */ + + uint32_t ctsn_ack_point; + + /* The number of unacknowledged data chunks. Reported through + * the SCTP_STATUS sockopt. + */ + uint16_t unack_data; + + /* This is the association's receive buffer space. This value is used + * to set a_rwnd field in an INIT or a SACK chunk. + */ + uint32_t rwnd; + + /* Number of bytes by which the rwnd has slopped. The rwnd is allowed + * to slop over a maximum of the association's frag_point. + */ + uint32_t rwnd_over; + + /* This is the sndbuf size in use for the association. + * This corresponds to the sndbuf size for the association, + * as specified in the sk->sndbuf. + */ + int sndbuf_used; + + /* This is the wait queue head for send requests waiting on + * the association sndbuf space. + */ + wait_queue_head_t wait; + + /* Association : The smallest PMTU discovered for all of the + * PMTU : peer's transport addresses. + */ + uint32_t pmtu; + + /* The message size at which SCTP fragmentation will occur. */ + uint32_t frag_point; + + /* Ack State : This flag indicates if the next received + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). + */ + /* Do we need to send an ack? + * When counters[SctpCounterAckState] is above 1 we do! + */ + int counters[SCTP_NUMBER_COUNTERS]; + + struct { + uint16_t stream; + uint32_t ppid; + } defaults; + + /* This tracks outbound ssn for a given stream. */ + uint16_t ssn[SCTP_MAX_STREAM]; + + /* All outbound chunks go through this structure. */ + sctp_outqueue_t outqueue; + + /* A smart pipe that will handle reordering and fragmentation, + * as well as handle passing events up to the ULP. + * In the future, we should make this at least dynamic, if + * not also some sparse structure. + */ + sctp_ulpqueue_t ulpq; + uint8_t _ssnmap[sctp_ulpqueue_storage_size(SCTP_MAX_STREAM)]; + + /* Need to send an ECNE Chunk? */ + int need_ecne; + + /* Last TSN that caused an ECNE Chunk to be sent. */ + uint32_t last_ecne_tsn; + + /* Last TSN that caused a CWR Chunk to be sent. */ + uint32_t last_cwr_tsn; + + /* How many duplicated TSNs have we seen? */ + int numduptsns; + + /* Number of seconds of idle time before an association is closed. */ + uint32_t autoclose; + + /* Name for debugging output... */ + char *debug_name; + + /* These are to support + * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses + * and Enforcement of Flow and Message Limits" + * + * or "ADDIP" for short. + */ + + /* Is the ADDIP extension enabled for this association? */ + int addip_enable; + + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * [This is our one-and-only-one ASCONF in flight. If we do + * not have an ASCONF in flight, this is NULL.] + */ + sctp_chunk_t *addip_last_asconf; + + /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. + * + * IMPLEMENTATION NOTE: As an optimization a receiver may wish + * to save the last ASCONF-ACK for some predetermined period + * of time and instead of re-processing the ASCONF (with the + * same serial number) it may just re-transmit the + * ASCONF-ACK. It may wish to use the arrival of a new serial + * number to discard the previously saved ASCONF-ACK or any + * other means it may choose to expire the saved ASCONF-ACK. + * + * [This is our saved ASCONF-ACK. We invalidate it when a new + * ASCONF serial number arrives.] + */ + sctp_chunk_t *addip_last_asconf_ack; + + /* These ASCONF chunks are waiting to be sent. + * + * These chunaks can't be pushed to outqueue until receiving + * ASCONF_ACK for the previous ASCONF indicated by + * addip_last_asconf, so as to guarantee that only one ASCONF + * is in flight at any time. + * + * ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks + * + * In defining the ASCONF Chunk transfer procedures, it is + * essential that these transfers MUST NOT cause congestion + * within the network. To achieve this, we place these + * restrictions on the transfer of ASCONF Chunks: + * + * R1) One and only one ASCONF Chunk MAY be in transit and + * unacknowledged at any one time. If a sender, after sending + * an ASCONF chunk, decides it needs to transfer another + * ASCONF Chunk, it MUST wait until the ASCONF-ACK Chunk + * returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, + * so at any time two ASCONF may be in-transit on any given + * association (one sent from each endpoint). + * + * + * [I really think this is EXACTLY the sort of intelligence + * which already resides in SCTP_outqueue. Please move this + * queue and its supporting logic down there. --piggy] */ + struct sk_buff_head addip_chunks; + + /* ADDIP Section 4.1 ASCONF Chunk Procedures + * + * A2) A serial number should be assigned to the Chunk. The + * serial number should be a monotonically increasing + * number. All serial numbers are defined to be initialized at + * the start of the association to the same value as the + * Initial TSN. + * + * [and] + * + * ADDIP + * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * + * Serial Number : 32 bits (unsigned integer) + * + * This value represents a Serial Number for the ASCONF + * Chunk. The valid range of Serial Number is from 0 to + * 4294967295 (2**32 - 1). Serial Numbers wrap back to 0 + * after reaching 4294967295. + */ + uint32_t addip_serial; +}; /* sctp_association_t */ + + +/* An eyecatcher for determining if we are really looking at an + * association data structure. + */ +enum { + SCTP_ASSOC_EYECATCHER = 0xa550c123, +}; + +/* Recover the outter association structure. */ +static inline sctp_association_t *sctp_assoc(sctp_endpoint_common_t *base) +{ + sctp_association_t *asoc; + + /* We are not really a list, but the list_entry() macro is + * really quite generic find the address of an outter struct. + */ + asoc = list_entry(base, sctp_association_t, base); + return asoc; + +} /* sctp_asoc() */ + +/* These are function signatures for manipulating associations. */ + + +sctp_association_t * +sctp_association_new(const sctp_endpoint_t *, const struct sock *, + sctp_scope_t scope, int priority); +sctp_association_t * +sctp_association_init(sctp_association_t *, const sctp_endpoint_t *, + const struct sock *, sctp_scope_t scope, + int priority); +void sctp_association_free(sctp_association_t *); +void sctp_association_put(sctp_association_t *); +void sctp_association_hold(sctp_association_t *); + +sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *); +sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, + const sockaddr_storage_t *); +sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, + const sockaddr_storage_t *address, + const int priority); +void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *, + sctp_transport_cmd_t, sctp_sn_error_t); +sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, uint32_t); +sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, + const sockaddr_storage_t *, + const sockaddr_storage_t *); +void sctp_assoc_migrate(sctp_association_t *, struct sock *); +void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); + +uint32_t __sctp_association_get_next_tsn(sctp_association_t *); +uint32_t __sctp_association_get_tsn_block(sctp_association_t *, int); +uint16_t __sctp_association_get_next_ssn(sctp_association_t *, uint16_t sid); + +int sctp_cmp_addr(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2); +int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2); +sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc); +sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc); + + +/* A convenience structure to parse out SCTP specific CMSGs. */ +typedef struct sctp_cmsgs { + struct sctp_initmsg *init; + struct sctp_sndrcvinfo *info; +} sctp_cmsgs_t; + +int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs); + + +/* Structure for tracking memory objects */ +typedef struct { + char *label; + atomic_t *counter; +} sctp_dbg_objcnt_entry_t; + + + +#endif /* __sctp_structs_h__ */ diff --git a/include/net/sctp/sctp_tsnmap.h b/include/net/sctp/sctp_tsnmap.h new file mode 100644 index 000000000000..6e39c306a494 --- /dev/null +++ b/include/net/sctp/sctp_tsnmap.h @@ -0,0 +1,163 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, Intel, and International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_tsnmap.h,v 1.8 2002/07/16 14:51:58 jgrimm Exp $ + * + * These are the definitions needed for the tsnmap type. The tsnmap is used + * to track out of order TSNs received. + * + * 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 one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#include + +#ifndef __sctp_tsnmap_h__ +#define __sctp_tsnmap_h__ + + + +/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB) + * Mapping An array of bits or bytes indicating which out of + * Array order TSN's have been received (relative to the + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. + */ +typedef struct sctp_tsnmap { + + + /* This array counts the number of chunks with each TSN. + * It points at one of the two buffers with which we will + * ping-pong between. + */ + uint8_t *tsn_map; + + /* This marks the tsn which overflows the tsn_map, when the + * cumulative ack point reaches this point we know we can switch + * maps (tsn_map and overflow_map swap). + */ + uint32_t overflow_tsn; + + /* This is the overflow array for tsn_map. + * It points at one of the other ping-pong buffers. + */ + uint8_t *overflow_map; + + /* This is the TSN at tsn_map[0]. */ + uint32_t base_tsn; + + /* Last Rcvd : This is the last TSN received in + * TSN : sequence. This value is set initially by + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. + * + * Throughout most of the specification this is called the + * "Cumulative TSN ACK Point". In this case, we + * ignore the advice in 12.2 in favour of the term + * used in the bulk of the text. + */ + uint32_t cumulative_tsn_ack_point; + + /* This is the minimum number of TSNs we can track. This corresponds + * to the size of tsn_map. Note: the overflow_map allows us to + * potentially track more than this quantity. + */ + uint16_t len; + + /* This is the highest TSN we've marked. */ + uint32_t max_tsn_seen; + + /* No. of data chunks pending receipt. used by SCTP_STATUS sockopt */ + uint16_t pending_data; + + int malloced; + + uint8_t raw_map[0]; +} sctp_tsnmap_t; + +typedef struct sctp_tsnmap_iter { + uint32_t start; +} sctp_tsnmap_iter_t; + + +/* Create a new tsnmap. */ +sctp_tsnmap_t *sctp_tsnmap_new(uint16_t len, uint32_t initial_tsn, + int priority); + +/* Dispose of a tsnmap. */ +void sctp_tsnmap_free(sctp_tsnmap_t *map); + +/* This macro assists in creation of external storage for variable length + * internal buffers. We double allocate so the overflow map works. + */ +#define sctp_tsnmap_storage_size(count) (sizeof(uint8_t) * (count) * 2) + +/* Initialize a block of memory as a tsnmap. */ +sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, + uint32_t initial_tsn); + + + +/* Test the tracking state of this TSN. + * Returns: + * 0 if the TSN has not yet been seen + * >0 if the TSN has been seen (duplicate) + * <0 if the TSN is invalid (too large to track) + */ +int sctp_tsnmap_check(const sctp_tsnmap_t *map, uint32_t tsn); + +/* Mark this TSN as seen. */ +void sctp_tsnmap_mark(sctp_tsnmap_t *map, uint32_t tsn); + +/* Retrieve the Cumulative TSN ACK Point. */ +uint32_t sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map); + +/* Retrieve the highest TSN we've seen. */ +uint32_t sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map); + +/* Is there a gap in the TSN map? */ +int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map); + +/* Initialize a gap ack block interator from user-provided memory. */ +void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter); + +/* Get the next gap ack blocks. We return 0 if there are no more + * gap ack blocks. + */ +int +sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + uint16_t *start, uint16_t *end); + + +#endif /* __sctp_tsnmap_h__ */ + + + diff --git a/include/net/sctp/sctp_ulpevent.h b/include/net/sctp/sctp_ulpevent.h new file mode 100644 index 000000000000..631c61609454 --- /dev/null +++ b/include/net/sctp/sctp_ulpevent.h @@ -0,0 +1,147 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_ulpevent.h,v 1.5 2002/07/12 14:50:25 jgrimm Exp $ + * + * These are the definitions needed for the sctp_ulpevent type. The + * sctp_ulpevent type is used to carry information from the state machine + * upwards to the ULP. + * + * 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 one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + + +#ifndef __sctp_ulpevent_h__ +#define __sctp_ulpevent_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +/* Warning: This sits inside an skb.cb[] area. Be very careful of + * growing this structure as it is at the maximum limit now. + */ +typedef struct sctp_ulpevent { + int malloced; + sctp_association_t *asoc; + struct sk_buff *parent; + struct sctp_sndrcvinfo sndrcvinfo; + int chunk_flags; /* Temp. until we get a new chunk_t */ + int msg_flags; +} sctp_ulpevent_t; + + +sctp_ulpevent_t * +sctp_ulpevent_new(int size, int msg_flags, int priority); + +sctp_ulpevent_t * +sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags); + +void +sctp_ulpevent_free(sctp_ulpevent_t *event); + + +int +sctp_ulpevent_is_notification(const sctp_ulpevent_t *event); + +sctp_ulpevent_t * +sctp_ulpevent_make_assoc_change(const struct SCTP_association *asoc, + uint16_t flags, + uint16_t state, + uint16_t error, + uint16_t outbound, + uint16_t inbound, + int priority); + +sctp_ulpevent_t * +sctp_ulpevent_make_peer_addr_change(const struct SCTP_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority); + +sctp_ulpevent_t * +sctp_ulpevent_make_remote_error(const struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + uint16_t flags, + int priority); +sctp_ulpevent_t * +sctp_ulpevent_make_send_failed(const struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + uint16_t flags, + uint32_t error, + int priority); + +sctp_ulpevent_t * +sctp_ulpevent_make_shutdown_event(const struct SCTP_association *asoc, + uint16_t flags, + int priority); + +sctp_ulpevent_t * +sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + int priority); + +void +sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr); + +uint16_t +sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event); + + + +/* Given an event subscription, is this event enabled? */ +static inline int +sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event, + const struct sctp_event_subscribe *mask) +{ + const char *amask = (const char *)mask; + uint16_t sn_type; + + int enabled = 1; + if (sctp_ulpevent_is_notification(event)) { + sn_type = sctp_ulpevent_get_notification_type(event); + enabled = amask[sn_type - SCTP_SN_TYPE_BASE]; + } + return(enabled); + +} /* sctp_ulpevent_is_enabled() */ + + +#endif /* __sctp_ulpevent_h__ */ + + + + + + + diff --git a/include/net/sctp/sctp_ulpqueue.h b/include/net/sctp/sctp_ulpqueue.h new file mode 100644 index 000000000000..2881457af222 --- /dev/null +++ b/include/net/sctp/sctp_ulpqueue.h @@ -0,0 +1,102 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_ulpqueue.h,v 1.2 2002/07/12 14:50:25 jgrimm Exp $ + * + * These are the definitions needed for the sctp_ulpqueue type. The + * sctp_ulpqueue 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. + * + * 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 one of the + * following email addresses: + * + * Jon Grimm + * La Monte H.P. Yarroll + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef __sctp_ulpqueue_h__ +#define __sctp_ulpqueue_h__ + +/* A structure to carry information to the ULP (e.g. Sockets API) */ +typedef struct sctp_ulpqueue { + int malloced; + spinlock_t lock; + sctp_association_t *asoc; + struct sk_buff_head reasm; + struct sk_buff_head lobby; + uint16_t 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(uint16_t) * (inbound)) + +sctp_ulpqueue_t * +sctp_ulpqueue_new(sctp_association_t *asoc, + uint16_t inbound, + int priority); + +sctp_ulpqueue_t * +sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, + sctp_association_t *asoc, + uint16_t inbound); + +void +sctp_ulpqueue_free(sctp_ulpqueue_t *); + + +/* Add a new DATA chunk for processing. */ +int +sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, + 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); + + +/* Is the ulpqueue empty. */ +int +sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); + +int +sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); + +#endif /* __sctp_ulpqueue_h__ */ + + + + + + + diff --git a/include/net/sctp/sctp_user.h b/include/net/sctp/sctp_user.h new file mode 100644 index 000000000000..afe665ace370 --- /dev/null +++ b/include/net/sctp/sctp_user.h @@ -0,0 +1,609 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_user.h,v 1.17 2002/07/29 21:04:23 jgrimm Exp $ + * + * This header represents the structures and constants needed to support + * the SCTP Extension to the Sockets API. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * R. Stewart + * K. Morneau + * Q. Xie + * Karl Knutson + * Jon Grimm + * Daisy Chang + * + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +#include +#include + +#ifndef __net_sctp_user_h__ +#define __net_sctp_user_h__ + + +typedef void * sctp_assoc_t; + +/* The following symbols come from the Sockets API Extensions for + * SCTP . + */ +enum sctp_optname { + SCTP_RTOINFO, +#define SCTP_RTOINFO SCTP_RTOINFO + SCTP_ASSOCRTXINFO, +#define SCTP_ASSOCRTXINFO SCTP_ASSOCRTXINFO + SCTP_INITMSG, +#define SCTP_INITMSG SCTP_INITMSG + SCTP_AUTO_CLOSE, +#define SCTP_AUTO_CLOSE SCTP_AUTO_CLOSE + SCTP_SET_PRIMARY_ADDR, +#define SCTP_SET_PRIMARY_ADDR SCTP_SET_PRIMARY_ADDR + SCTP_SET_PEER_PRIMARY_ADDR, +#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR + SCTP_SET_ADAPTATION_LAYER, +#define SCTP_SET_ADAPTATION_LAYER SCTP_SET_ADAPTATION_LAYER + SCTP_SET_STREAM_TIMEOUTS, +#define SCTP_SET_STREAM_TIMEOUTS SCTP_SET_STREAM_TIMEOUTS + SCTP_DISABLE_FRAGMENTS, +#define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS + SCTP_SET_PEER_ADDR_PARAMS, +#define SCTP_SET_PEER_ADDR_PARAMS SCTP_SET_PEER_ADDR_PARAMS + SCTP_GET_PEER_ADDR_PARAMS, +#define SCTP_GET_PEER_ADDR_PARAMS SCTP_GET_PEER_ADDR_PARAMS + SCTP_STATUS, +#define SCTP_STATUS SCTP_STATUS + SCTP_GET_PEER_ADDR_INFO, +#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO + SCTP_SET_EVENTS, +#define SCTP_SET_EVENTS SCTP_SET_EVENTS + SCTP_AUTOCLOSE, +#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE + SCTP_SET_DEFAULT_SEND_PARAM, +#define SCTP_SET_DEFAULT_SEND_PARAM SCTP_SET_DEFAULT_SEND_PARAM + + SCTP_SOCKOPT_DEBUG_NAME = 42, /* FIXME */ +#define SCTP_SOCKOPT_DEBUG_NAME SCTP_SOCKOPT_DEBUG_NAME + + SCTP_SOCKOPT_BINDX_ADD, /* BINDX requests for adding addresses. */ +#define SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_ADD + SCTP_SOCKOPT_BINDX_REM, /* BINDX requests for removing addresses. */ +#define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM + SCTP_SOCKOPT_PEELOFF, /* peel off association. */ +#define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF +}; /* enum sctp_optname */ + + +/* + * 5.2 SCTP msg_control Structures + * + * A key element of all SCTP-specific socket extensions is the use of + * ancillary data to specify and access SCTP-specific data via the + * struct msghdr's msg_control member used in sendmsg() and recvmsg(). + * Fine-grained control over initialization and sending parameters are + * handled with ancillary data. + * + * Each ancillary data item is preceeded by a struct cmsghdr (see + * Section 5.1), which defines the function and purpose of the data + * contained in in the cmsg_data[] member. + */ + +/* + * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for initializing new + * SCTP associations with sendmsg(). The SCTP_INITMSG socket option + * uses this same data structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + * + */ +struct sctp_initmsg { + uint16_t sinit_num_ostreams; + uint16_t sinit_max_instreams; + uint16_t sinit_max_attempts; + uint16_t sinit_max_init_timeo; +}; /* struct sctp_initmsg */ + + +/* + * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for sendmsg() and + * describes SCTP header information about a received message through + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + * + */ +struct sctp_sndrcvinfo { + uint16_t sinfo_stream; + uint16_t sinfo_ssn; + uint16_t sinfo_flags; + uint32_t sinfo_ppid; + uint32_t sinfo_context; + uint32_t sinfo_timetolive; + uint32_t sinfo_tsn; + sctp_assoc_t sinfo_assoc_id; +}; /* struct sctp_sndrcvinfo */ + +/* + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + */ + +enum sctp_sinfo_flags { + MSG_UNORDERED = 1, /* Send/recieve message unordered. */ + MSG_ADDR_OVER = 2, /* Override the primary destination. */ + MSG_ABORT=4, /* Send an ABORT message to the peer. */ + /* MSG_EOF is already defined per socket.h */ +}; /* enum sctp_sinfo_flags */ + + +typedef union { + u_int8_t raw; + struct sctp_initmsg init; + struct sctp_sndrcvinfo sndrcv; +} sctp_cmsg_data_t; + +/* These are cmsg_types. */ +typedef enum sctp_cmsg_type { + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ +} sctp_cmsg_t; + + +/* + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notificaion. The notification information has the + * following format: + * + */ + +struct sctp_assoc_change { + uint16_t sac_type; + uint16_t sac_flags; + uint32_t sac_length; + uint16_t sac_state; + uint16_t sac_error; + uint16_t sac_outbound_streams; + uint16_t sac_inbound_streams; + sctp_assoc_t sac_assoc_id; +}; /* sctp_assoc_change */ + +/* + * sac_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the association. They include: + * + * Note: The following state names deviate from the API draft as + * the names clash too easily with other kernel symbols. + */ +enum sctp_sac_state { + SCTP_COMM_UP, + SCTP_COMM_LOST, + SCTP_RESTART, + SCTP_SHUTDOWN_COMP, + SCTP_CANT_STR_ASSOC, +}; /* sctp_sac_state */ + +/* + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. The information has the + * following structure: + */ +struct sctp_paddr_change{ + uint16_t spc_type; + uint16_t spc_flags; + uint32_t spc_length; + struct sockaddr_storage spc_aaddr; + int spc_state; + int spc_error; + sctp_assoc_t spc_assoc_id; +}; /* sctp_paddr_change */ + +/* + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. They include: + */ +enum sctp_spc_state { + ADDRESS_AVAILABLE, + ADDRESS_UNREACHABLE, + ADDRESS_REMOVED, + ADDRESS_ADDED, + ADDRESS_MADE_PRIM, +}; /* sctp_spc_state */ + + +/* + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. SCTP error TLVs have the format: + */ +struct sctp_remote_error { + uint16_t sre_type; + uint16_t sre_flags; + uint32_t sre_length; + uint16_t sre_error; + uint16_t sre_len; + sctp_assoc_t sre_assoc_id; + uint8_t sre_data[0]; +}; + + +/* + * 5.3.1.4 SCTP_SEND_FAILED + * + * If SCTP cannot deliver a message it may return the message as a + * notification. + */ +struct sctp_send_failed { + uint16_t ssf_type; + uint16_t ssf_flags; + uint32_t ssf_length; + uint32_t ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + uint8_t ssf_data[0]; +}; + +/* + * ssf_flags: 16 bits (unsigned integer) + * + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ + +enum sctp_ssf_flags { + SCTP_DATA_UNSENT, + SCTP_DATA_SENT, +}; + +/* + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ + +struct sctp_shutdown_event { + uint16_t sse_type; + uint16_t sse_flags; + uint32_t sse_length; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.6 SCTP_ADAPTION_INDICATION + * + * When a peer sends a Adaption Layer Indication parameter , SCTP + * delivers this notification to inform the application + * that of the peers requested adaption layer. + */ +struct sctp_adaption_event { + uint16_t sai_type; + uint16_t sai_flags; + uint32_t sai_length; + uint32_t sai_adaptation_bits; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT + * + * When a reciever is engaged in a partial delivery of a + * message this notification will be used to inidicate + * various events. + */ + +struct sctp_rcv_pdapi_event { + uint16_t pdapi_type; + uint16_t pdapi_flags; + uint32_t pdapi_length; + uint32_t pdapi_indication; + sctp_assoc_t pdapi_assoc_id; +}; + + +/* + * Described in Section 7.3 + * Ancillary Data and Notification Interest Options + */ +struct sctp_event_subscribe { + uint8_t sctp_data_io_event; + uint8_t sctp_association_event; + uint8_t sctp_address_event; + uint8_t sctp_send_failure_event; + uint8_t sctp_peer_error_event; + uint8_t sctp_shutdown_event; + uint8_t sctp_partial_delivery_event; + uint8_t sctp_adaption_layer_event; +}; /* struct sctp_event_subscribe */ + +/* + * 5.3.1 SCTP Notification Structure + * + * The notification structure is defined as the union of all + * notification types. + * + */ +union sctp_notification { + struct { + uint16_t sn_type; /* Notification type. */ + uint16_t sn_flags; + uint32_t sn_length; + } h; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_padr_change; + struct sctp_remote_error sn_remote_error; + struct sctp_send_failed sn_send_failed; + struct sctp_shutdown_event sn_shutdown_event; + struct sctp_adaption_event sn_adaption_event; + struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; +}; + +/* Section 5.3.1 + * All standard values for sn_type flags are greater than 2^15. + * Values from 2^15 and down are reserved. + */ + +enum sctp_sn_type { + SCTP_SN_TYPE_BASE = (1<<15), + SCTP_ASSOC_CHANGE, + SCTP_PEER_ADDR_CHANGE, + SCTP_REMOTE_ERROR, + SCTP_SEND_FAILED, + SCTP_SHUTDOWN_EVENT, + SCTP_PARTIAL_DELIVERY_EVENT, + SCTP_ADAPTION_INDICATION, +}; + +/* Notification error codes used to fill up the error fields in some + * notifications. + * SCTP_PEER_ADDRESS_CHAGE : spc_error + * SCTP_ASSOC_CHANGE : sac_error + * These names should be potentially included in the draft 04 of the SCTP + * sockets API specification. + */ +typedef enum sctp_sn_error { + SCTP_FAILED_THRESHOLD, + SCTP_RECEIVED_SACK, + SCTP_HEARTBEAT_SUCCESS, + SCTP_RESPONSE_TO_USER_REQ, + SCTP_INTERNAL_ERROR, + SCTP_SHUTDOWN_GUARD_EXPIRES, + SCTP_PEER_FAULTY, +} sctp_sn_error_t; + +/* + * + * 7.1.14 Peer Address Parameters + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ + +struct sctp_paddrparams { + struct sockaddr_storage spp_address; + uint32_t spp_hbinterval; + uint16_t spp_pathmaxrxt; + sctp_assoc_t spp_assoc_id; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ + +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + int32_t spinfo_state; + uint32_t spinfo_cwnd; + uint32_t spinfo_srtt; + uint32_t spinfo_rto; + uint32_t spinfo_mtu; +}; + + +/* + * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. See [SCTP] for more information on how + * these parameters are used in RTO calculation. The peer address + * parameter is ignored for TCP style socket. + */ + +struct sctp_rtoinfo { + uint32_t srto_initial; + uint32_t srto_max; + uint32_t srto_min; + sctp_assoc_t srto_assoc_id; +}; + +/* + * 7.1.2 Association Retransmission Parameter (SCTP_ASSOCRTXINFO) + * + * The protocol parameter used to set the number of retransmissions + * sent before an association is considered unreachable. + * See [SCTP] for more information on how this parameter is used. The + * peer address parameter is ignored for TCP style socket. + */ + +struct sctp_assocparams { + uint16_t sasoc_asocmaxrxt; + sctp_assoc_t sasoc_assoc_id; +}; + + +/* + * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ + +struct sctp_setprim { + struct sockaddr_storage ssp_addr; + sctp_assoc_t ssp_assoc_id; +}; + +/* + * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the local SCTP stack use the enclosed peer address as + * the association primary. The enclosed address must be one of the + * association peer's addresses. The following structure is used to + * make a set peer primary request: + */ + +struct sctp_setpeerprim { + struct sockaddr_storage sspp_addr; + sctp_assoc_t sspp_assoc_id; +}; + +/* + * 7.2.1 Association Status (SCTP_STATUS) + * + * Applications can retrieve current status information about an + * association, including association state, peer receiver window size, + * number of unacked data chunks, and number of data chunks pending + * receipt. This information is read-only. The following structure is + * used to access this information: + */ +struct sctp_status { + sctp_assoc_t sstat_assoc_id; + int32_t sstat_state; + uint32_t sstat_rwnd; + uint16_t sstat_unackdata; + uint16_t sstat_penddata; + uint16_t sstat_instrms; + uint16_t sstat_outstrms; + uint32_t sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; +}; + + +/* + * 7.1.12 Set Adaption Layer Indicator + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future + * INIT and INIT-ACK exchanges. + */ + +struct sctp_setadaption { + u_int32_t ssb_adaption_ind; +}; + +/* + * 7.1.12 Set default message time outs (SCTP_SET_STREAM_TIMEOUTS) + * + * This option requests that the requested stream apply a + * default time-out for messages in queue. + */ +struct sctp_setstrm_timeout { + sctp_assoc_t ssto_assoc_id; + u_int32_t ssto_timeout; + u_int16_t ssto_streamid_start; + u_int16_t ssto_streamid_end; +}; + + +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; /* enum sctp_msg_flags */ + +/* + * 8.1 sctp_bindx() + * + * The flags parameter is formed from the bitwise OR of zero or more of the + * following currently defined flags: + */ +#define BINDX_ADD_ADDR 0x01 +#define BINDX_REM_ADDR 0x02 + +/* This is the structure that is passed as an argument(optval) to + * getsockopt(SCTP_SOCKOPT_PEELOFF). + */ +typedef struct { + sctp_assoc_t associd; + int sd; +} sctp_peeloff_arg_t; + +#endif /* __net_sctp_user_h__ */ + + + diff --git a/net/Config.in b/net/Config.in index 7762e7468182..6c9ee39850e6 100644 --- a/net/Config.in +++ b/net/Config.in @@ -26,6 +26,9 @@ if [ "$CONFIG_INET" = "y" ]; then source net/ipv6/Config.in fi fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + source net/sctp/Config.in + fi fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM diff --git a/net/Makefile b/net/Makefile index 2ad255681bf4..4fed0f516ca9 100644 --- a/net/Makefile +++ b/net/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_DECNET) += decnet/ obj-$(CONFIG_ECONET) += econet/ obj-$(CONFIG_VLAN_8021Q) += 8021q/ obj-$(CONFIG_LLC) += llc/ +obj-$(CONFIG_IP_SCTP) += sctp/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_MODULES) += netsyms.o diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 50beeb9a9e32..2dcea8fd874c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -493,7 +493,7 @@ int inet_release(struct socket *sock) /* It is off by default, see below. */ int sysctl_ip_nonlocal_bind; -static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; struct sock *sk = sock->sk; @@ -729,7 +729,7 @@ do_err: /* * This does both peername and sockname. */ -static int inet_getname(struct socket *sock, struct sockaddr *uaddr, +int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sock *sk = sock->sk; @@ -846,7 +846,7 @@ int inet_shutdown(struct socket *sock, int how) * There's a good 20K of config code hanging around the kernel. */ -static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index fbe45634e28b..ee838c63969a 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -274,7 +274,7 @@ do_oom: /* bind for INET6 API */ -static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr; struct sock *sk = sock->sk; @@ -370,7 +370,7 @@ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return 0; } -static int inet6_release(struct socket *sock) +int inet6_release(struct socket *sock) { struct sock *sk = sock->sk; @@ -415,7 +415,7 @@ int inet6_destroy_sock(struct sock *sk) * This does both peername and sockname. */ -static int inet6_getname(struct socket *sock, struct sockaddr *uaddr, +int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr; @@ -451,7 +451,7 @@ static int inet6_getname(struct socket *sock, struct sockaddr *uaddr, return(0); } -static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = -EINVAL; @@ -547,7 +547,7 @@ struct proto_ops inet6_dgram_ops = { .sendpage = sock_no_sendpage, }; -static struct net_proto_family inet6_family_ops = { +struct net_proto_family inet6_family_ops = { .family =PF_INET6, .create =inet6_create, }; diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 4b98f52e6864..e4c491b68c0c 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -10,3 +11,16 @@ EXPORT_SYMBOL(ndisc_mc_map); EXPORT_SYMBOL(register_inet6addr_notifier); EXPORT_SYMBOL(unregister_inet6addr_notifier); EXPORT_SYMBOL(ip6_route_output); +EXPORT_SYMBOL(addrconf_lock); +EXPORT_SYMBOL(ipv6_setsockopt); +EXPORT_SYMBOL(ipv6_getsockopt); +EXPORT_SYMBOL(inet6_register_protosw); +EXPORT_SYMBOL(inet6_unregister_protosw); +EXPORT_SYMBOL(inet6_add_protocol); +EXPORT_SYMBOL(inet6_del_protocol); +EXPORT_SYMBOL(ip6_xmit); +EXPORT_SYMBOL(inet6_release); +EXPORT_SYMBOL(inet6_bind); +EXPORT_SYMBOL(inet6_getname); +EXPORT_SYMBOL(inet6_ioctl); +EXPORT_SYMBOL(ipv6_get_saddr); diff --git a/net/netsyms.c b/net/netsyms.c index 654411e005e0..463f6749b027 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -56,7 +56,8 @@ extern __u32 sysctl_rmem_max; extern struct net_proto_family inet_family_ops; -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) \ + || defined (CONFIG_IP_SCTP_MODULE) #include #include #include @@ -159,6 +160,7 @@ EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(sock_kmalloc); EXPORT_SYMBOL(sock_kfree_s); +EXPORT_SYMBOL(sock_map_fd); #ifdef CONFIG_FILTER EXPORT_SYMBOL(sk_run_filter); @@ -286,7 +288,7 @@ EXPORT_SYMBOL(dlci_ioctl_hook); #endif -#if defined (CONFIG_IPV6_MODULE) +#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) /* inet functions common to v4 and v6 */ EXPORT_SYMBOL(inet_release); EXPORT_SYMBOL(inet_stream_connect); @@ -397,6 +399,14 @@ EXPORT_SYMBOL(sysctl_max_syn_backlog); EXPORT_SYMBOL(tcp_read_sock); +#ifdef CONFIG_IP_SCTP_MODULE +EXPORT_SYMBOL(ip_setsockopt); +EXPORT_SYMBOL(ip_getsockopt); +EXPORT_SYMBOL(inet_ioctl); +EXPORT_SYMBOL(inet_bind); +EXPORT_SYMBOL(inet_getname); +#endif /* CONFIG_IP_SCTP_MODULE */ + EXPORT_SYMBOL(netlink_set_err); EXPORT_SYMBOL(netlink_broadcast); EXPORT_SYMBOL(netlink_unicast); diff --git a/net/sctp/Config.help b/net/sctp/Config.help new file mode 100644 index 000000000000..5dfb7250d6f7 --- /dev/null +++ b/net/sctp/Config.help @@ -0,0 +1,44 @@ +CONFIG_IP_SCTP + Stream Control Transmission Protocol + + From RFC 2960 (http://www.ietf.org/rfc/rfc2960.txt) + + "SCTP is a reliable transport protocol operating on top of a + connectionless packet network such as IP. It offers the following + services to its users: + + -- acknowledged error-free non-duplicated transfer of user data, + -- data fragmentation to conform to discovered path MTU size, + -- sequenced delivery of user messages within multiple streams, + with an option for order-of-arrival delivery of individual user + messages, + -- optional bundling of multiple user messages into a single SCTP + packet, and + -- network-level fault tolerance through supporting of multi- + homing at either or both ends of an association." + + If in doubt, say N. + +CONFIG_SCTP_ADLER32 + RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. + This has been deprecated and replaced by an algorithm now referred + to as crc32c. + + If you say Y, this will use the Adler-32 algorithm, this might be useful + for interoperation with downlevel peers. + + If unsure, say N. + +CONFIG_SCTP_DBG_MSG + If you say Y, this will enable verbose debugging messages. + + If unsure, say N. However, if you are running into problems, use this + option to gather detailed trace information + +CONFIG_SCTP_DBG_OBJCNT + If you say Y, this will enable debugging support for counting the types + of objects that are currently allocated. This is useful for identifying + memory leaks. If the /proc filesystem is enabled this debug information + can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' + + If unsure, say N diff --git a/net/sctp/Config.in b/net/sctp/Config.in new file mode 100644 index 000000000000..ad21aec87db3 --- /dev/null +++ b/net/sctp/Config.in @@ -0,0 +1,20 @@ +# +# SCTP configuration +# +mainmenu_option next_comment +comment ' SCTP Configuration (EXPERIMENTAL)' + +if [ "$CONFIG_IPV6" != "n" ]; then + define_bool CONFIG_IPV6_SCTP__ $CONFIG_IPV6 +else + define_bool CONFIG_IPV6_SCTP__ y +fi + +dep_tristate ' The SCTP Protocol (EXPERIMENTAL)' CONFIG_IP_SCTP $CONFIG_IPV6_SCTP__ +if [ "$CONFIG_IP_SCTP" != "n" ]; then + bool ' SCTP: Use old checksum (Adler-32)' CONFIG_SCTP_ADLER32 + bool ' SCTP: Debug messages' CONFIG_SCTP_DBG_MSG + bool ' SCTP: Debug object counts' CONFIG_SCTP_DBG_OBJCNT +fi + +endmenu diff --git a/net/sctp/Makefile b/net/sctp/Makefile new file mode 100644 index 000000000000..4506c069a186 --- /dev/null +++ b/net/sctp/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for SCTP support code. +# + +obj-$(CONFIG_IP_SCTP) += sctp.o + +obj-y := sctp_sm_statetable.o sctp_sm_statefuns.o sctp_sm_sideeffect.o \ + sctp_protocol.o sctp_endpointola.o sctp_associola.o \ + sctp_transport.o sctp_sm_make_chunk.o sctp_ulpevent.o \ + sctp_inqueue.o sctp_outqueue.o sctp_ulpqueue.o sctp_command.o \ + sctp_tsnmap.o sctp_bind_addr.o sctp_socket.o sctp_primitive.o \ + sctp_output.o sctp_input.o sctp_hashdriver.o sctp_sla1.o \ + sctp_debug.o + +ifeq ($(CONFIG_SCTP_ADLER32), y) +obj-y += sctp_adler32.o +else +obj-y += sctp_crc32c.o +endif + +obj-$(CONFIG_SCTP_DBG_OBJCNT) += sctp_objcnt.o +obj-$(CONFIG_SYSCTL) += sctp_sysctl.o + +obj-$(subst m,y,$(CONFIG_IPV6)) += sctp_ipv6.o + +sctp-objs := $(obj-y) + +include $(TOPDIR)/Rules.make diff --git a/net/sctp/sctp_adler32.c b/net/sctp/sctp_adler32.c new file mode 100644 index 000000000000..d00dc9c5a120 --- /dev/null +++ b/net/sctp/sctp_adler32.c @@ -0,0 +1,151 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_adler32.c,v 1.5 2002/06/13 16:03:38 jgrimm Exp $ + * + * This file has direct heritage from the SCTP user-level reference + * implementation by R. Stewart, et al. These functions implement the + * Adler-32 algorithm as specified by RFC 2960. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_adler32.c,v 1.5 2002/06/13 16:03:38 jgrimm Exp $"; + +/* This is an entry point for external calls + * Define this function in the header file. This is + * direct from rfc1950, ... + + * The following C code computes the Adler-32 checksum of a data buffer. + It is written for clarity, not for speed. The sample code is in the + ANSI C programming language. Non C users may find it easier to read + with these hints: + + & Bitwise AND operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero bit(s) + at the left. + << Bitwise left shift operator. Left shift inserts zero + bit(s) at the right. + ++ "n++" increments the variable n. + % modulo operator: a % b is the remainder of a divided by b. + + * Well, the above is a bit of a lie, I have optimized this a small + * tad, but I have commented the original lines below + */ + +#include +#include + +#define BASE 65521 /* largest prime smaller than 65536 */ + + +/* Performance work as shown this pig to be the + * worst CPU wise guy. I have done what I could think + * of on my flight to Austrialia but I am sure some + * clever assembly could speed this up, but of + * course this would require the dreaded #ifdef's for + * architecture. If you can speed this up more, pass + * it back and we will incorporate it :-) + */ + + +unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) +{ + uint32_t s1 = adler & 0xffff; + uint32_t s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++,buf++) { + + /* s1 = (s1 + buf[n]) % BASE */ + /* first we add */ + s1 = (s1 + *buf); + /* Now if we need to, we do a mod by + * subtracting. It seems a bit faster + * since I really will only ever do + * one subtract at the MOST, since buf[n] + * is a max of 255. + */ + if(s1 >= BASE){ + s1 -= BASE; + } + /* s2 = (s2 + s1) % BASE */ + /* first we add */ + s2 = (s2 + s1); + /* again, it is more efficent (it seems) to + * subtract since the most s2 will ever be + * is (BASE-1 + BASE-1) in the worse case. + * This would then be (2 * BASE) - 2, which + * will still only do one subtract. On Intel + * this is much better to do this way and + * avoid the divide. Have not -pg'd on + * sparc. + */ + if(s2 >= BASE){ + /* s2 %= BASE;*/ + s2 -= BASE; + } + } + /* Return the adler32 of the bytes buf[0..len-1] */ + return (s2 << 16) + s1; +} + +uint32_t +count_crc(uint8_t *ptr, + uint16_t count) +{ + /* + * Update a running Adler-32 checksum with the bytes + * buf[0..len-1] and return the updated checksum. The Adler-32 + * checksum should be initialized to 1. + */ + uint32_t adler = 1L; + uint32_t zero = 0L; + + /* Calculate the CRC up to the checksum field. */ + adler = update_adler32(adler, ptr, + sizeof(struct sctphdr) - sizeof(uint32_t)); + /* Skip over the checksum field. */ + adler = update_adler32(adler, &zero, sizeof(uint32_t)); + ptr += sizeof(struct sctphdr); + count -= sizeof(struct sctphdr); + /* Calculate the rest of the Adler-32. */ + adler = update_adler32(adler, ptr, count); + + return(adler); +} + diff --git a/net/sctp/sctp_associola.c b/net/sctp/sctp_associola.c new file mode 100644 index 000000000000..57d03a6a8acd --- /dev/null +++ b/net/sctp/sctp_associola.c @@ -0,0 +1,1118 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_associola.c,v 1.48 2002/08/16 19:30:49 jgrimm Exp $ + * + * This module provides the abstraction for an SCTP association. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_associola.c,v 1.48 2002/08/16 19:30:49 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* Forward declarations for internal functions. */ +static void sctp_assoc_bh_rcv(sctp_association_t *asoc); + + +/* 1st Level Abstractions. */ + +/* Allocate and initialize a new association */ +sctp_association_t * +sctp_association_new(const sctp_endpoint_t *ep, const struct sock *sk, + sctp_scope_t scope, int priority) +{ + sctp_association_t *asoc; + + asoc = t_new(sctp_association_t, priority); + if (!asoc) { + goto fail; + } + + if (!sctp_association_init(asoc, ep, sk, scope, priority)) { + goto fail_init; + } + + asoc->base.malloced = 1; + SCTP_DBG_OBJCNT_INC(assoc); + + return asoc; + +fail_init: + kfree(asoc); +fail: + return NULL; + +} /* sctp_association_new() */ + +/* Intialize a new association from provided memory. */ +sctp_association_t * +sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, + const struct sock *sk, sctp_scope_t scope, + int priority) +{ + int i; + sctp_opt_t *sp; + + /* Retrieve the SCTP per socket area. */ + sp = sctp_sk((struct sock *)sk); + + /* Init all variables to a known value. */ + memset(asoc, 0, sizeof(sctp_association_t)); + + /* Discarding const is appropriate here. */ + asoc->ep = (sctp_endpoint_t *)ep; + sctp_endpoint_hold(asoc->ep); + + /* Hold the sock. */ + asoc->base.sk = (struct sock *)sk; + sock_hold(asoc->base.sk); + + /* Initialize the common base substructure. */ + asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; + + /* Initialize the object handling fields. */ + atomic_set(&asoc->base.refcnt, 1); + asoc->base.dead = 0; + asoc->base.malloced = 0; + + /* Initialize the bind addr area. */ + sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); + asoc->base.addr_lock = RW_LOCK_UNLOCKED; + + asoc->state = SCTP_STATE_CLOSED; + asoc->state_timestamp = jiffies; + + /* Set things that have constant value. */ + asoc->cookie_life.tv_sec = SCTP_DEFAULT_COOKIE_LIFE_SEC; + asoc->cookie_life.tv_usec = SCTP_DEFAULT_COOKIE_LIFE_USEC; + + asoc->pmtu = 0; + asoc->frag_point = 0; + + /* Initialize the default association max_retrans and RTO values. */ + asoc->max_retrans = ep->proto->max_retrans_association; + asoc->rto_initial = ep->proto->rto_initial; + asoc->rto_max = ep->proto->rto_max; + asoc->rto_min = ep->proto->rto_min; + + asoc->overall_error_threshold = 0; + asoc->overall_error_count = 0; + + /* Initialize the maximum mumber of new data packets that can be sent + * in a burst. + */ + asoc->max_burst = ep->proto->max_burst; + + /* Copy things from the endpoint. */ + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + asoc->timeouts[i] = ep->timeouts[i]; + init_timer(&asoc->timers[i]); + asoc->timers[i].function = sctp_timer_events[i]; + asoc->timers[i].data = (unsigned long)asoc; + } + + /* Pull default initialization values from the sock options. + * Note: This assumes that the values have already been + * validated in the sock. + */ + asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; + asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; + asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; + asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ; + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * The stream sequence number in all the streams shall start + * from 0 when the association is established. Also, when the + * stream sequence number reaches the value 65535 the next + * stream sequence number shall be set to 0. + */ + for(i=0; i < SCTP_MAX_STREAM; i++) { + asoc->ssn[i] = 0; + } + + /* Set the local window size for receive. + * This is also the rcvbuf space per association. + * RFC 6 - A SCTP receiver MUST be able to receive a minimum of + * 1500 bytes in one SCTP packet. + */ + if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) { + asoc->rwnd = SCTP_DEFAULT_MINWINDOW; + } else { + asoc->rwnd = sk->rcvbuf; + } + + asoc->rwnd_over = 0; + + /* Use my own max window until I learn something better. */ + asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; + + /* Set the sndbuf size for transmit. */ + asoc->sndbuf_used = 0; + + init_waitqueue_head(&asoc->wait); + + asoc->c.my_vtag = sctp_generate_tag(ep); + asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ + asoc->c.peer_vtag = 0; + asoc->c.my_ttag = 0; + asoc->c.peer_ttag = 0; + + asoc->c.initial_tsn = sctp_generate_tsn(ep); + + asoc->next_tsn = asoc->c.initial_tsn; + + asoc->ctsn_ack_point = asoc->next_tsn - 1; + + asoc->unack_data = 0; + + SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", + asoc->ep->debug_name, + asoc->ctsn_ack_point); + + /* ADDIP Section 4.1 Asconf Chunk Procedures + * + * When an endpoint has an ASCONF signaled change to be sent to the + * remote endpoint it should do the following: + * ... + * A2) a serial number should be assigned to the chunk. The serial + * number should be a monotonically increasing number. All serial + * numbers are defined to be initialized at the start of the + * association to the same value as the initial TSN. + */ + asoc->addip_serial = asoc->c.initial_tsn; + + /* Make an empty list of remote transport addresses. */ + INIT_LIST_HEAD(&asoc->peer.transport_addr_list); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * After the reception of the first data chunk in an + * association the endpoint must immediately respond with a + * sack to acknowledge the data chunk. Subsequent + * acknowledgements should be done as described in Section + * 6.2. + * + * [We implement this by telling a new association that it + * already received one packet.] + */ + asoc->peer.sack_needed = 1; + + /* Create an input queue. */ + sctp_inqueue_init(&asoc->base.inqueue); + sctp_inqueue_set_th_handler(&asoc->base.inqueue, + (void (*)(void *))sctp_assoc_bh_rcv, + asoc); + + /* Create an output queue. */ + sctp_outqueue_init(asoc, &asoc->outqueue); + sctp_outqueue_set_output_handlers(&asoc->outqueue, + sctp_packet_init, + sctp_packet_config, + sctp_packet_append_chunk, + sctp_packet_transmit_chunk, + sctp_packet_transmit); + + if (NULL == sctp_ulpqueue_init(&asoc->ulpq, asoc, SCTP_MAX_STREAM)) { + goto fail_init; + } + + /* Set up the tsn tracking. */ + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); + asoc->peer.next_dup_tsn = 0; + + skb_queue_head_init(&asoc->addip_chunks); + + asoc->need_ecne = 0; + + asoc->debug_name = "unnamedasoc"; + asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; + + /* Assume that peer would support both address types unless we are + * told otherwise. + */ + asoc->peer.ipv4_address = 1; + asoc->peer.ipv6_address = 1; + INIT_LIST_HEAD(&asoc->asocs); + + asoc->autoclose = sp->autoclose; + + return asoc; + +fail_init: + sctp_endpoint_put(asoc->ep); + sock_put(asoc->base.sk); + return NULL; + +} /* sctp_association_init() */ + + +/* Free this association if possible. There may still be users, so + * the actual deallocation may be delayed. +*/ +void +sctp_association_free(sctp_association_t *asoc) +{ + sctp_transport_t *transport; + sctp_endpoint_t *ep; + list_t *pos, *temp; + int i; + + ep = asoc->ep; + list_del(&asoc->asocs); + + /* Mark as dead, so other users can know this structure is + * going away. + */ + asoc->base.dead = 1; + + /* Dispose of any data lying around in the outqueue. */ + sctp_outqueue_free(&asoc->outqueue); + + /* Dispose of any pending messages for the upper layer. */ + sctp_ulpqueue_free(&asoc->ulpq); + + /* Dispose of any pending chunks on the inqueue. */ + sctp_inqueue_free(&asoc->base.inqueue); + + /* Clean up the bound address list. */ + sctp_bind_addr_free(&asoc->base.bind_addr); + + /* Do we need to go through all of our timers and + * delete them? To be safe we will try to delete all, but we + * should be able to go through and make a guess based + * on our state. + */ + + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + if (timer_pending(&asoc->timers[i]) + && del_timer(&asoc->timers[i])) { + sctp_association_put(asoc); + } + } + + /* Release the transport structures. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + list_del(pos); + sctp_transport_free(transport); + } /* for (all transports). */ + + asoc->eyecatcher = 0; + + sctp_association_put(asoc); + +} /* sctp_association_free() */ + + +/* Cleanup and free up an association. */ +static void +sctp_association_destroy(sctp_association_t *asoc) +{ + SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); + + sctp_endpoint_put(asoc->ep); + sock_put(asoc->base.sk); + + if (asoc->base.malloced) { + kfree(asoc); + SCTP_DBG_OBJCNT_DEC(assoc); + } + +} /* sctp_association_destroy() */ + + +/* Add a transport address to an association. */ +sctp_transport_t * +sctp_assoc_add_peer(sctp_association_t *asoc, const sockaddr_storage_t *addr, + int priority) +{ + sctp_transport_t *peer; + sctp_opt_t *sp; + const uint16_t *port; + + switch (addr->sa.sa_family){ + case AF_INET: + port = &addr->v4.sin_port; + break; + case AF_INET6: + SCTP_V6( + port = &addr->v6.sin6_port; + break; + ); + default: + return NULL; + } /* switch addr type */ + + /* Set the port if it has not been set yet. */ + if (0 == asoc->peer.port) { + asoc->peer.port = *port; + } + + SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", + return NULL); + + /* Check to see if this is a duplicate. */ + peer = sctp_assoc_lookup_paddr(asoc, addr); + if (peer) { return peer; } + + peer = sctp_transport_new(addr, priority); + if (NULL == peer) { return NULL; } + + sctp_transport_set_owner(peer, asoc); + + /* If this is the first transport addr on this association, + * initialize the association PMTU to the peer's PMTU. + * If not and the current association PMTU is higher than the new + * peer's PMTU, reset the association PMTU to the new peer's PMTU. + */ + if (asoc->pmtu) { + asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu); + } else { + asoc->pmtu = peer->pmtu; + } + + SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " + "%d\n", asoc, asoc->pmtu); + + asoc->frag_point = asoc->pmtu - + (SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t)); + + /* The asoc->peer.port might not be meaningful as of now, but + * initialize the packet structure anyway. + */ + (asoc->outqueue.init_output)(&peer->packet, + peer, + asoc->base.bind_addr.port, + asoc->peer.port); + + /* 7.2.1 Slow-Start + * + * o The initial cwnd before data transmission or after a + * sufficiently long idle period MUST be <= 2*MTU. + * + * o The initial value of ssthresh MAY be arbitrarily high + * (for example, implementations MAY use the size of the + * receiver advertised window). + */ + peer->cwnd = asoc->pmtu * 2; + /* At this point, we may not have the receiver's advertised window, + * so initialize ssthresh to the default value and it will be set + * later when we process the INIT. + */ + peer->ssthresh = SCTP_DEFAULT_MAXWINDOW; + + peer->partial_bytes_acked = 0; + peer->flight_size = 0; + + peer->error_threshold = peer->max_retrans; + + /* Update the overall error threshold value of the association + * taking the new peer's error threshold into account. + */ + asoc->overall_error_threshold = + min(asoc->overall_error_threshold + peer->error_threshold, + asoc->max_retrans); + + /* Initialize the peer's heartbeat interval based on the + * sock configured value. + */ + sp = sctp_sk(asoc->base.sk); + peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; + + /* Attach the remote transport to our asoc. */ + list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); + + /* If we do not yet have a primary path, set one. */ + if (NULL == asoc->peer.primary_path) { + asoc->peer.primary_path = peer; + asoc->peer.active_path = peer; + asoc->peer.retran_path = peer; + } + + if (asoc->peer.active_path == asoc->peer.retran_path) { + asoc->peer.retran_path = peer; + } + + return peer; + +} /* sctp_assoc_add_peer() */ + +/* Lookup a transport by address. */ +sctp_transport_t * +sctp_assoc_lookup_paddr(const sctp_association_t *asoc, + const sockaddr_storage_t *address) +{ + sctp_transport_t *t; + list_t *pos; + + /* Cycle through all transports searching for a peer address. */ + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + if ( sctp_cmp_addr_exact(address, &t->ipaddr) ) { return t; } + } /* for (all transports) */ + + return NULL; + +} /* sctp_assoc_lookup_paddr() */ + +/* Engage in transport control operations. + * Mark the transport up or down and send a notification to the user. + * Select and update the new active and retran paths. + */ +void +sctp_assoc_control_transport(sctp_association_t *asoc, + sctp_transport_t *transport, + sctp_transport_cmd_t command, + sctp_sn_error_t error) +{ + sctp_transport_t *t = NULL; + sctp_transport_t *first; + sctp_transport_t *second; + sctp_ulpevent_t *event; + list_t *pos; + int spc_state = 0; + + + /* Record the transition on the transport. */ + switch (command) { + case SCTP_TRANSPORT_UP: + transport->state.active = 1; + spc_state = ADDRESS_AVAILABLE; + break; + case SCTP_TRANSPORT_DOWN: + transport->state.active = 0; + spc_state = ADDRESS_UNREACHABLE; + break; + default: + BUG(); + } /* switch (command) */ + + + /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the + * user. + */ + event = sctp_ulpevent_make_peer_addr_change(asoc, + (struct sockaddr_storage *)&transport->ipaddr, + 0, spc_state, error, GFP_ATOMIC); + if (event) { + sctp_ulpqueue_tail_event(&asoc->ulpq, event); + } + + + /* Select new active and retran paths. */ + + /* Look for the two most recently used active transports. + * + * This code produces the wrong ordering whenever jiffies + * rolls over, but we still get usable transports, so we don't + * worry about it. + */ + first = NULL; second = NULL; + + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + + if (!t->state.active) { continue; } + + if (!first || t->last_time_heard > first->last_time_heard) { + second = first; + first = t; + } + if (!second || t->last_time_heard > second->last_time_heard) { + second = t; + } + + } /* for (all transports) */ + + /* RFC 2960 6.4 Multi-Homed SCTP Endpoints + * + * By default, an endpoint should always transmit to the + * primary path, unless the SCTP user explicitly specifies the + * destination transport address (and possibly source + * transport address) to use. + * + * [If the primary is active but not most recent, bump the most + * recently used transport.] + */ + if (asoc->peer.primary_path->state.active + && first != asoc->peer.primary_path) { + second = first; + first = asoc->peer.primary_path; + } + + + /* If we failed to find a usable transport, just camp on the + * primary, even if it is inactive. + */ + if ( NULL == first ) { + first = asoc->peer.primary_path; + second = asoc->peer.primary_path; + } + + /* Set the active and retran transports. */ + asoc->peer.active_path = first; + asoc->peer.retran_path = second; + + return; + +} /* sctp_assoc_control_transport() */ + + +/* Hold a reference to an association. */ +void sctp_association_hold(sctp_association_t *asoc) +{ + atomic_inc(&asoc->base.refcnt); + +} /* sctp_association_hold() */ + +/* Release a reference to an association and cleanup + * if there are no more references. + */ +void sctp_association_put(sctp_association_t *asoc) +{ + if (atomic_dec_and_test(&asoc->base.refcnt)) { + sctp_association_destroy(asoc); + } + +} /* sctp_association_put() */ + + +/* Allocate the next TSN, Transmission Sequence Number, for the given + * association. + */ +uint32_t +__sctp_association_get_next_tsn(sctp_association_t *asoc) +{ + /* From Section 1.6 Serial Number Arithmetic: + * Transmission Sequence Numbers wrap around when they reach + * 2**32 - 1. That is, the next TSN a DATA chunk MUST use + * after transmitting TSN = 2*32 - 1 is TSN = 0. + */ + uint32_t retval = asoc->next_tsn; + asoc->next_tsn++; + asoc->unack_data++; + + return retval; + +} /* __sctp_association_get_next_tsn() */ + + +/* Allocate 'num' TSNs by incrementing the association's TSN by num. */ +uint32_t +__sctp_association_get_tsn_block(sctp_association_t *asoc, int num) +{ + uint32_t retval = asoc->next_tsn; + asoc->next_tsn += num; + asoc->unack_data += num; + + return retval; + +} /* __sctp_association_get_tsn_block() */ + + +/* Fetch the next Stream Sequence Number for stream number 'sid'. */ +uint16_t +__sctp_association_get_next_ssn(sctp_association_t *asoc, uint16_t sid) +{ + return(asoc->ssn[sid]++); + +} /* __sctp_association_get_next_ssn() */ + + +/* Compare two addresses to see if they match. Wildcard addresses + * always match within their address family. + * + * FIXME: We do not match address scopes correctly. + */ +int +sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2) +{ + int len; + const void *base1; + const void *base2; + + if (ss1->sa.sa_family != ss2->sa.sa_family) { + return 0; + } + if (ss1->v4.sin_port != ss2->v4.sin_port) { + return 0; + } + + switch (ss1->sa.sa_family) { + case AF_INET: + if (INADDR_ANY == ss1->v4.sin_addr.s_addr || + INADDR_ANY == ss2->v4.sin_addr.s_addr) { + goto match; + } + + len = sizeof(struct in_addr); + base1 = &ss1->v4.sin_addr; + base2 = &ss2->v4.sin_addr; + break; + case AF_INET6: + SCTP_V6( + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss1->v6.sin6_addr)) { + goto match; + } + + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss2->v6.sin6_addr)) { + goto match; + } + len = sizeof(struct in6_addr); + base1 = &ss1->v6.sin6_addr; + base2 = &ss2->v6.sin6_addr; + break; + ) + + default: + printk(KERN_WARNING + "WARNING, bogus socket address family %d\n", + ss1->sa.sa_family); + return 0; + } + + return (0 == memcmp(base1, base2, len)); + match: + return 1; + +} /* sctp_cmp_addr() */ + +/* Compare two addresses to see if they match. Wildcard addresses + * only match themselves. + * + * FIXME: We do not match address scopes correctly. + */ +int +sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2) +{ + int len; + const void *base1; + const void *base2; + + + if (ss1->sa.sa_family != ss2->sa.sa_family) { + return 0; + } + + if (ss1->v4.sin_port != ss2->v4.sin_port) { + return 0; + } + + switch(ss1->sa.sa_family) { + case AF_INET: + len = sizeof(struct in_addr); + base1 = &ss1->v4.sin_addr; + base2 = &ss2->v4.sin_addr; + break; + case AF_INET6: + SCTP_V6( + len = sizeof(struct in6_addr); + base1 = &ss1->v6.sin6_addr; + base2 = &ss2->v6.sin6_addr; + break; + ) + default: + printk(KERN_WARNING + "WARNING, bogus socket address family %d\n", + ss1->sa.sa_family); + return 0; + } + + return (0 == memcmp(base1, base2, len)); + +} /* sctp_cmp_addr_exact() */ + + +/* Return an ecne chunk to get prepended to a packet. + * Note: We are sly and return a shared, prealloced chunk. + */ +sctp_chunk_t * +sctp_get_ecne_prepend(sctp_association_t *asoc) +{ + sctp_chunk_t *chunk; + int need_ecne; + uint32_t lowest_tsn; + + /* Can be called from task or bh. Both need_ecne and + * last_ecne_tsn are written during bh. + */ + + need_ecne = asoc->need_ecne; + lowest_tsn = asoc->last_ecne_tsn; + + if (need_ecne) { + chunk = sctp_make_ecne(asoc, lowest_tsn); + + /* ECNE is not mandatory to the flow. Being unable to + * alloc mem is not deadly. We are just unable to help + * out the network. If we run out of memory, just return + * NULL. + */ + + } else { + chunk = NULL; + } + + return chunk; + +} /* sctp_get_ecne_prepend(asoc) */ + + +/* Use this function for the packet prepend callback when no ECNE + * packet is desired (e.g. some packets don't like to be bundled). + */ +sctp_chunk_t * +sctp_get_no_prepend(sctp_association_t *asoc) +{ + return NULL; + +} /* sctp_get_no_prepend(asoc) */ + + +/* + * Find which transport this TSN was sent on. + */ +sctp_transport_t * +sctp_assoc_lookup_tsn(sctp_association_t *asoc, uint32_t tsn) +{ + sctp_transport_t *active; + sctp_transport_t *match; + list_t *entry, *pos; + sctp_transport_t *transport; + + sctp_chunk_t *chunk; + + uint32_t key = htonl(tsn); + + match = NULL; + + /* + * FIXME: In general, find a more efficient data structure for + * searching. + */ + + /* + * The general strategy is to search each transport's transmitted + * list. Return which transport this TSN lives on. + * + * Let's be hopeful and check the active_path first. + * Another optimization would be to know if there is only one + * outbound path and not have to look for the TSN at all. + * + */ + + active = asoc->peer.active_path; + + list_for_each(entry, &active->transmitted) { + + chunk = list_entry(entry, sctp_chunk_t, transmitted_list); + + if (key == chunk->subh.data_hdr->tsn){ + match = active; + goto out; + } + } /* for (each unacknowledged TSN) */ + + /* If not found, go search all the other transports. */ + + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + if (transport == active) { break; } + + list_for_each(entry, &transport->transmitted) { + + chunk = list_entry(entry, sctp_chunk_t, + transmitted_list); + if (key == chunk->subh.data_hdr->tsn) { + match = transport; + goto out; + } + } /* for (all unacknowledged TSNs) */ + + } /* for (all transports) */ + +out: + return match; + +} /* sctp_assoc_lookup_tsn() */ + +/* Is this the association we are looking for? */ +sctp_transport_t * +sctp_assoc_is_match(sctp_association_t *asoc, const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr) +{ + sctp_transport_t *transport; + + sctp_read_lock(&asoc->base.addr_lock); + + if ((asoc->base.bind_addr.port == laddr->v4.sin_port) && + (asoc->peer.port == paddr->v4.sin_port)) { + + transport = sctp_assoc_lookup_paddr(asoc, paddr); + if (!transport) { goto out; } + + if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) { + goto out; + } + + } + transport = NULL; + +out: + sctp_read_unlock(&asoc->base.addr_lock); + return transport; + +} /* sctp_assoc_is_match() */ + +/* Do delayed input processing. This is scheduled by sctp_rcv(). */ +static void +sctp_assoc_bh_rcv(sctp_association_t *asoc) +{ + sctp_endpoint_t *ep; + sctp_chunk_t *chunk; + struct sock *sk; + sctp_inqueue_t *inqueue; + int state, subtype; + sctp_assoc_t associd = sctp_assoc2id(asoc); + int error = 0; + + /* The association should be held so we should be safe. */ + ep = asoc->ep; + sk = asoc->base.sk; + + inqueue = &asoc->base.inqueue; + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + state = asoc->state; + subtype = chunk->chunk_hdr->type; + + /* Remember where the last DATA chunk came from so we + * know where to send the SACK. + */ + if (sctp_chunk_is_data(chunk)) { + asoc->peer.last_data_from = chunk->transport; + } + + if (chunk->transport) { + chunk->transport->last_time_heard = jiffies; + } + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), + state, ep, asoc, chunk, GFP_ATOMIC); + + /* Check to see if the association is freed in response to + * the incoming chunk. If so, get out of the while loop. + */ + if (!sctp_id2assoc(sk, associd)) { goto out; } + + if (error != 0) { goto err_out; } + + } /* while (we have more chunks to receive) */ + +err_out: + /* Is this the right way to pass errors up to the ULP? */ + if (error) { + sk->err = -error; + } + +out: + return; + +} /* sctp_bh_rcv_asoc() */ + +/* This routine moves an association from its old sk to a new sk. */ +void +sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) +{ + sctp_opt_t *newsp = sctp_sk(newsk); + + /* Delete the association from the old endpoint's list of + * associations. + */ + list_del(&assoc->asocs); + + /* Release references to the old endpoint and the sock. */ + sctp_endpoint_put(assoc->ep); + sock_put(assoc->base.sk); + + /* Get a reference to the new endpoint. */ + assoc->ep = newsp->ep; + sctp_endpoint_hold(assoc->ep); + + /* Get a reference to the new sock. */ + assoc->base.sk = newsk; + sock_hold(assoc->base.sk); + + /* Add the association to the new endpoint's list of associations. */ + sctp_endpoint_add_asoc(newsp->ep, assoc); + +} /* sctp_assoc_migrate() */ + +/* Update an association (possibly from unexpected COOKIE-ECHO processing). */ +void +sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) +{ + int i; + + /* Copy in new parameters of peer. */ + asoc->c = new->c; + asoc->peer.rwnd = new->peer.rwnd; + asoc->peer.next_dup_tsn = new->peer.next_dup_tsn; + asoc->peer.sack_needed = new->peer.sack_needed; + asoc->peer.i = new->peer.i; + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, + asoc->peer.i.initial_tsn); + + /* FIXME: + * Do we need to copy primary_path etc? + * + * More explicitly, addresses may have been removed and + * this needs accounting for. + */ + + + /* If the case is A (association restart), use + * initial_tsn as next_tsn. If the case is B, use + * current next_tsn in case there is data sent to peer + * has been discarded and needs retransmission. + */ + if (SCTP_STATE_ESTABLISHED == asoc->state){ + asoc->next_tsn = new->next_tsn; + asoc->ctsn_ack_point = new->ctsn_ack_point; + + /* Reinitialize SSN for both local streams + * and peer's streams. + */ + for(i=0; i < SCTP_MAX_STREAM; i++) { + asoc->ssn[i] = 0; + asoc->ulpq.ssn[i] = 0; + } + + } else { + asoc->ctsn_ack_point = asoc->next_tsn-1; + } + + return; + +} /* sctp_assoc_update() */ + +/* Choose the transport for sending a shutdown packet. + * Round-robin through the active transports, else round-robin + * through the inactive transports as this is the next best thing + * we can try. + */ +sctp_transport_t * +sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) { + sctp_transport_t *t, *next; + list_t *head = &asoc->peer.transport_addr_list; + list_t *pos; + + + /* If this is the first time SHUTDOWN is sent, use the active + * path. + */ + if (!asoc->shutdown_last_sent_to) { + return asoc->peer.active_path; + } + + /* Otherwise, find the next transport in a round-robin fashion. */ + + t = asoc->shutdown_last_sent_to; + pos = &t->transports; + next = NULL; + + while (1) { + + /* Skip the head. */ + if (pos->next == head) { + pos = head->next; + } else { + pos = pos->next; + } + + t = list_entry(pos, sctp_transport_t, transports); + + /* Try to find an active transport. */ + + if (t->state.active) { + break; + } else { + /* Keep track of the next transport in case + * we don't find any active transport. + */ + if (!next) { + next = t; + } + } + + /* We have exhausted the list, but didn't find any + * other active transports. If so, use the next + * transport. + */ + if (t == asoc->shutdown_last_sent_to) { + t = next; + break; + } + } + + return t; + +} /* sctp_assoc_choose_shutdown_transport() */ diff --git a/net/sctp/sctp_bind_addr.c b/net/sctp/sctp_bind_addr.c new file mode 100644 index 000000000000..be6d11202997 --- /dev/null +++ b/net/sctp/sctp_bind_addr.c @@ -0,0 +1,587 @@ +/* SCTP kernel reference Implementation + * Copyright (c) Cisco 1999,2000 + * Copyright (c) Motorola 1999,2000,2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) La Monte H.P. Yarroll 2001 + * + * This file is part of the SCTP kernel reference implementation. + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_bind_addr.c,v 1.16 2002/07/12 15:15:45 jgrimm Exp $ + * + * A collection class to handle the storage of transport addresses. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_bind_addr.c,v 1.16 2002/07/12 15:15:45 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, + sctp_scope_t scope, int priority, int flags); +static void sctp_bind_addr_clean(sctp_bind_addr_t *); + +/* First Level Abstractions. */ + +/* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses + * in 'src' which have a broader scope than 'scope'. + */ +int +sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, + sctp_scope_t scope, int priority, int flags) +{ + int error = 0; + struct sockaddr_storage_list *addr; + list_t *pos; + + /* All addresses share the same port. */ + dest->port = src->port; + + /* Extract the addresses which are relevant for this scope. */ + list_for_each(pos, &src->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + error = sctp_copy_one_addr(dest, &addr->a, scope, priority, + flags); + if (error < 0) { goto out; } + + } /* for (each address in the source bind_addr) */ + + out: + if (0 != error) { + sctp_bind_addr_clean(dest); + } + + return error; + +} /* sctp_bind_addr_copy() */ + +/* Create a new SCTP_bind_addr from nothing. */ +sctp_bind_addr_t * +sctp_bind_addr_new(int priority) +{ + sctp_bind_addr_t *retval; + + retval = t_new(sctp_bind_addr_t, priority); + if (NULL == retval) { goto nomem; } + + sctp_bind_addr_init(retval, 0); + retval->malloced = 1; + SCTP_DBG_OBJCNT_INC(bind_addr); + nomem: + return retval; + +} /* sctp_bind_addr_new() */ + + +/* Initialize the SCTP_bind_addr structure for either an endpoint or + * an association. + */ +void +sctp_bind_addr_init(sctp_bind_addr_t *bp, uint16_t port) +{ + bp->malloced = 0; + + INIT_LIST_HEAD(&bp->address_list); + bp->port = port; + +} /* sctp_bind_addr_init() */ + +/* Dispose of the address list. */ +static void +sctp_bind_addr_clean(sctp_bind_addr_t *bp) +{ + struct sockaddr_storage_list *addr; + list_t *pos, *temp; + + /* Empty the bind address list. */ + list_for_each_safe(pos, temp, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + list_del(pos); + kfree(addr); + SCTP_DBG_OBJCNT_DEC(addr); + } /* for (each bound address) */ + +} /* sctp_bind_addr_clean() */ + +/* Dispose of an SCTP_bind_addr structure + */ +void +sctp_bind_addr_free(sctp_bind_addr_t *bp) +{ + + /* Empty the bind address list. */ + sctp_bind_addr_clean(bp); + + if (bp->malloced) { + kfree(bp); + SCTP_DBG_OBJCNT_DEC(bind_addr); + } + +} /* sctp_bind_addr_free() */ + +/* Add an address to the bind address list in the SCTP_bind_addr structure. */ +int +sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, + int priority) +{ + + struct sockaddr_storage_list *addr; + + /* Add the address to the bind address list. */ + addr = t_new(struct sockaddr_storage_list, priority); + if (NULL == addr) { + return -ENOMEM; + } + + addr->a = *new; + + /* Fix up the port if it has not yet been set. + * Both v4 and v6 have the port at the same offset. + */ + if (0 == addr->a.v4.sin_port) { + addr->a.v4.sin_port = bp->port; + } + + INIT_LIST_HEAD(&addr->list); + list_add_tail(&addr->list, &bp->address_list); + SCTP_DBG_OBJCNT_INC(addr); + + return 0; + +} /* sctp_add_bind_addr() */ + +/* Delete an address from the bind address list in the SCTP_bind_addr + * structure. + */ +int +sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) +{ + list_t *pos, *temp; + struct sockaddr_storage_list *addr; + + list_for_each_safe(pos, temp, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_cmp_addr_exact(&addr->a, del_addr)) { + /* Found the exact match. */ + list_del(pos); + kfree(addr); + SCTP_DBG_OBJCNT_DEC(addr); + return 0; + } + } /* for (each bound address) */ + + return -EINVAL; + +} /* sctp_del_bind_addr() */ + +/* Create a network byte-order representation of all the addresses + * formated as SCTP parameters. + * + * The second argument is the return value for the length. + */ +sctpParam_t +sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, + int priority) +{ + sctpParam_t rawaddr; + sctpParam_t addrparms; + sctpParam_t retval; + int addrparms_len; + sctpIpAddress_t rawaddr_space; + int len; + struct sockaddr_storage_list *addr; + list_t *pos; + + retval.v = NULL; + addrparms_len = 0; + len = 0; + + /* Allocate enough memory at once. */ + list_for_each(pos, &bp->address_list) { + len += sizeof(sctp_ipv6addr_param_t); + } /* for (each bound address) */ + + addrparms.v = kmalloc(len, priority); + if (NULL == addrparms.v) { goto end_raw; } + + retval = addrparms; + rawaddr.v4 = &rawaddr_space.v4; + + list_for_each(pos, &bp->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + len = sockaddr2sctp_addr(&addr->a, rawaddr); + memcpy(addrparms.v, rawaddr.v, len); + addrparms.v += len; + addrparms_len += len; + } /* for (all addresses in the bind address list) */ + +end_raw: + + *addrs_len = addrparms_len; + return retval; + +} /* sctp_bind_addrs_to_raw() */ + +/* + * Create an address list out of the raw address list format (IPv4 and IPv6 + * address parameters). + * + */ +int +sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, uint8_t *raw_addr_list, + int addrs_len, uint16_t port, int priority) +{ + sctpParam_t rawaddr; + sockaddr_storage_t addr; + int retval = 0; + int len; + + /* Convert the raw address to standard address format */ + while (addrs_len) { + rawaddr.v = raw_addr_list; + if (SCTP_PARAM_IPV4_ADDRESS==rawaddr.p->type + || SCTP_PARAM_IPV6_ADDRESS==rawaddr.p->type) { + + sctp_param2sockaddr(&addr, rawaddr, port); + retval = sctp_add_bind_addr(bp, &addr, priority); + if (retval) { + /* Can't finish building the list, clean up. */ + sctp_bind_addr_clean(bp); + break; + } + + len = ntohs(rawaddr.p->length); + addrs_len -= len; + raw_addr_list += len; + } else { + /* Corrupted raw addr list! */ + retval = -EINVAL; + sctp_bind_addr_clean(bp); + break; + } + } + + return retval; + +} /* sctp_raw_to_bind_addrs() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Does this contain a specified address? */ +int +sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) +{ + list_t *pos; + struct sockaddr_storage_list *laddr; + + list_for_each(pos, &bp->address_list) { + laddr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_cmp_addr(&laddr->a, addr)) { + return 1; + } + } /* for (all bound addresses). */ + + return 0; + +} /* sctp_bind_addr_has_addr() */ + +/* Copy out addresses from the global local address list. */ +static int +sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, + sctp_scope_t scope, int priority, int flags) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + int error = 0; + + if (sctp_is_any(addr)) { + error = sctp_copy_local_addr_list(proto, dest, scope, + priority, flags); + } else if (sctp_in_scope(addr, scope)) { + /* Now that the address is in scope, check to see if + * the address type is supported by local sock as + * well as the remote peer. + */ + if ((((AF_INET == addr->sa.sa_family) + && (flags & SCTP_ADDR4_PEERSUPP))) + || (((AF_INET6 == addr->sa.sa_family) + && (flags & SCTP_ADDR6_ALLOWED) + && (flags & SCTP_ADDR6_PEERSUPP)))) { + + error = sctp_add_bind_addr(dest, addr, priority); + } + } + + return error; + +} /* sctp_copy_one_addr() */ + + +/* Is addr one of the wildcards? */ +int +sctp_is_any(const sockaddr_storage_t *addr) +{ + int retval = 0; + + switch (addr->sa.sa_family) { + case AF_INET: + if (INADDR_ANY == addr->v4.sin_addr.s_addr) { + retval = 1; + } + break; + case AF_INET6: + SCTP_V6( + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&addr->v6.sin6_addr)) { + retval = 1; + } + ); + break; + default: + break; + } + + return retval; + +} /* sctp_is_any() */ + +/* Is 'addr' valid for 'scope'? */ +int +sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) +{ + + sctp_scope_t addr_scope = sctp_scope(addr); + + switch (addr->sa.sa_family) { + case AF_INET: + /* According to the SCTP IPv4 address scoping document - + * , the scope has + * a heirarchy of 5 levels: + * Level 0 - unusable SCTP addresses + * Level 1 - loopback address + * Level 2 - link-local addresses + * Level 3 - private addresses. + * Level 4 - global addresses + * For INIT and INIT-ACK address list, let L be the level of + * of requested destination address, sender and receiver + * SHOULD include all of its addresses with level greater + * than or equal to L. + */ + /* The unusable SCTP addresses will not be considered with + * any defined scopes. + */ + if (SCTP_SCOPE_UNUSABLE == addr_scope) { + return 0 ; + } + + /* Note that we are assuming that the scoping are the same + * for both IPv4 addresses and IPv6 addresses, i.e., if the + * scope is link local, both IPv4 link local addresses and + * IPv6 link local addresses would be treated as in the + * scope. There is no filtering for IPv4 vs. IPv6 addresses + * based on scoping alone. + */ + if (addr_scope <= scope) { + return 1; + } + break; + + case AF_INET6: + + /* FIXME: + * This is almost certainly wrong since scopes have an + * heirarchy. I don't know what RFC to look at. + * There may be some guidance in the SCTP implementors + * guide (an Internet Draft as of October 2001). + * + * Further verification on the correctness of the IPv6 + * scoping is needed. According to the IPv6 scoping draft, + * the link local and site local address may require + * further scoping. + * + * Is the heirachy of the IPv6 scoping the same as what's + * defined for IPv4? + * If the same heirarchy indeed applies to both famiies, + * this function can be simplified with one set of code. + * (see the comments for IPv4 above) + * + */ + if (addr_scope <= scope) { + return 1; + } + + break; + + default: + return 0; + } + + return 0; + +} /* sctp_in_scope() */ + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + +/* What is the scope of 'addr'? */ +sctp_scope_t +sctp_scope(const sockaddr_storage_t *addr) +{ + + sctp_scope_t retval = SCTP_SCOPE_GLOBAL; + + switch (addr->sa.sa_family) { + case AF_INET: + /* We are checking the loopback, private and other address + * scopes as defined in RFC 1918. + * The IPv4 scoping is based on the draft for SCTP IPv4 + * scoping . + * The set of SCTP address scope hopefully can cover both + * types of addresses. + */ + /* Should IPv4 scoping be a sysctl configurable option + * so users can turn it off (default on) for certain + * unconventional networking environments? + */ + /* Check for unusable SCTP addresses. */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_UNUSABLE ; + + } else if (LOOPBACK(addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LOOPBACK; + + } else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) { + retval = SCTP_SCOPE_LINK; + + } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)){ + retval = SCTP_SCOPE_PRIVATE; + + } else { + retval = SCTP_SCOPE_GLOBAL; + + } + + + break; + + case AF_INET6: + { + SCTP_V6( + int v6scope; + v6scope = ipv6_addr_scope((struct in6_addr *) + &addr->v6.sin6_addr); + /* The IPv6 scope is really a set of bit + * fields. See IFA_* in . + * Mapping them to the generic SCTP scope + * set is an attempt to have code + * consistencies with the IPv4 scoping. + */ + switch (v6scope) { + case IFA_HOST: + retval = SCTP_SCOPE_LOOPBACK; + break; + case IFA_LINK: + retval = SCTP_SCOPE_LINK; + break; + case IFA_SITE: + retval = SCTP_SCOPE_PRIVATE; + break; + default: + retval = SCTP_SCOPE_GLOBAL; + } + ); + + break; + } + + default: + retval = SCTP_SCOPE_GLOBAL; + } + + return retval; + +} /* sctp_scope() */ + +/* This function checks if the address is a valid address to be used for + * SCTP. + * + * Output: + * Return 0 - If the address is a non-unicast or an illegal address. + * Return 1 - If the address is a unicast. + */ +int +sctp_addr_is_valid(const sockaddr_storage_t *addr) +{ + unsigned short sa_family = addr->sa.sa_family; + + switch (sa_family) { + case AF_INET: + /* Is this a non-unicast address or a unusable SCTP address? */ + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + return 0; + } + break; + + case AF_INET6: + SCTP_V6( + { + int ret; + + ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + /* Is this a non-unicast address */ + if (!(ret & IPV6_ADDR_UNICAST)) { + return 0; + } + break; + }); + default: + return 0; + } + + return 1; + + +} /* sctp_addr_is_valid() */ + diff --git a/net/sctp/sctp_command.c b/net/sctp/sctp_command.c new file mode 100644 index 000000000000..cf41e09ffa95 --- /dev/null +++ b/net/sctp/sctp_command.c @@ -0,0 +1,123 @@ +/* SCTP kernel reference Implementation Copyright (C) 1999-2001 + * Cisco, Motorola, and IBM + * Copyright 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_command.c,v 1.4 2002/04/24 16:33:39 jgrimm Exp $ + * + * These functions manipulate sctp command sequences. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_command.c,v 1.4 2002/04/24 16:33:39 jgrimm Exp $"; + +#include +#include +#include +#include + +/* Create a new sctp_command_sequence. */ +sctp_cmd_seq_t * +sctp_new_cmd_seq(int priority) +{ + sctp_cmd_seq_t *retval; + + retval = t_new(sctp_cmd_seq_t, priority); + + sctp_init_cmd_seq(retval); + + return retval; + +} /* sctp_new_cmd_seq() */ + +/* Initialize a block of memory as a command sequence. */ +int +sctp_init_cmd_seq(sctp_cmd_seq_t *seq) +{ + memset(seq, 0, sizeof(sctp_cmd_seq_t)); + return 1; /* We always succeed. */ + +} /* sctp_init_cmd_seq() */ + +/* Add a command to a sctp_cmd_seq_t. + * Return 0 if the command sequence is full. + */ +int +sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +{ + if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS) { + goto fail; + } + + seq->cmds[seq->next_free_slot].verb = verb; + seq->cmds[seq->next_free_slot++].obj = obj; + + return 1; + fail: + return 0; + +} /* sctp_add_cmd() */ + +/* Rewind an sctp_cmd_seq_t to iterate from the start. */ +int +sctp_rewind_sequence(sctp_cmd_seq_t *seq) +{ + seq->next_cmd = 0; + return 1; /* We always succeed. */ + +} /* sctp_rewind_sequence() */ + +/* Return the next command structure in a sctp_cmd_seq. + * Returns NULL at the end of the sequence. + */ +sctp_cmd_t * +sctp_next_cmd(sctp_cmd_seq_t *seq) +{ + sctp_cmd_t *retval = NULL; + + if (seq->next_cmd < seq->next_free_slot) { + retval = &seq->cmds[seq->next_cmd++]; + } + + return retval; + +} /* sctp_next_cmd() */ + +/* Dispose of a command sequence. */ +void +sctp_free_cmd_seq(sctp_cmd_seq_t *seq) +{ + kfree(seq); + +} /* sctp_free_cmd_seq() */ diff --git a/net/sctp/sctp_crc32c.c b/net/sctp/sctp_crc32c.c new file mode 100644 index 000000000000..fc9a9cc29873 --- /dev/null +++ b/net/sctp/sctp_crc32c.c @@ -0,0 +1,199 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_crc32c.c,v 1.9 2002/07/12 14:50:25 jgrimm Exp $ + * + * SCTP Checksum functions + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Dinakaran Joseph + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_crc32c.c,v 1.9 2002/07/12 14:50:25 jgrimm Exp $"; + +/* The following code has been taken directly from + * draft-ietf-tsvwg-sctpcsum-03.txt + * + * The code has now been modified specifically for SCTP knowledge. + */ + + +#include +#include + +#define CRC32C_POLY 0x1EDC6F41 +#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Copyright 2001, D. Otis. Use this program, code or tables */ +/* extracted from it, as desired without restriction. */ +/* */ +/* 32 Bit Reflected CRC table generation for SCTP. */ +/* To accommodate serial byte data being shifted out least */ +/* significant bit first, the table's 32 bit words are reflected */ +/* which flips both byte and bit MS and LS positions. The CRC */ +/* is calculated MS bits first from the perspective of the serial*/ +/* stream. The x^32 term is implied and the x^0 term may also */ +/* be shown as +1. The polynomial code used is 0x1EDC6F41. */ +/* Castagnoli93 */ +/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ +/* x^11+x^10+x^9+x^8+x^6+x^0 */ +/* Guy Castagnoli Stefan Braeuer and Martin Herrman */ +/* "Optimization of Cyclic Redundancy-Check Codes */ +/* with 24 and 32 Parity Bits", */ +/* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +unsigned long crc_c[256] = +{ + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, + 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, + 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, + 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, + 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, + 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, + 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, + 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, + 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, + 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, + 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, + 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, + 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, + 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, + 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, + 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, + 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, + 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, + 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, + 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, + 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, + 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, + 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, + 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, + 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, + 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, + 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, + 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, + 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, + 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, + 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, + 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, + 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, + 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, + 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, + 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, + 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, + 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, + 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, + 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, + 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, + 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, + 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, + 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, + 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, + 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, + 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, + 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, + 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, + 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, + 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, + 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, +}; + + + +uint32_t +count_crc(uint8_t *buffer, uint16_t length) +{ + unsigned int i; + unsigned long crc32 = ~0L; + unsigned long result; + unsigned char byte0, byte1, byte2, byte3; + + /* Optimize this routine to be SCTP specific, knowing how + * to skip the checksum field of the SCTP header. + */ + + /* Calculate CRC up to the checksum. */ + for (i = 0; i < (sizeof(struct sctphdr) - sizeof(uint32_t)); i++) { + CRC32C(crc32, buffer[i]); + } + /* Skip checksum field of the header. */ + for (i = 0; i < sizeof(uint32_t); i++){ + CRC32C(crc32, 0); + } + + /* Calculate the rest of the CRC. */ + for (i = sizeof(struct sctphdr); i < length ; i++){ + CRC32C(crc32, buffer[i]); + } + + result = ~crc32; + + /* result now holds the negated polynomial remainder; + * since the table and algorithm is "reflected" [williams95]. + * That is, result has the same value as if we mapped the message + * to a polyomial, computed the host-bit-order polynomial + * remainder, performed final negation, then did an end-for-end + * bit-reversal. + * Note that a 32-bit bit-reversal is identical to four inplace + * 8-bit reversals followed by an end-for-end byteswap. + * In other words, the bytes of each bit are in the right order, + * but the bytes have been byteswapped. So we now do an explicit + * byteswap. On a little-endian machine, this byteswap and + * the final ntohl cancel out and could be elided. + */ + byte0 = result & 0xff; + byte1 = (result>>8) & 0xff; + byte2 = (result>>16) & 0xff; + byte3 = (result>>24) & 0xff; + + crc32 = ((byte0 << 24) | + (byte1 << 16) | + (byte2 << 8) | + byte3); + return(crc32); + +} /* count_crc() */ + + diff --git a/net/sctp/sctp_debug.c b/net/sctp/sctp_debug.c new file mode 100644 index 000000000000..12ca661ad0c0 --- /dev/null +++ b/net/sctp/sctp_debug.c @@ -0,0 +1,241 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_debug.c,v 1.10 2002/07/12 14:50:25 jgrimm Exp $ + * + * This file converts numerical ID value to alphabetical names for SCTP + * terms such as chunk type, parameter time, event type, etc. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_debug.c,v 1.10 2002/07/12 14:50:25 jgrimm Exp $"; + +#include + +#if SCTP_DEBUG +int sctp_debug_flag = 1; /* Initially enable DEBUG */ +#endif /* SCTP_DEBUG */ + + +/* These are printable forms of Chunk ID's from section 3.1. */ +static const char *sctp_cid_tbl[SCTP_NUM_BASE_CHUNK_TYPES] = { + "DATA", + "INIT", + "INIT_ACK", + "SACK", + "HEARTBEAT", + "HEARTBEAT_ACK", + "ABORT", + "SHUTDOWN", + "SHUTDOWN_ACK", + "ERROR", + "COOKIE_ECHO", + "COOKIE_ACK", + "ECN_ECNE", + "ECN_CWR", + "SHUTDOWN_COMPLETE", +}; /* char *sctp_cid_tbl[] */ + +/* Lookup "chunk type" debug name. */ +const char * +sctp_cname(const sctp_subtype_t cid) +{ + if ( cid.chunk < 0 ) { + return "illegal chunk id"; + } + + if ( cid.chunk <= SCTP_CID_BASE_MAX ) { + return sctp_cid_tbl[cid.chunk]; + } + + switch ( cid.chunk ) { + case SCTP_CID_ASCONF : return "ASCONF"; + case SCTP_CID_ASCONF_ACK : return "ASCONF_ACK"; + default: + return "unknown chunk"; + } + + return "unknown chunk"; + +} /* sctp_cname() */ + +/* These are printable form of variable-length parameters. */ +const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE+1] = { + "", + "PARAM_HEATBEAT_INFO", + "", + "", + "", + "PARAM_IPV4_ADDRESS", + "PARAM_IPV6_ADDRESS", + "PARAM_STATE_COOKIE", + "PARAM_UNRECOGNIZED_PARAMETERS", + "PARAM_COOKIE_PRESERVATIVE", + "", + "PARAM_HOST_NAME_ADDRESS", + "PARAM_SUPPORTED_ADDRESS_TYPES", +}; /* char *sctp_param_tbl[] */ + + +/* These are printable forms of the states. */ +const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = { + "STATE_EMPTY", + "STATE_CLOSED", + "STATE_COOKIE_WAIT", + "STATE_COOKIE_ECHOED", + "STATE_ESTABLISHED", + "STATE_SHUTDOWN_PENDING", + "STATE_SHUTDOWN_SENT", + "STATE_SHUTDOWN_RECEIVED", + "STATE_SHUTDOWN_ACK_SENT", +}; /* char *sctp_state_tbl[] */ + +/* Events that could change the state of an association. */ +const char *sctp_evttype_tbl[] = { + "EVENT_T_unknown", + "EVENT_T_CHUNK", + "EVENT_T_TIMEOUT", + "EVENT_T_OTHER", + "EVENT_T_PRIMITIVE" +}; + +/* Return value of a state function */ +const char *sctp_status_tbl[] = { + "DISPOSITION_DISCARD", + "DISPOSITION_CONSUME", + "DISPOSITION_NOMEM", + "DISPOSITION_DELETE_TCB", + "DISPOSITION_ABORT", + "DISPOSITION_VIOLATION", + "DISPOSITION_NOT_IMPL", + "DISPOSITION_ERROR", + "DISPOSITION_BUG" +}; + +/* 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. */ +const char * +sctp_pname(const sctp_subtype_t id) +{ + if ( id.primitive < 0 ) { + return "illegal primitive"; + } + + if ( id.primitive <= SCTP_EVENT_PRIMITIVE_MAX ) { + return sctp_primitive_tbl[id.primitive]; + } + + return "unknown_primitive"; + +} /* sctp_pname() */ + +static const char *sctp_other_tbl[] = { + "NO_PENDING_TSN", + "ICMP_UNREACHFRAG" +}; + +/* Lookup "other" debug name. */ +const char * +sctp_oname(const sctp_subtype_t id) +{ + if ( id.other < 0 ) { + return "illegal 'other' event"; + } + + if ( id.other < SCTP_EVENT_OTHER_MAX ) { + return sctp_other_tbl[id.other]; + } + + return "unknown 'other' event"; +} /* sctp_oname() */ + +static const char *sctp_timer_tbl[] = { + "TIMEOUT_NONE", + "TIMEOUT_T1_COOKIE", + "TIMEOUT_T1_INIT", + "TIMEOUT_T2_SHUTDOWN", + "TIMEOUT_T3_RTX", + "TIMEOUT_T4_RTO", + "TIMEOUT_HEARTBEAT", + "TIMEOUT_SACK", + "TIMEOUT_AUTOCLOSE", + "TIMEOUT_PMTU_RAISE", +}; + +/* Lookup timer debug name. */ +const char * +sctp_tname(const sctp_subtype_t id) +{ + if ( id.timeout < 0 ) { + return "illegal 'timer' event"; + } + + if ( id.timeout <= SCTP_EVENT_TIMEOUT_MAX ) { + return sctp_timer_tbl[id.timeout]; + } + + return "unknown_timer"; + +} /* sctp_tname() */ + + diff --git a/net/sctp/sctp_endpointola.c b/net/sctp/sctp_endpointola.c new file mode 100644 index 000000000000..16799bcc5970 --- /dev/null +++ b/net/sctp/sctp_endpointola.c @@ -0,0 +1,417 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_endpointola.c,v 1.26 2002/08/16 19:30:49 jgrimm Exp $ + * + * This abstraction represents an SCTP endpoint. + * + * This file is part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Daisy Chang + * Dajiang Zhang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_endpointola.c,v 1.26 2002/08/16 19:30:49 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include /* get_random_bytes() */ +#include +#include +#include +#include + + +/* Forward declarations for internal helpers. */ +static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); + + +/* Create a sctp_endpoint_t with all that boring stuff initialized. + * Returns NULL if there isn't enough memory. + */ +sctp_endpoint_t * +sctp_endpoint_new(sctp_protocol_t *proto, struct sock *sk, int priority) +{ + sctp_endpoint_t *ep; + + /* Build a local endpoint. */ + ep = t_new(sctp_endpoint_t, priority); + if (NULL == ep) { + goto fail; + } + + if (NULL == sctp_endpoint_init(ep, proto, sk, priority)) { + goto fail_init; + } + ep->base.malloced = 1; + SCTP_DBG_OBJCNT_INC(ep); + return ep; + +fail_init: + kfree(ep); +fail: + return NULL; + +} /* sctp_endpoint_new() */ + + +/* + * Initialize the base fields of the endpoint structure. + */ +sctp_endpoint_t * +sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, + struct sock *sk, int priority) +{ + + memset(ep, 0, sizeof(sctp_endpoint_t)); + + /* Initialize the base structure. */ + /* What type of endpoint are we? */ + ep->base.type = SCTP_EP_TYPE_SOCKET; + + /* Initialize the basic object fields. */ + atomic_set(&ep->base.refcnt, 1); + ep->base.dead = 0; + ep->base.malloced = 1; + + /* Create an input queue. */ + sctp_inqueue_init(&ep->base.inqueue); + + /* Set its top-half handler */ + sctp_inqueue_set_th_handler(&ep->base.inqueue, + (void (*)(void *))sctp_endpoint_bh_rcv, + ep); + + /* Initialize the bind addr area */ + sctp_bind_addr_init(&ep->base.bind_addr, 0); + ep->base.addr_lock = RW_LOCK_UNLOCKED; + + /* Remember who we are attached to. */ + ep->base.sk = sk; + sock_hold(ep->base.sk); + + /* This pointer is useful to access the default protocol parameter + * values. + */ + ep->proto = proto; + + /* Create the lists of associations. */ + INIT_LIST_HEAD(&ep->asocs); + + /* Set up the base timeout information. */ + ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] + = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] + = SCTP_DEFAULT_TIMEOUT_T1_INIT; + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] + = sctp_sk(sk)->rtoinfo.srto_initial; + ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] + = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] + = SCTP_DEFAULT_TIMEOUT_SACK; + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] + = sctp_sk(sk)->autoclose * HZ; + ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] + = SCTP_DEFAULT_TIMEOUT_PMTU_RAISE; + + /* Set up the default send/receive buffer space. */ + /* FIXME - Should the min and max window size be configurable + * sysctl parameters as opposed to be constants? + */ + sk->rcvbuf = SCTP_DEFAULT_MAXWINDOW; + sk->sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; + + /* Use SCTP specific send buffer space queues. */ + sk->write_space = sctp_write_space; + sk->use_write_queue = 1; + + /* Initialize the secret key used with cookie. */ + get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); + ep->last_key = ep->current_key = 0; + ep->key_changed_at = jiffies; + + ep->debug_name = "unnamedEndpoint"; + + return ep; + +} /* sctp_endpoint_init() */ + + +/* Add an association to an endpoint. + */ +void +sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +{ + /* Now just add it to our list of asocs */ + list_add_tail(&asoc->asocs, &ep->asocs); + +} /* sctp_endpoint_add_asoc() */ + + +/* Free the endpoint structure. Delay cleanup until + * all users have released their reference count on this structure. + */ +void +sctp_endpoint_free(sctp_endpoint_t *ep) +{ + ep->base.dead = 1; + sctp_endpoint_put(ep); + +} /* sctp_free_endpoint() */ + +/* Final destructor for endpoint. */ +void sctp_endpoint_destroy(sctp_endpoint_t *ep) +{ + SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); + + /* Unlink this endpoint, so we can't find it again! */ + sctp_unhash_endpoint(ep); + + /* Cleanup the inqueue. */ + sctp_inqueue_free(&ep->base.inqueue); + + sctp_bind_addr_free(&ep->base.bind_addr); + + /* Remove and free the port */ + if (ep->base.sk->prev != NULL) { + sctp_put_port(ep->base.sk); + } + + /* Give up our hold on the sock. */ + if (ep->base.sk) { + sock_put(ep->base.sk); + } + + /* Finally, free up our memory. */ + if (ep->base.malloced) { + kfree(ep); + SCTP_DBG_OBJCNT_DEC(ep); + } + return; + +} /* sctp_endpoint_destroy() */ + + +/* Hold a reference to an endpoint. */ +void sctp_endpoint_hold(sctp_endpoint_t *ep) +{ + atomic_inc(&ep->base.refcnt); + +} /* sctp_endpoint_hold() */ + + +/* Release a reference to an endpoint and clean up if there are + * no more references. + */ +void sctp_endpoint_put(sctp_endpoint_t *ep) +{ + if (atomic_dec_and_test(&ep->base.refcnt)) { + sctp_endpoint_destroy(ep); + } + +} /* sctp_endpoint_put() */ + + +/* Is this the endpoint we are looking for? */ +sctp_endpoint_t * +sctp_endpoint_is_match(sctp_endpoint_t *ep, const sockaddr_storage_t *laddr) +{ + sctp_endpoint_t *retval; + + sctp_read_lock(&ep->base.addr_lock); + if (ep->base.bind_addr.port == laddr->v4.sin_port) { + if (sctp_bind_addr_has_addr(&ep->base.bind_addr, laddr)) { + retval = ep; + goto out; + } + } + + retval = NULL; + +out: + sctp_read_unlock(&ep->base.addr_lock); + return retval; + +} /* sctp_endpoint_is_match() */ + +/* Find the association that goes with this chunk. + * We do a linear search of the associations for this endpoint. + * We return the matching transport address too. + */ + + +sctp_association_t * +__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) +{ + int rport; + sctp_association_t *asoc; + list_t *pos; + + rport = paddr->v4.sin_port; + + list_for_each(pos, &endpoint->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + if (rport == asoc->peer.port) { + + sctp_read_lock(&asoc->base.addr_lock); + *transport = sctp_assoc_lookup_paddr(asoc, paddr); + sctp_read_unlock(&asoc->base.addr_lock); + + if (*transport) { + return asoc; + } + } + } /* for (all associations on endpoint) */ + + *transport = NULL; + return NULL; + +} /* __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, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) +{ + sctp_association_t *asoc; + + sctp_local_bh_disable(); + asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); + sctp_local_bh_enable(); + + return asoc; + +} /* sctp_endpoint_lookup_assoc() */ + + + +/* Do delayed input processing. This is scheduled by sctp_rcv(). + * This may be called on BH or task time. + */ +static void +sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +{ + sctp_association_t *asoc; + struct sock *sk; + sctp_transport_t *transport; + sctp_chunk_t *chunk; + sctp_inqueue_t *inqueue; + sctp_subtype_t subtype; + sctp_state_t state; + int error = 0; + + if (ep->base.dead) { goto out; } + + asoc = NULL; + inqueue = &ep->base.inqueue; + sk = ep->base.sk; + + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + subtype.chunk = chunk->chunk_hdr->type; + + /* We might have grown an association since last we + * looked, so try again. + * + * This happens when we've just processed our + * COOKIE-ECHO chunk. + */ + if (NULL == chunk->asoc) { + asoc = sctp_endpoint_lookup_assoc(ep, + sctp_source(chunk), + &transport); + chunk->asoc = asoc; + chunk->transport = transport; + } + + state = asoc ? asoc->state : SCTP_STATE_CLOSED; + + /* Remember where the last DATA chunk came from so we + * know where to send the SACK. + */ + if ( asoc != NULL && sctp_chunk_is_data(chunk) ) { + asoc->peer.last_data_from = + chunk->transport; + } + + if (chunk->transport) { + chunk->transport->last_time_heard = jiffies; + } + + + /* FIX ME We really would rather NOT have to use + * GFP_ATOMIC. + */ + error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state, + ep, asoc, chunk, GFP_ATOMIC); + + + if (error != 0) { goto err_out; } + + /* Check to see if the endpoint is freed in response to + * the incoming chunk. If so, get out of the while loop. + */ + if (NULL == sctp_sk(sk)->ep) { goto out; } + + } /* while (we have more chunks to receive) */ + +err_out: + /* Is this the right way to pass errors up to the ULP? */ + if (error) { + ep->base.sk->err = -error; + } +out: + return; + +} /* sctp_bh_rcv_ep() */ + + + + diff --git a/net/sctp/sctp_hashdriver.c b/net/sctp/sctp_hashdriver.c new file mode 100644 index 000000000000..f42a06ab8c85 --- /dev/null +++ b/net/sctp/sctp_hashdriver.c @@ -0,0 +1,135 @@ +/* SCTP reference Implementation Copyright (C) 1999 Cisco And Motorola + * + * This file origiantes from Randy Stewart's SCTP reference Implementation. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randy Stewart rstewar1@email.mot.com + * Ken Morneau kmorneau@cisco.com + * Qiaobing Xie qxie1@email.mot.com + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorperated into the next SCTP release. + * + * There are still LOTS of bugs in this code... I always run on the motto + * "it is a wonder any code ever works :)" + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_hashdriver.c,v 1.2 2002/07/19 22:00:33 jgrimm Exp $"; + +#include +#include +#include +#include + + +/* SCTP Main driver. + passing a two pointers and two lengths, + returning a digest pointer filled. The md5 code + was taken directly from the RFC (2104) so to understand it + you may want to go look at the RFC referenced in the + SCTP spec. We did modify this code to either user OUR + implementation of SLA1 or the MD5 that comes from its + RFC. SLA1 may have IPR issues so you need to check in + to this if you wish to use it... Or at least that is + what the FIP-180.1 web page says. + */ + +void +sctp_hash_digest(const char *key, const int in_key_len, + const char *text, const int text_len, + uint8_t *digest) +{ + int key_len = in_key_len; + unsigned long *p; + struct SLA_1_Context context; + + uint8_t k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + uint8_t k_opad[65]; /* outer padding - + * key XORd with opad + */ + uint8_t tk[20]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + struct SLA_1_Context tctx; + SLA1_Init(&tctx); + SLA1_Process(&tctx, key, key_len); + SLA1_Final(&tctx,tk); + key = tk; + key_len = 20; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset( k_ipad, 0, sizeof k_ipad); + memset( k_opad, 0, sizeof k_opad); + memcpy( k_ipad, key, key_len); + memcpy( k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* + * perform inner hash + */ + SLA1_Init(&context); /* init context for 1st + * pass + */ + SLA1_Process(&context, k_ipad, 64); /* start with inner pad */ + SLA1_Process(&context, text, text_len); /* then text of datagram */ + SLA1_Final(&context,digest); /* finish up 1st pass */ + + /* + * perform outer hash + */ + + SLA1_Init(&context); /* init context for 2nd + * pass + */ + SLA1_Process(&context, k_opad, 64); /* start with outer pad */ + SLA1_Process(&context, digest, 20); /* then results of 1st + * hash + */ + SLA1_Final(&context, digest); /* finish up 2nd pass */ + + p = (unsigned long *)digest; +} + diff --git a/net/sctp/sctp_input.c b/net/sctp/sctp_input.c new file mode 100644 index 000000000000..996e81abd85b --- /dev/null +++ b/net/sctp/sctp_input.c @@ -0,0 +1,725 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_input.c,v 1.24 2002/07/24 12:26:20 jgrimm Exp $ + * + * These functions handle all input from the IP layer into SCTP. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Xingang Guo + * Jon Grimm + * Hui Huang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_input.c,v 1.24 2002/07/24 12:26:20 jgrimm Exp $"; + +#include +#include +#include /* For struct list_head */ +#include +#include +#include /* For struct timeval */ +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static inline int sctp_rcv_checksum(struct sk_buff *skb); +static int sctp_rcv_ootb(struct sk_buff *); +sctp_association_t * +__sctp_rcv_lookup(struct sk_buff *skb, const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp); +sctp_endpoint_t * +__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); + + +/* Initialize a sockaddr_storage from in incoming skb. + * FIXME: This belongs with AF specific sctp_func_t. --jgrimm + */ +static sockaddr_storage_t * +sctp_sockaddr_storage_init(sockaddr_storage_t *addr, const struct sk_buff *skb, + int is_saddr) +{ + sockaddr_storage_t *ret=NULL; + void *to, *saddr, *daddr; + uint16_t *port; + size_t len; + struct sctphdr *sh; + + switch (skb->nh.iph->version){ + case 4: + to = &addr->v4.sin_addr.s_addr; + port = &addr->v4.sin_port; + saddr = &skb->nh.iph->saddr; + daddr = &skb->nh.iph->daddr; + len = sizeof(struct in_addr); + addr->v4.sin_family = AF_INET; + break; + case 6: + SCTP_V6( + to = &addr->v6.sin6_addr; + port = &addr->v6.sin6_port; + saddr = &skb->nh.ipv6h->saddr; + daddr = &skb->nh.ipv6h->daddr; + len = sizeof(struct in6_addr); + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_flowinfo = 0; /* FIXME */ + addr->v6.sin6_scope_id = 0; /* FIXME */ + break; + ) + default: + goto out; + } + + sh = (struct sctphdr *)skb->h.raw; + + if (is_saddr) { + *port = ntohs(sh->source); + memcpy(to, saddr, len); + } else { + *port = ntohs(sh->dest); + memcpy(to, daddr, len); + } + + ret = addr; +out: + return ret; + +} /* sctp_sockaddr_storage_init() */ + +/* + * This is the routine which IP calls when receiving an SCTP packet. + */ +int +sctp_rcv(struct sk_buff *skb) +{ + struct sock *sk; + sctp_association_t *asoc; + sctp_endpoint_t *ep = NULL; + sctp_endpoint_common_t *rcvr; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk; + struct sctphdr *sh; + sockaddr_storage_t src; + sockaddr_storage_t dest; + int ret = 0; + + if (skb->pkt_type!=PACKET_HOST) { + goto discard_it; + } + + sh = (struct sctphdr *)skb->h.raw; + + /* Pull up the IP and SCTP headers. */ + __skb_pull(skb, skb->h.raw - skb->data); + + if (skb->len < sizeof(struct sctphdr)) { + goto bad_packet; + } + + if (sctp_rcv_checksum(skb) < 0) { + goto bad_packet; + } + + skb_pull(skb, sizeof(struct sctphdr)); + + sctp_sockaddr_storage_init(&src, skb, 1); + sctp_sockaddr_storage_init(&dest, skb, 0); + + /* If the packet is to or from a non-unicast address, + * silently discard the packet. + * + * This is not clearly defined in the RFC except in section + * 8.4 - OOTB handling. However, based on the book "Stream Control + * Transmission Protocol" 2.1, "It is important to note that the + * IP address of an SCTP transport address must be a routable + * unicast address. In other words, IP multicast addresses and + * IP broadcast addresses cannot be used in an SCTP transport + * address." + */ + if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) { + goto discard_it; + } + + asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); + + /* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets. + * An SCTP packet is called an "out of the blue" (OOTB) + * packet if it is correctly formed, i.e., passed the + * receiver's checksum check, but the receiver is not + * able to identify the association to which this + * packet belongs. + */ + if (!asoc) { + ep = __sctp_rcv_lookup_endpoint(&dest); + if (sctp_rcv_ootb(skb)) { + goto discard_release; + } + } + + /* Retrieve the common input handling substructure. */ + rcvr = asoc ? &asoc->base : &ep->base; + sk = rcvr->sk; + + if (!ipsec_sk_policy(sk, skb)) { + goto discard_release; + } + + /* Create an SCTP packet structure. */ + chunk = sctp_chunkify(skb, asoc, sk); + + if (!chunk) { + ret = -ENOMEM; + goto discard_release; + } + + /* Remember what endpoint is to handle this packet. */ + chunk->rcvr = rcvr; + + /* Remember the SCTP header. */ + chunk->sctp_hdr = sh; + + /* Set the source address. */ + sctp_init_source(chunk); + + /* Remember where we came from. */ + chunk->transport = transport; + + /* Acquire access to the sock lock. Note: We are safe from other + * bottom halves on this lock, but a user may be in the lock too, + * so check if it is busy. + */ + sctp_bh_lock_sock(sk); + + if (__sctp_sock_busy(sk)) { + sk_add_backlog(sk, (struct sk_buff *)chunk); + } else { + sctp_backlog_rcv(sk, (struct sk_buff *)chunk); + } + + /* Release the sock and any reference counts we took in the + * lookup calls. + */ + sctp_bh_unlock_sock(sk); + if (asoc) { + sctp_association_put(asoc); + } else { + sctp_endpoint_put(ep); + } + sock_put(sk); + return ret; + +bad_packet: +#if 0 /* FIXME */ + SCTP_INC_STATS(SctpInErrs); +#endif /* FIXME*/ + +discard_it: + kfree_skb(skb); + return ret; + +discard_release: + /* Release any structures we may be holding. */ + if (asoc) { + sock_put(asoc->base.sk); + sctp_association_put(asoc); + } else { + sock_put(ep->base.sk); + sctp_endpoint_put(ep); + } + + goto discard_it; + +} /* sctp_rcv() */ + +/* Handle second half of inbound skb processing. If the sock was busy, + * we may have need to delay processing until later when the sock is + * released (on the backlog). If not busy, we call this routine + * directly from the bottom half. + */ +int +sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) +{ + sctp_chunk_t *chunk; + sctp_inqueue_t *inqueue; + + /* One day chunk will live inside the skb, but for + * now this works. + */ + chunk = (sctp_chunk_t *)skb; + inqueue = &chunk->rcvr->inqueue; + + sctp_push_inqueue(inqueue, chunk); + + return 0; + +} /* sctp_backlog_rcv() */ + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. If err < 0 then the socket should + * be closed and the error returned to the user. If err > 0 + * it's just the icmp type << 8 | icmp code. After adjustment + * header points to the first 8 bytes of the sctp header. We need + * to find the appropriate port. + * + * The locking strategy used here is very "optimistic". When + * someone else accesses the socket the ICMP is just dropped + * and for some paths there is no check at all. + * A more general error queue to queue errors for later handling + * is probably better. + * + */ +void +sctp_v4_err(struct sk_buff *skb, u32 info) +{ + /* This should probably involve a call to SCTPhandleICMP(). */ +} /* void sctp_v4_err(struct sk_buff *skb, u32 info) */ + + +/* Calculate the SCTP checksum of an SCTP packet. */ +static inline int +sctp_rcv_checksum(struct sk_buff *skb) +{ + uint32_t cmp,val; + struct sctphdr *sh; + + sh = (struct sctphdr *)skb->h.raw; + cmp = ntohl(sh->checksum); + val = count_crc((uint8_t *)sh, skb->len); + if (val != cmp) { + /* CRC failure, dump it. */ + return -1; + } + return 0; + +} /* sctp_rcv_checksum() */ + + + +/* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets. + * + * This function scans all the chunks in the OOTB packet to determine if + * the packet should be discarded right away. If a response might be needed + * for this packet, or, if further processing is possible, the packet will + * be queued to a proper inqueue for the next phase of handling. + * + * Output: + * Return 0 - If further processing is needed. + * Return 1 - If the packet can be discarded right away. + */ +int +sctp_rcv_ootb(struct sk_buff *skb) +{ + sctp_chunkhdr_t *ch; + uint8_t *ch_end; + + ch = (sctp_chunkhdr_t *)skb->data; + + /* Scan through all the chunks in the packet. */ + do { + ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); + + /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the + * receiver MUST silently discard the OOTB packet and take no + * further action. + */ + + if (SCTP_CID_ABORT == ch->type) { + goto discard; + } + + /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE + * chunk, the receiver should silently discard the packet + * and take no further action. + */ + + if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE) { + 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) { + goto discard; + } + + if (ch->type == SCTP_CID_ERROR) { + /* FIXME - Need to check the "Stale cookie" ERROR. */ + goto discard; + } + + ch = (sctp_chunkhdr_t *)ch_end; + + } while (ch_end < skb->tail); + + return 0; + +discard: + return 1; + +} /* sctp_rcv_ootb() */ + + +/* Insert endpoint into the hash table. */ +void __sctp_hash_endpoint(sctp_endpoint_t *ep) +{ + sctp_endpoint_common_t **epp; + sctp_endpoint_common_t *epb; + sctp_hashbucket_t *head; + + epb = &ep->base; + + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); + head = &sctp_proto.ep_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + epp = &head->chain; + epb->next = *epp; + if (epb->next) { + (*epp)->pprev = &epb->next; + } + *epp = epb; + epb->pprev = epp; + sctp_write_unlock(&head->lock); + +} /* __sctp_hash_endpoint() */ + +/* Add an endpoint to the hash. Local BH-safe. */ +void sctp_hash_endpoint(sctp_endpoint_t *ep) +{ + sctp_local_bh_disable(); + __sctp_hash_endpoint(ep); + sctp_local_bh_enable(); + +} /* __sctp_hash_endpoint() */ + + +/* Remove endpoint from the hash table. */ +void __sctp_unhash_endpoint(sctp_endpoint_t *ep) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + + epb = &ep->base; + + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); + + head = &sctp_proto.ep_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + + if (epb->pprev) { + if (epb->next) { + epb->next->pprev = epb->pprev; + } + *epb->pprev = epb->next; + epb->pprev = NULL; + } + + sctp_write_unlock(&head->lock); + +} /* __sctp_unhash_endpoint() */ + +/* Remove endpoint from the hash. Local BH-safe. */ +void sctp_unhash_endpoint(sctp_endpoint_t *ep) +{ + sctp_local_bh_disable(); + __sctp_unhash_endpoint(ep); + sctp_local_bh_enable(); + +} /* sctp_unhash_endpoint() */ + + +/* Look up an endpoint. */ +sctp_endpoint_t * +__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + sctp_endpoint_t *ep; + int hash; + + hash = sctp_ep_hashfn(laddr->v4.sin_port); + head = &sctp_proto.ep_hashbucket[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + ep = sctp_ep(epb); + if (sctp_endpoint_is_match(ep, laddr)) { goto hit; } + } + + ep = sctp_sk((sctp_get_ctl_sock()))->ep; + epb = &ep->base; + +hit: + sctp_endpoint_hold(ep); + sock_hold(epb->sk); + read_unlock(&head->lock); + return ep; + +} /* __sctp_rcv_lookup_endpoint() */ + + +/* Add an association to the hash. Local BH-safe. */ +void sctp_hash_established(sctp_association_t *asoc) +{ + sctp_local_bh_disable(); + __sctp_hash_established(asoc); + sctp_local_bh_enable(); + +} /* sctp_hash_association() */ + +/* Insert association into the hash table. */ +void __sctp_hash_established(sctp_association_t *asoc) +{ + sctp_endpoint_common_t **epp; + sctp_endpoint_common_t *epb; + sctp_hashbucket_t *head; + + epb = &asoc->base; + + /* Calculate which chain this entry will belong to. */ + epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); + + head = &sctp_proto.assoc_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + epp = &head->chain; + epb->next = *epp; + if (epb->next) { + (*epp)->pprev = &epb->next; + } + *epp = epb; + epb->pprev = epp; + sctp_write_unlock(&head->lock); + +} /* __sctp_hash_established() */ + +/* Remove association from the hash table. Local BH-safe. */ +void sctp_unhash_established(sctp_association_t *asoc) +{ + sctp_local_bh_disable(); + __sctp_unhash_established(asoc); + sctp_local_bh_enable(); + +} /* sctp_unhash_established() */ + +/* Remove association from the hash table. */ +void __sctp_unhash_established(sctp_association_t *asoc) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + + epb = &asoc->base; + + epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, + asoc->peer.port); + + head = &sctp_proto.assoc_hashbucket[epb->hashent]; + + sctp_write_lock(&head->lock); + + if (epb->pprev) { + if (epb->next) { + epb->next->pprev = epb->pprev; + } + *epb->pprev = epb->next; + epb->pprev = NULL; + } + + sctp_write_unlock(&head->lock); + +} /* __sctp_unhash_established() */ + + +/* Look up an association. */ +sctp_association_t * +__sctp_rcv_lookup_association(const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp) +{ + sctp_hashbucket_t *head; + sctp_endpoint_common_t *epb; + sctp_association_t *asoc; + sctp_transport_t *transport; + int hash; + + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ + + hash = sctp_assoc_hashfn(laddr->v4.sin_port, paddr->v4.sin_port); + head = &sctp_proto.assoc_hashbucket[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + asoc = sctp_assoc(epb); + transport = sctp_assoc_is_match(asoc, laddr, paddr); + if (transport) { goto hit; } + } + + read_unlock(&head->lock); + + return NULL; + +hit: + *transportp = transport; + sctp_association_hold(asoc); + sock_hold(epb->sk); + read_unlock(&head->lock); + return asoc; + +} /* __sctp_rcv_lookup_association() */ + +/* + * SCTP Implementors Guide, 2.18 Handling of address + * parameters within the INIT or INIT-ACK. + * + * D) When searching for a matching TCB upon reception of an INIT + * or INIT-ACK chunk the receiver SHOULD use not only the + * source address of the packet (containing the INIT or + * INIT-ACK) but the receiver SHOULD also use all valid + * address parameters contained within the chunk. + * + * 2.18.3 Solution description + * + * This new text clearly specifies to an implementor the need + * to look within the INIT or INIT-ACK. Any implementation that + * does not do this, may not be able to establish associations + * in certain circumstances. + * + */ +static sctp_association_t * +__sctp_rcv_initack_lookup(struct sk_buff *skb, + const sockaddr_storage_t *laddr, + sctp_transport_t **transportp) +{ + sctp_association_t *asoc; + sockaddr_storage_t addr; + sockaddr_storage_t *paddr = &addr; + struct sctphdr *sh = (struct sctphdr *)skb->h.raw; + sctp_chunkhdr_t *ch; + uint8_t *ch_end, *data; + sctpParam_t parm; + + ch = (sctp_chunkhdr_t *)skb->data; + + ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); + + if (SCTP_CID_INIT_ACK != ch->type) { + return NULL; + } + + /* + * This code will NOT touch anything inside the chunk--it is + * strictly READ-ONLY. + * + * RFC 2960 3 SCTP packet Format + * + * Multiple chunks can be bundled into one SCTP packet up to + * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN + * COMPLETE chunks. These chunks MUST NOT be bundled with any + * other chunk in a packet. See Section 6.10 for more details + * on chunk bundling. + */ + + /* Find the start of the TLVs and the end of the chunk. This is + * the region we search for address parameters. + */ + + data = skb->data + sizeof(sctp_init_chunk_t); + + /* See sctp_process_init() for how to go thru TLVs. */ + while ( data < ch_end ) { + + parm.v = data; + + if (parm.p->length == 0) { break; } + + data += WORD_ROUND(ntohs(parm.p->length)); + + /* Note: Ignoring hostname addresses. */ + if((SCTP_PARAM_IPV4_ADDRESS != parm.p->type) + && (SCTP_PARAM_IPV6_ADDRESS != parm.p->type)) { + continue; + } + + sctp_param2sockaddr(paddr, parm, ntohs(sh->source)); + + asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); + if (asoc) { return asoc; } + + } /* while (not at end of chunk) */ + + return NULL; + +} /* __sctp_rcv_initack_lookup() */ + +/* Lookup an association for an inbound skb. */ +sctp_association_t * +__sctp_rcv_lookup(struct sk_buff *skb, const sockaddr_storage_t *paddr, + const sockaddr_storage_t *laddr, + sctp_transport_t **transportp) +{ + sctp_association_t *asoc; + + asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); + + /* Further lookup for INIT-ACK packet. + * SCTP Implementors Guide, 2.18 Handling of address + * parameters within the INIT or INIT-ACK. + */ + if (!asoc) { + asoc = __sctp_rcv_initack_lookup(skb, laddr, transportp); + } + + return asoc; + +} /* __sctp_rcv_lookup() */ + + + + + diff --git a/net/sctp/sctp_inqueue.c b/net/sctp/sctp_inqueue.c new file mode 100644 index 000000000000..70a46f650bf2 --- /dev/null +++ b/net/sctp/sctp_inqueue.c @@ -0,0 +1,219 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2002 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_inqueue.c,v 1.10 2002/05/20 22:05:54 jgrimm Exp $ + * + * These functions are the methods for accessing the SCTP inqueue. + * + * An SCTP inqueue is a queue into which you push SCTP packets + * (which might be bundles or fragments of chunks) and out of which you + * pop SCTP whole chunks. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_inqueue.c,v 1.10 2002/05/20 22:05:54 jgrimm Exp $"; + +#include +#include +#include + +/* Initialize an SCTP_inqueue. */ +void +sctp_inqueue_init(sctp_inqueue_t *queue) +{ + skb_queue_head_init(&queue->in); + queue->in_progress = NULL; + + /* Create a task for delivering data. */ + INIT_LIST_HEAD(&queue->immediate.list); + queue->immediate.sync = 0; + queue->immediate.routine = NULL; + queue->immediate.data = NULL; + + queue->malloced = 0; + +} /* sctp_inqueue_init() */ + +/* Create an initialized SCTP_inqueue. */ +sctp_inqueue_t * +sctp_inqueue_new() +{ + sctp_inqueue_t *retval; + + retval = t_new(sctp_inqueue_t, GFP_ATOMIC); + if (NULL == retval) { return(NULL); } + + sctp_inqueue_init(retval); + retval->malloced = 1; + + return(retval); + +} /* sctp_inqueue_new() */ + +/* Release the memory associated with an SCTP inqueue. */ +void +sctp_inqueue_free(sctp_inqueue_t *queue) +{ + sctp_chunk_t *chunk; + + /* Empty the queue. */ + while ((chunk=(sctp_chunk_t *)skb_dequeue(&queue->in))!=NULL) { + sctp_free_chunk(chunk); + } + /* If there is a packet which is currently being worked on, + * free it as well. + */ + if (queue->in_progress) { + sctp_free_chunk(queue->in_progress); + } + + if (queue->malloced) { + /* Dump the master memory segment. */ + kfree(queue); + } + +} /* sctp_inqueue_free() */ + + + +/* Put a new packet in an SCTP inqueue. + * We assume that packet->sctp_hdr is set and in host byte order. + */ +void +sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) +{ + /* Directly call the packet handling routine. */ + /* We are now calling this either from the soft interrupt + * or from the backlog processing. + * Eventually, we should clean up inqueue to not rely + * on the BH related data structures. + */ + skb_queue_tail(&(q->in), (struct sk_buff *)packet); + q->immediate.routine(q->immediate.data); + +} /* sctp_push_inqueue() */ + +/* Extract a chunk from an SCTP inqueue. + * + * WARNING: If you need to put the chunk on another queue, you need to + * make a shallow copy (clone) of it. + */ +sctp_chunk_t * +sctp_pop_inqueue(sctp_inqueue_t *queue) +{ + sctp_chunk_t *chunk; + sctp_chunkhdr_t *ch = NULL; + + /* The assumption is that we are safe to process the chunks + * at this time. + */ + + if (NULL != (chunk = queue->in_progress)) { + /* There is a packet that we have been working on. + * Any post processing work to do before we move on? + */ + if (chunk->singleton || chunk->end_of_packet + || chunk->pdiscard) { + sctp_free_chunk(chunk); + chunk = queue->in_progress = NULL; + } else { + /* Nothing to do. Next chunk in the packet, please. */ + ch = (sctp_chunkhdr_t *)chunk->chunk_end; + + /* Force chunk->skb->data to chunk->chunk_end. */ + skb_pull(chunk->skb, + chunk->chunk_end - chunk->skb->data); + } + } + + /* Do we need to take the next packet out of the queue to process? */ + if (NULL == chunk) { + + /* Is the queue empty? */ + if (skb_queue_empty(&queue->in)) { + return(NULL); + } + + chunk = queue->in_progress = + (sctp_chunk_t *)skb_dequeue(&queue->in); + + /* This is the first chunk in the packet. */ + chunk->singleton = 1; + ch = (sctp_chunkhdr_t *) chunk->skb->data; + } + + chunk->chunk_hdr = ch; + chunk->chunk_end = ((uint8_t *)ch) + + WORD_ROUND(ntohs(ch->length)); + skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + chunk->subh.v = NULL; /* Subheader is no longer valid. */ + + if (chunk->chunk_end < chunk->skb->tail) { + /* This is not a singleton */ + chunk->singleton = 0; + } else { + /* We are at the end of the packet, so mark the chunk + * in case we need to send a SACK. + */ + chunk->end_of_packet = 1; + } + + + SCTP_DEBUG_PRINTK("+++sctp_pop_inqueue+++ chunk %p[%s]," + " length %d, skb->len %d\n",chunk, + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), + ntohs(chunk->chunk_hdr->length), chunk->skb->len); + return(chunk); + +} /* sctp_pop_inqueue() */ + +/* Set a top-half handler. + * + * Originally, we the top-half handler was scheduled as a BH. We now + * call the handler directly in sctp_push_inqueue() at a time that + * we know we are lock safe. + * The intent is that this routine will pull stuff out of the + * inqueue and process it. + */ +void +sctp_inqueue_set_th_handler(sctp_inqueue_t *q, + void (*callback)(void *), void *arg) +{ + q->immediate.routine = callback; + q->immediate.data = arg; + +} /* sctp_inqueue_set_th_handler() */ + diff --git a/net/sctp/sctp_ipv6.c b/net/sctp/sctp_ipv6.c new file mode 100644 index 000000000000..e2c382e89823 --- /dev/null +++ b/net/sctp/sctp_ipv6.c @@ -0,0 +1,288 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * Copyright (c) 2002 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ipv6.c,v 1.12 2002/08/16 19:30:49 jgrimm Exp $ + * + * SCTP over IPv6. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Le Yanqun + * Hui Huang + * La Monte H.P. Yarroll + * Sridhar Samudrala + * Jon Grimm + * + * Based on: + * linux/net/ipv6/tcp_ipv6.c + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ipv6.c,v 1.12 2002/08/16 19:30:49 jgrimm Exp $"; + +#define __NO_VERSION__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* FIXME: Cleanup so we don't need TEST_FRAME here. */ +#ifndef TEST_FRAME +/* FIXME: Comments. */ +static inline void sctp_v6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + /* BUG. WRITE ME. */ +}/* sctp_v6_err */ + +/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ +static inline int +sctp_v6_xmit(struct sk_buff *skb) +{ + struct sock *sk = skb->sk; + struct ipv6_pinfo *np = inet6_sk(sk); + struct flowi fl; + struct dst_entry *dst; + struct in6_addr saddr; + int err = 0; + + fl.proto = sk->protocol; + fl.fl6_dst = &np->daddr; + fl.fl6_src = NULL; + + fl.fl6_flowlabel = np->flow_label; + IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); + fl.oif = sk->bound_dev_if; + fl.uli_u.ports.sport = inet_sk(sk)->sport; + fl.uli_u.ports.dport = inet_sk(sk)->dport; + + if (np->opt && np->opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; + fl.nl_u.ip6_u.daddr = rt0->addr; + } + + dst = __sk_dst_check(sk, np->dst_cookie); + + if (dst == NULL) { + dst = ip6_route_output(sk, &fl); + + if (dst->error) { + sk->err_soft = -dst->error; + dst_release(dst); + return -sk->err_soft; + } + ip6_dst_store(sk, dst, NULL); + } + + skb->dst = dst_clone(dst); + + /* FIXME: This is all temporary until real source address + * selection is done. + */ + if (ipv6_addr_any(&np->saddr)) { + err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); + + if (err) { + printk(KERN_ERR "sctp_v6_xmit: no saddr available\n"); + } + + /* FIXME: This is a workaround until we get + * real source address selection done. This is here + * to disallow loopback when the scoping rules have + * not bound loopback to the endpoint. + */ + if (sctp_ipv6_addr_type(&saddr) + & IPV6_ADDR_LOOPBACK) { + if (!(sctp_ipv6_addr_type(&np->daddr) & + IPV6_ADDR_LOOPBACK)) { + + ipv6_addr_copy(&saddr, &np->daddr); + } + } + + fl.fl6_src = &saddr; + } else { + fl.fl6_src = &np->saddr; + } + + /* Restore final destination back after routing done */ + fl.nl_u.ip6_u.daddr = &np->daddr; + + + + return ip6_xmit(sk, skb, &fl, np->opt); + +} /* sctp_v6_xmit */ +#endif /* TEST_FRAME */ + +/* Returns the mtu for the given v6 destination address. */ +int +sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) +{ + int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; + + + struct flowi fl; + struct dst_entry *dst; + + fl.proto = 0; + fl.fl6_dst = (struct in6_addr *)&address->v6.sin6_addr; + fl.fl6_src = NULL; + fl.fl6_flowlabel = 0; + fl.oif = 0; + fl.uli_u.ports.sport = 0; + fl.uli_u.ports.dport = 0; + + dst = ip6_route_output(NULL, &fl); + if (dst) { + dst_mtu = dst->pmtu; + SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " + "ip6_route_output: dev:%s pmtu:%d\n", + dst->dev->name, dst_mtu); + dst_release(dst); + } else { + SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " + "ip6_route_output failed, returning " + "%d as dst_mtu\n", dst_mtu); + } + + return (dst_mtu); + +} /* sctp_v6_get_dst_mtu() */ + + +static struct proto_ops inet6_seqpacket_ops = { + .family = PF_INET6, + .release = inet6_release, + .bind = inet6_bind, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = inet_accept, + .getname = inet6_getname, + .poll = sctp_poll, + .ioctl = inet6_ioctl, + .listen = sctp_inet_listen, + .shutdown = inet_shutdown, + .setsockopt = inet_setsockopt, + .getsockopt = inet_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, + .mmap = sock_no_mmap, +}; + +static struct inet_protosw sctpv6_protosw = +{ + .type = SOCK_SEQPACKET, + .protocol = IPPROTO_SCTP, + .prot = &sctp_prot, + .ops = &inet6_seqpacket_ops, + .capability = -1, + .no_check = 0, + .flags = SCTP_PROTOSW_FLAG +}; + +static struct inet6_protocol sctpv6_protocol = +{ + .handler = sctp_rcv, + .err_handler = sctp_v6_err, + .next = NULL, + .protocol = IPPROTO_SCTP, + .copy = 0, + .data = NULL, + .name = "SCTPv6" +}; + +static sctp_func_t sctp_ipv6_specific = { + .queue_xmit = sctp_v6_xmit, + .setsockopt = ipv6_setsockopt, + .getsockopt = ipv6_getsockopt, + .get_dst_mtu = sctp_v6_get_dst_mtu, + .net_header_len = sizeof(struct ipv6hdr), + .sockaddr_len = sizeof(struct sockaddr_in6), + .sa_family = AF_INET6, +}; + + +/* Initialize IPv6 support and register with inet6 stack. */ +int sctp_v6_init(void) +{ + + /* Add SCTPv6 to inetsw6 linked list. */ + inet6_register_protosw(&sctpv6_protosw); + + /* Register inet6 protocol. */ + inet6_add_protocol(&sctpv6_protocol); + + /* Fill in address family info. */ + INIT_LIST_HEAD(&sctp_ipv6_specific.list); + list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); + + return 0; + +} /* sctp_v6_init() */ + +/* IPv6 specific exit support. */ +void sctp_v6_exit(void) +{ + list_del(&sctp_ipv6_specific.list); + inet6_del_protocol(&sctpv6_protocol); + inet6_unregister_protosw(&sctpv6_protosw); + +} /* sctp_v6_exit() */ diff --git a/net/sctp/sctp_objcnt.c b/net/sctp/sctp_objcnt.c new file mode 100644 index 000000000000..d3e9e6d2b2c2 --- /dev/null +++ b/net/sctp/sctp_objcnt.c @@ -0,0 +1,142 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_objcnt.c,v 1.5 2002/07/12 14:50:25 jgrimm Exp $ + * + * Support for memory object debugging. This allows one to monitor the + * object allocations/deallocations for types instrumented for this + * via the proc fs. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_objcnt.c,v 1.5 2002/07/12 14:50:25 jgrimm Exp $"; + +#include + +/* + * Global counters to count raw object allocation counts. + * To add new counters, choose a unique suffix for the variable + * name as the helper macros key off this suffix to make + * life easier for the programmer. + */ + +SCTP_DBG_OBJCNT(sock); +SCTP_DBG_OBJCNT(ep); +SCTP_DBG_OBJCNT(transport); +SCTP_DBG_OBJCNT(assoc); +SCTP_DBG_OBJCNT(bind_addr); +SCTP_DBG_OBJCNT(chunk); +SCTP_DBG_OBJCNT(addr); + +/* An array to make it easy to pretty print the debug information + * to the proc fs. + */ +sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { + SCTP_DBG_OBJCNT_ENTRY(sock), + SCTP_DBG_OBJCNT_ENTRY(ep), + SCTP_DBG_OBJCNT_ENTRY(assoc), + SCTP_DBG_OBJCNT_ENTRY(transport), + SCTP_DBG_OBJCNT_ENTRY(chunk), + SCTP_DBG_OBJCNT_ENTRY(bind_addr), + SCTP_DBG_OBJCNT_ENTRY(addr), +}; + +/* Callback from procfs to read out objcount information. + * Walk through the entries in the sctp_dbg_objcnt array, dumping + * the raw object counts for each monitored type. + * + * This code was modified from similar code in route.c + */ +static int +sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + int len = 0; + off_t pos = 0; + int entries; + int i; + char temp[128]; + + /* How many entries? */ + entries = sizeof(sctp_dbg_objcnt)/sizeof(sctp_dbg_objcnt[0]); + + /* Walk the entries and print out the debug information + * for proc fs. + */ + for(i = 0; i < entries; i++) { + pos += 128; + + /* Skip ahead. */ + if (pos <= offset) { + len = 0; + continue; + } + /* Print out each entry. */ + sprintf(temp, "%s: %d", + sctp_dbg_objcnt[i].label, + atomic_read(sctp_dbg_objcnt[i].counter)); + + sprintf(buffer + len, "%-127s\n", temp); + len += 128; + if (pos >= offset+length) { + goto done; + } + + } + +done: + *start = buffer + len - (pos - offset); + len = pos - offset; + if (len > length) + len = length; + + return len; + +} /* sctp_dbg_objcnt_read() */ + +/* Initialize the objcount in the proc filesystem. */ +void sctp_dbg_objcnt_init(void) +{ + create_proc_read_entry("sctp_dbg_objcnt", 0, proc_net_sctp, + sctp_dbg_objcnt_read, NULL); + +} /* sctp_dbg_objcnt_init() */ + +/* Cleanup the objcount entry in the proc filesystem. */ +void sctp_dbg_objcnt_exit(void) +{ + remove_proc_entry("sctp_dbg_objcount", proc_net_sctp); + +} /* sctp_dbg_objcnt_exit() */ + + diff --git a/net/sctp/sctp_output.c b/net/sctp/sctp_output.c new file mode 100644 index 000000000000..0d3ae24fd50f --- /dev/null +++ b/net/sctp/sctp_output.c @@ -0,0 +1,600 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_output.c,v 1.22 2002/07/12 14:39:05 jgrimm Exp $ + * + * These functions handle output processing. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_output.c,v 1.22 2002/07/12 14:39:05 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CONFIG_INET_ECN +#define CONFIG_INET_ECN +#endif /* CONFIG_INET_ECN */ +#include +#include + +#ifndef TEST_FRAME +#include +#endif /* TEST_FRAME (not defined) */ + +#include /* for sa_family_t */ +#include /* For NULL, etc... */ +#include + +#include +#include + + +/* Forward declarations for private helpers. */ +uint32_t count_crc(uint8_t *ptr, uint16_t count); +static void sctp_packet_reset(sctp_packet_t *packet); +static inline sctp_xmit_t +sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk); + +/* Config a packet. + * This appears to be a followup set of initializations.) + */ +sctp_packet_t * +sctp_packet_config(sctp_packet_t *packet, + uint32_t vtag, + int ecn_capable, + sctp_packet_phandler_t *prepend_handler) +{ + int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + + packet->vtag = vtag; + packet->ecn_capable = ecn_capable; + packet->get_prepend_chunk = prepend_handler; + packet->has_cookie_echo = 0; + + /* We might need to call the prepend_handler right away. */ + if (packet_empty) { + sctp_packet_reset(packet); + } + return(packet); + +} /* sctp_packet_config() */ + +/* Initialize the packet structure. */ +sctp_packet_t * +sctp_packet_init(sctp_packet_t *packet, + sctp_transport_t *transport, + uint16_t sport, + uint16_t dport) +{ + packet->transport = transport; + packet->source_port = sport; + packet->destination_port = dport; + skb_queue_head_init(&packet->chunks); + packet->vtag = 0; + packet->ecn_capable = 0; + packet->get_prepend_chunk = NULL; + packet->has_cookie_echo = 0; + + packet->malloced = 0; + + sctp_packet_reset(packet); + return packet; + +} /* sctp_packet_init() */ + + +/* Free a packet. */ +void +sctp_packet_free(sctp_packet_t *packet) +{ + sctp_chunk_t *chunk; + + while (NULL != + (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) { + sctp_free_chunk(chunk); + } + + if (packet->malloced) { + kfree(packet); + } + +} /* sctp_packet_free() */ + +/* This routine tries to append the chunk to the offered packet. If adding + * the chunk causes the packet to exceed the path MTU and COOKIE_ECHO chunk + * is not present in the packet, it transmits the input packet. + * Data can be bundled with a packet containing a COOKIE_ECHO chunk as long + * as it can fit in the packet, but any more data that does not fit in this + * packet can be sent only after receiving the COOKIE_ACK. + */ +sctp_xmit_t +sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval; + int error = 0; + + switch (retval = (sctp_packet_append_chunk(packet, chunk))) { + case SCTP_XMIT_PMTU_FULL: + if (!packet->has_cookie_echo) { + error = sctp_packet_transmit(packet); + if (error < 0) { + chunk->skb->sk->err = -error; + } + /* If we have an empty packet, then we can NOT ever + * return PMTU_FULL. + */ + retval = sctp_packet_append_chunk(packet, chunk); + } + break; + case SCTP_XMIT_MUST_FRAG: + case SCTP_XMIT_RWND_FULL: + case SCTP_XMIT_OK: + break; + } + + return(retval); + +} /* sctp_packet_transmit_chunk() */ + + +/* Append a chunk to the offered packet reporting back any inability to do + * so. + */ +sctp_xmit_t +sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval = SCTP_XMIT_OK; + uint16_t chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); + size_t psize = packet->size; + size_t pmtu; + int too_big; + + pmtu = ((packet->transport->asoc) ? + (packet->transport->asoc->pmtu) : + (packet->transport->pmtu)); + + too_big = (psize + chunk_len > pmtu); + + /* Decide if we need to fragment or resubmit later. */ + if (too_big) { + int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + + /* Both control chunks and data chunks with TSNs are + * non-fragmentable. + */ + int fragmentable = sctp_chunk_is_data(chunk) + && (!chunk->has_tsn); + if (packet_empty) { + if (fragmentable) { + retval = SCTP_XMIT_MUST_FRAG; + goto finish; + } else { + /* The packet is too big but we can + * not fragment it--we have to just + * transmit and rely on IP + * fragmentation. + */ + goto append; + } + + } else { /* !packet_empty */ + retval = SCTP_XMIT_PMTU_FULL; + goto finish; + } + + } else { + /* The chunk fits in the packet. */ + goto append; + } + +append: + /* We believe that this chunk is OK to add to the packet (as + * long as we have the cwnd for it). + */ + + /* DATA is a special case since we must examine both rwnd and cwnd + * before we send DATA. + */ + if (sctp_chunk_is_data(chunk)) { + retval = sctp_packet_append_data(packet, chunk); + if (SCTP_XMIT_OK != retval) { + goto finish; + } + } + else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) { + packet->has_cookie_echo = 1; + } + + + + /* It is OK to send this chunk. */ + skb_queue_tail(&packet->chunks, + (struct sk_buff *)chunk); + packet->size += chunk_len; + + +finish: + return(retval); + +} /* sctp_packet_append_chunk() */ + +/* All packets are sent to the network through this function from + * sctp_push_outqueue(). + * + * The return value is a normal kernel error return value. + */ +int +sctp_packet_transmit(sctp_packet_t *packet) +{ + sctp_transport_t *transport = packet->transport; + sctp_association_t *asoc = transport->asoc; + struct sctphdr *sh; + uint32_t crc32; + struct sk_buff *nskb; + sctp_chunk_t *chunk; + struct sock *sk; + int err = 0; + int padding; /* How much padding do we need? */ + uint8_t packet_has_data = 0; + + /* Do NOT generate a chunkless packet... */ + if (skb_queue_empty(&packet->chunks)) { + return(err); + } + + /* Set up convenience variables... */ + chunk = (sctp_chunk_t *)(packet->chunks.next); + sk = chunk->skb->sk; + + /* Allocate the new skb. */ + nskb = dev_alloc_skb(packet->size); + if (NULL == nskb) { + err = -ENOMEM; + goto out; + } + /* Make sure the outbound skb has enough header room reserved. */ + skb_reserve(nskb, SCTP_IP_OVERHEAD); + + /* Set the owning socket so that we know where to get the + * destination IP address. + */ + skb_set_owner_w(nskb, sk); + + /** + * 6.10 Bundling + * + * An endpoint bundles chunks by simply including multiple + * chunks in one outbound SCTP packet. ... + */ + /** + * 3.2 Chunk Field Descriptions + * + * The total length of a chunk (including Type, Length and + * Value fields) MUST be a multiple of 4 bytes. If the length + * of the chunk is not a multiple of 4 bytes, the sender MUST + * pad the chunk with all zero bytes and this padding is not + * included in the chunk length field. The sender should + * never pad with more than 3 bytes. + * + * [This whole comment explains WORD_ROUND() below.] + */ + SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); + while (NULL != (chunk = (sctp_chunk_t *) + skb_dequeue(&packet->chunks))) { + chunk->num_times_sent++; + chunk->sent_at = jiffies; + if (sctp_chunk_is_data(chunk)) { + + sctp_chunk_assign_tsn(chunk); + + /* 6.3.1 C4) When data is in flight and when allowed + * by rule C5, a new RTT measurement MUST be made each + * round trip. Furthermore, new RTT measurements + * SHOULD be made no more than once per round-trip + * for a given destination transport address. + */ + if ((1 == chunk->num_times_sent) + && (!transport->rto_pending)) { + chunk->rtt_in_progress = 1; + transport->rto_pending = 1; + } + packet_has_data = 1; + } + memcpy(skb_put(nskb, chunk->skb->len), + chunk->skb->data, chunk->skb->len); + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; + memset(skb_put(nskb, padding), 0, padding); + SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " + "%s %d\n", + "*** Chunk", chunk, + sctp_cname(SCTP_ST_CHUNK( + chunk->chunk_hdr->type)), + chunk->has_tsn ? "TSN" : "No TSN", + chunk->has_tsn ? + ntohl(chunk->subh.data_hdr->tsn) : 0, + "length", ntohs(chunk->chunk_hdr->length), + "chunk->skb->len", chunk->skb->len, + "num_times_sent", chunk->num_times_sent, + "rtt_in_progress", chunk->rtt_in_progress); + + /* + * If this is a control chunk, this is our last + * reference. Free data chunks after they've been + * acknowledged or have failed. + */ + if (!sctp_chunk_is_data(chunk)) { + sctp_free_chunk(chunk); + } + } + + /* Build the SCTP header. */ + sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); + sh->source = htons(packet->source_port); + sh->dest = htons(packet->destination_port); + + /* From 6.8 Adler-32 Checksum Calculation: + * After the packet is constructed (containing the SCTP common + * header and one or more control or DATA chunks), the + * transmitter shall: + * + * 1) Fill in the proper Verification Tag in the SCTP common + * header and initialize the checksum field to 0's. + */ + sh->vtag = htonl(packet->vtag); + sh->checksum = 0; + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * + * Note: Adler-32 is no longer applicable, as has been replaced + * by CRC32-C as described in . + */ + crc32 = count_crc((uint8_t *)sh, nskb->len); + + /* 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); + + switch (transport->ipaddr.sa.sa_family){ + case AF_INET: + inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr; + break; + case AF_INET6: + SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) + break; + default: + /* This is bogus address type, just bail. */ + break; + } + + /* IP layer ECN support + * From RFC 2481 + * "The ECN-Capable Transport (ECT) bit would be set by the + * data sender to indicate that the end-points of the + * transport protocol are ECN-capable." + * + * If ECN capable && negotiated && it makes sense for + * this packet to support it (e.g. post ECN negotiation) + * then lets set the ECT bit + * + * FIXME: Need to do something else for IPv6 + */ + + if (packet->ecn_capable) { + INET_ECN_xmit(nskb->sk); + } else { + INET_ECN_dontxmit(nskb->sk); + } + + + /* Set up the IP options. */ + /* BUG: not implemented + * For v4 this all lives somewhere in sk->opt... + */ + + /* Dump that on IP! */ + if ( asoc != NULL + && asoc->peer.last_sent_to != transport ) { + + /* Considering the multiple CPU scenario, this is a + * "correcter" place for last_sent_to. --xguo + */ + asoc->peer.last_sent_to = transport; + } + + /* Hey, before Linux changes, here's what we have to + * do to force IP routing to recognize the change of + * dest addr. --xguo + */ + if ( sk->dst_cache != NULL ) { sk->dst_cache->obsolete = 1; } + + if (packet_has_data) { + struct timer_list *timer; + unsigned long timeout; + + transport->last_time_used = jiffies; + + /* Restart the AUTOCLOSE timer when sending data. */ + if ((SCTP_STATE_ESTABLISHED == asoc->state) && + (asoc->autoclose)) { + timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; + timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; + + if (!mod_timer(timer, jiffies + timeout)) { + sctp_association_hold(asoc); + } + } + } + + SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", + nskb->len); + (*transport->af_specific->queue_xmit)(nskb); +out: + packet->size = SCTP_IP_OVERHEAD; + return err; + +} /* sctp_packet_transmit() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* + * This private function resets the packet to a fresh state. + */ +static void +sctp_packet_reset(sctp_packet_t *packet) +{ + sctp_chunk_t *chunk = NULL; + + packet->size = SCTP_IP_OVERHEAD; + + if ( NULL != packet->get_prepend_chunk ) { + chunk = packet->get_prepend_chunk(packet->transport->asoc); + } + + /* If there a is a prepend chunk stick it on the list before + * any other chunks get appended. + */ + if (chunk) { + sctp_packet_append_chunk(packet, chunk); + } +} /* sctp_packet_reset() */ + +/* This private function handles the specifics of appending DATA chunks. */ +static inline sctp_xmit_t +sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) +{ + sctp_xmit_t retval = SCTP_XMIT_OK; + size_t datasize, rwnd, inflight; + sctp_transport_t *transport = packet->transport; + uint32_t max_burst_bytes; + + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * A) At any given time, the data sender MUST NOT transmit new data to + * any destination transport address if its peer's rwnd indicates + * that the peer has no buffer space (i.e. rwnd is 0, see Section + * 6.2.1). However, regardless of the value of rwnd (including if it + * is 0), the data sender can always have one DATA chunk in flight to + * the receiver if allowed by cwnd (see rule B below). This rule + * allows the sender to probe for a change in rwnd that the sender + * missed due to the SACK having been lost in transit from the data + * receiver to the data sender. + */ + + + rwnd = transport->asoc->peer.rwnd; + inflight = transport->asoc->outqueue.outstanding_bytes; + + datasize = sctp_data_size(chunk); + + if (datasize > rwnd) { + if (inflight > 0){ + /* We have (at least) one data chunk in flight, + * so we can't fall back to rule 6.1 B). + */ + retval = SCTP_XMIT_RWND_FULL; + goto finish; + } + } + + + /* sctpimpguide-05 2.14.2 D) When the time comes for the sender to + * transmit new DATA chunks, the protocol parameter Max.Burst MUST + * first be applied to limit how many new DATA chunks may be sent. + * The limit is applied by adjusting cwnd as follows: + * if((flightsize + Max.Burst*MTU) < cwnd) + * cwnd = flightsize + Max.Burst*MTU + */ + max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu; + if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { + transport->cwnd = transport->flight_size + max_burst_bytes; + SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " + "transport: %p, cwnd: %d, " + "ssthresh: %d, flight_size: %d, " + "pba: %d\n", + __FUNCTION__, transport, + transport->cwnd, + transport->ssthresh, + transport->flight_size, + transport->partial_bytes_acked); + } + + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * B) At any given time, the sender MUST NOT transmit new data + * to a given transport address if it has cwnd or more bytes + * of data outstanding to that transport address. + */ + if (transport->flight_size >= transport->cwnd) { + retval = SCTP_XMIT_RWND_FULL; + goto finish; + } + + /* Keep track of how many bytes are in flight over this transport. */ + transport->flight_size += datasize; + + /* Keep track of how many bytes are in flight to the receiver. */ + transport->asoc->outqueue.outstanding_bytes += datasize; + + /* Update our view of the receiver's rwnd. */ + if (datasize < rwnd) { + rwnd -= datasize; + } else { + rwnd = 0; + } + + transport->asoc->peer.rwnd = rwnd; + +finish: + return(retval); + +} /* sctp_packet_append_data() */ + + + + diff --git a/net/sctp/sctp_outqueue.c b/net/sctp/sctp_outqueue.c new file mode 100644 index 000000000000..8fafc30cff32 --- /dev/null +++ b/net/sctp/sctp_outqueue.c @@ -0,0 +1,1515 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_outqueue.c,v 1.35 2002/08/05 02:58:05 jgrimm Exp $ + * + * These functions implement the outqueue class. The outqueue handles + * bundling and queueing of outgoing SCTP chunks. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Perry Melange + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_outqueue.c,v 1.35 2002/08/05 02:58:05 jgrimm Exp $"; + +#include +#include +#include /* For struct list_head */ +#include +#include +#include /* For skb_set_owner_w */ + +#include + +/* Declare internal functions here. */ +static int sctp_acked(sctp_sackhdr_t *sack, uint32_t tsn); +static void sctp_check_transmitted(sctp_outqueue_t *q, + struct list_head *transmitted_queue, + sctp_transport_t *transport, + sctp_sackhdr_t *sack); + + +/* Generate a new outqueue. */ +sctp_outqueue_t * +sctp_outqueue_new(sctp_association_t *asoc) +{ + sctp_outqueue_t *q; + + q = t_new(sctp_outqueue_t, GFP_KERNEL); + if (q) { + sctp_outqueue_init(asoc, q); + q->malloced = 1; + } + return q; + +} /* sctp_outqueue_new() */ + + +/* Initialize an existing SCTP_outqueue. This does the boring stuff. + * You still need to define handlers if you really want to DO + * something with this structure... + */ +void +sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q) +{ + q->asoc = asoc; + skb_queue_head_init(&q->out); + skb_queue_head_init(&q->control); + INIT_LIST_HEAD(&q->retransmit); + INIT_LIST_HEAD(&q->sacked); + + q->init_output = NULL; + q->config_output = NULL; + q->append_output = NULL; + q->build_output = NULL; + q->force_output = NULL; + + q->outstanding_bytes = 0; + q->empty = 1; + + q->malloced = 0; + +} /* sctp_outqueue_init() */ + + +/* Free the outqueue structure and any related pending chunks. + * FIXME: Add SEND_FAILED support. + */ +void +sctp_outqueue_teardown(sctp_outqueue_t *q) +{ + sctp_transport_t *transport; + list_t *lchunk, *pos; + sctp_chunk_t *chunk; + + /* Throw away unacknowledged chunks. */ + list_for_each(pos, &q->asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { + chunk = list_entry(lchunk, sctp_chunk_t, + transmitted_list); + sctp_free_chunk(chunk); + } + } /* For all transports. */ + + /* Throw away any leftover chunks. */ + while((chunk = (sctp_chunk_t *)skb_dequeue(&q->out))) { + sctp_free_chunk(chunk); + } + +} /* sctp_outqueue_teardown() */ + +/* Free the outqueue structure and any related pending chunks. */ +void +sctp_outqueue_free(sctp_outqueue_t *q) +{ + /* Throw away leftover chunks. */ + sctp_outqueue_teardown(q); + + /* If we were kmalloc()'d, free the memory. */ + if (q->malloced) { + kfree(q); + } + +} /* sctp_outqueue_free() */ + +/* Transmit any pending partial chunks. */ +void +sctp_force_outqueue(sctp_outqueue_t *q) +{ + /* Do we really need this? */ + /* BUG */ +} /* sctp_force_outqueue() */ + +/* Put a new chunk in an SCTP_outqueue. */ +int +sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) +{ + int error = 0; + + SCTP_DEBUG_PRINTK("sctp_push_outqueue(%p, %p[%s])\n", + q, chunk, chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + /* If it is data, queue it up, otherwise, send it + * immediately. + */ + if (SCTP_CID_DATA == chunk->chunk_hdr->type) { + /* Is it OK to queue data chunks? */ + /* From 9. Termination of Association + * + * When either endpoint performs a shutdown, the + * association on each peer will stop accepting new + * data from its user and only deliver data in queue + * at the time of sending or receiving the SHUTDOWN + * chunk. + */ + switch(q->asoc->state) { + case SCTP_STATE_EMPTY: + case SCTP_STATE_CLOSED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_SENT: + case SCTP_STATE_SHUTDOWN_RECEIVED: + case SCTP_STATE_SHUTDOWN_ACK_SENT: + /* Cannot send after transport endpoint shutdown */ + error = -ESHUTDOWN; + break; + default: + SCTP_DEBUG_PRINTK("outqueueing (%p, %p[%s])\n", + q, chunk, + chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK( + chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + skb_queue_tail(&q->out, + (struct sk_buff *)chunk); + q->empty = 0; + break; + } /* switch() (case It is OK to queue data chunks) */ + } else { + skb_queue_tail(&q->control, (struct sk_buff *)chunk); + } + if (error < 0) { return error; } + + error = sctp_flush_outqueue(q, 0); + + return error; + +} /* sctp_push_outqueue() */ + +/* Mark all the eligible packets on a transport for retransmission and force + * one packet out. + */ +void +sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, + uint8_t fast_retransmit) +{ + struct list_head *lchunk; + sctp_chunk_t *chunk; + int error = 0; + struct list_head tlist; + + if (fast_retransmit) { + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); + } else { + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); + } + + INIT_LIST_HEAD(&tlist); + + while( !list_empty(&transport->transmitted)) { + lchunk = sctp_list_dequeue(&transport->transmitted); + + chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + + /* If we are doing retransmission due to a fast retransmit, + * only the chunk's that are marked for fast retransmit + * should be added to the retransmit queue. If we are doing + * retransmission due to a timeout, only the chunks that are + * not yet acked should be added to the retransmit queue. + */ + + if ((fast_retransmit && !chunk->fast_retransmit) + || (!fast_retransmit && chunk->tsn_gap_acked)) { + list_add_tail(lchunk, &tlist); + } else { + /* RFC 2960 6.2.1 Processing a Received SACK + * + * C) Any time a DATA chunk is marked for + * retransmission (via either T3-rtx timer expiration + * (Section 6.3.3) or via fast retransmit + * (Section 7.2.4)), add the data size of those + * chunks to the rwnd. + */ + q->asoc->peer.rwnd += sctp_data_size(chunk); + q->outstanding_bytes -= sctp_data_size(chunk); + transport->flight_size -= sctp_data_size(chunk); + + /* sctpimpguide-05 Section 2.8.2 + * M5) If a T3-rtx timer expires, the + * 'TSN.Missing.Report' of all affected TSNs is set + * to 0. + */ + chunk->tsn_missing_report = 0; + + /* If a chunk that is being used for RTT measurement + * has to be retransmitted, we cannot use this chunk + * anymore for RTT measurements. Reset rto_pending so + * that a new RTT measurement is started when a new + * data chunk is sent. + */ + if (chunk->rtt_in_progress) { + chunk->rtt_in_progress = 0; + transport->rto_pending = 0; + } + + list_add_tail(lchunk, &q->retransmit); + } + + } /* while (we have stuff left on transport->transmitted) */ + + /* Reconstruct the transmitted queue with chunks that are not + * eligible for retransmission. + */ + while( NULL != (lchunk = sctp_list_dequeue(&tlist))) { + list_add_tail(lchunk, &transport->transmitted); + } + + SCTP_DEBUG_PRINTK(__FUNCTION__": transport: %p, fast_retransmit: %d, " + "cwnd: %d, ssthresh: %d, flight_size: %d, " + "pba: %d\n",transport, fast_retransmit, + transport->cwnd, transport->ssthresh, + transport->flight_size, + transport->partial_bytes_acked); + + error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); + + if (error) { + q->asoc->base.sk->err = -error; + } + +} /* sctp_retransmit() */ + +/* + * Transmit DATA chunks on the retransmit queue. Upon return from + * sctp_flush_retran_queue() the packet 'pkt' may contain chunks which + * need to be transmitted by the caller. + * We assume that pkt->transport has already been set. + * + * The return value is a normal kernel error return value. + */ +static int +sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, + int rtx_timeout, int *start_timer) +{ + + struct list_head *lqueue; + struct list_head *lchunk; + sctp_transport_t *transport = pkt->transport; + sctp_xmit_t status; + sctp_chunk_t *chunk; + sctp_association_t *asoc; + int error = 0; + + asoc = q->asoc; + lqueue = &q->retransmit; + + /* RFC 2960 6.3.3 Handle T3-rtx Expiration + * + * E3) Determine how many of the earliest (i.e., lowest TSN) + * outstanding DATA chunks for the address for which the + * T3-rtx has expired will fit into a single packet, subject + * to the MTU constraint for the path corresponding to the + * destination transport address to which the retransmission + * is being sent (this may be different from the address for + * which the timer expires [see Section 6.4]). Call this value + * K. Bundle and retransmit those K DATA chunks in a single + * packet to the destination endpoint. + * + * [Just to be painfully clear, if we are retransmitting + * because a timeout just happened, we should send only ONE + * packet of retransmitted data.] + */ + + + lchunk = sctp_list_dequeue(lqueue); + + while (NULL != lchunk) { + + chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + +#if 0 + /* If a chunk has been tried for more than SCTP_DEF_MAX_SEND + * times, discard it, and check the empty flag of the outqueue. + * + * --xguo + */ + + if ( chunk->snd_count > SCTP_DEF_MAX_SEND ) { + sctp_free_chunk(chunk); + continue; + } +#endif + /* Attempt to append this chunk to the packet. */ + status = (*q->append_output)(pkt, chunk); + + switch (status) { + case SCTP_XMIT_PMTU_FULL: + + /* Send this packet. */ + if ( (error = (*q->force_output)(pkt)) == 0 ) { + *start_timer = 1; + } + + /* If we are retransmitting, we should only + * send a single packet. + */ + if (rtx_timeout) { + list_add(lchunk, lqueue); + lchunk = NULL; + } + + /* Bundle lchunk in the next round. */ + break; + case SCTP_XMIT_RWND_FULL: + + /* Send this packet. */ + if ( (error = (*q->force_output)(pkt)) == 0 ) { + *start_timer = 1; + } + + /* Stop sending DATA as there is no more room + * at the reciever. + */ + list_add(lchunk, lqueue); + lchunk = NULL; + break; + default: + /* The append was successful, so add this chunk to + * the transmitted list. + */ + list_add_tail(lchunk, + &transport->transmitted); + *start_timer = 1; + q->empty = 0; + + /* Retrieve a new chunk to bundle. */ + lchunk = sctp_list_dequeue(lqueue); + break; + } + + + } /* while (more retransmit chunks) */ + + return(error); + +} /* sctp_flush_retran_queue() */ + +/* This routine either transmits the fragment or puts it on the output + * queue. 'pos' points to the next chunk in the output queue after the + * chunk that is currently in the process of fragmentation. + */ +void +sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, sctp_packet_t *packet, + sctp_chunk_t *frag, uint32_t tsn) +{ + sctp_transport_t *transport = packet->transport; + struct sk_buff_head *queue = &q->out; + sctp_xmit_t status; + int error; + + frag->subh.data_hdr->tsn = htonl(tsn); + frag->has_tsn = 1; + + /* An inner fragment may be smaller than the earlier one and may get + * in if we call q->build_output. This ensures that all the fragments + * are sent in order. + */ + if (!skb_queue_empty(queue)) { + SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " + "adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *)frag); + } else { + skb_queue_tail(queue, (struct sk_buff *)frag); + } + return; + } + + /* Add the chunk fragment to the packet. */ + status = (*q->build_output)(packet, frag); + switch (status) { + case SCTP_XMIT_RWND_FULL: + /* RWND is full, so put the chunk in the output queue. */ + SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " + "adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *)frag); + } else { + skb_queue_tail(queue, (struct sk_buff *)frag); + } + break; + case SCTP_XMIT_OK: + error = (*q->force_output)(packet); + if (error < 0) { + /* Packet could not be transmitted, put the chunk in + * the output queue + */ + SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " + "failed. adding 0x%x to outqueue\n", + ntohl(frag->subh.data_hdr->tsn)); + if (pos) { + skb_insert(pos, (struct sk_buff *)frag); + } else { + skb_queue_tail(queue, (struct sk_buff *)frag); + } + } else { + SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " + "success. 0x%x sent\n", + ntohl(frag->subh.data_hdr->tsn)); + list_add_tail(&frag->transmitted_list, + &transport->transmitted); + + sctp_transport_reset_timers(transport); + } + break; + default: + BUG(); + } + +} /* sctp_xmit_frag() */ + +/* This routine calls sctp_xmit_frag() for all the fragments of a message. + * The argument 'frag' point to the first fragment and it holds the list + * of all the other fragments in the 'frag_list' field. + */ +void +sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, + sctp_chunk_t *frag) +{ + sctp_association_t *asoc = frag->asoc; + struct list_head *lfrag, *frag_list; + uint32_t tsn; + int nfrags = 1; + struct sk_buff *pos; + + /* Count the number of fragments. */ + frag_list = &frag->frag_list; + list_for_each(lfrag, frag_list) { + nfrags++; + } + + /* Get a TSN block of nfrags TSNs. */ + tsn = __sctp_association_get_tsn_block(asoc, nfrags); + + pos = skb_peek(&q->out); + /* Transmit the first fragment. */ + sctp_xmit_frag(q, pos, packet, frag, tsn++); + + /* Transmit the rest of fragments. */ + frag_list = &frag->frag_list; + list_for_each(lfrag, frag_list) { + frag = list_entry(lfrag, sctp_chunk_t, frag_list); + sctp_xmit_frag(q, pos, packet, frag, tsn++); + } + +} /* sctp_xmit_fragmented_chunks() */ + +/* This routine breaks the given chunk into 'max_frag_data_len' size + * fragments. It returns the first fragment with the frag_list field holding + * the remaining fragments. + */ +sctp_chunk_t * +sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) +{ + sctp_association_t *asoc = chunk->asoc; + void *data_ptr = chunk->subh.data_hdr; + struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; + uint16_t chunk_data_len = sctp_data_size(chunk); + uint16_t ssn = ntohs(chunk->subh.data_hdr->ssn); + sctp_chunk_t *first_frag, *frag; + struct list_head *frag_list; + int nfrags; + + /* nfrags = no. of max size fragments + any smaller last fragment. */ + nfrags = ((chunk_data_len / max_frag_data_len) + + ((chunk_data_len % max_frag_data_len) ? 1 : 0)); + + /* Start of the data in the chunk. */ + data_ptr += sizeof(sctp_datahdr_t); + + /* Make the first fragment. */ + first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + data_ptr, SCTP_DATA_FIRST_FRAG, ssn); + + if (!first_frag) { goto err; } + + /* All the fragments are added to the frag_list of the first chunk. */ + frag_list = &first_frag->frag_list; + + chunk_data_len -= max_frag_data_len; + data_ptr += max_frag_data_len; + + /* Make the middle fragments. */ + while (chunk_data_len > max_frag_data_len) { + + frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); + if (!frag) { goto err; } + + /* Add the middle fragment to the first fragment's frag_list.*/ + list_add_tail(&frag->frag_list, frag_list); + + chunk_data_len -= max_frag_data_len; + data_ptr += max_frag_data_len; + } + + /* Make the last fragment. */ + frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, + SCTP_DATA_LAST_FRAG, ssn); + if (!frag) { goto err; } + + /* Add the last fragment to the first fragment's frag_list. */ + list_add_tail(&frag->frag_list, frag_list); + + /* Free the original chunk. */ + sctp_free_chunk(chunk); + + return (first_frag); + +err: + /* Free any fragments that are created before the failure. */ + if (first_frag) { + struct list_head *flist, *lfrag; + + /* Free all the fragments off the first one. */ + flist = &first_frag->frag_list; + while (NULL != (lfrag = sctp_list_dequeue(flist))) { + frag = list_entry(lfrag, sctp_chunk_t, frag_list); + sctp_free_chunk(frag); + } + + /* Free the first fragment. */ + sctp_free_chunk(first_frag); + } + + return(NULL); + +} /* sctp_fragment_chunk() */ + + +/* + * sctp_flush_outqueue - Try to flush an outqueue. + * + * Description: Send everything in q which we legally can, subject to + * congestion limitations. + * + * Note: This function can be called from multiple contexts so appropriate + * locking concerns must be made. Today we use the sock lock to protect + * this function. + */ +int +sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) +{ + sctp_packet_t *packet; + sctp_packet_t singleton; + sctp_association_t *asoc = q->asoc; + int ecn_capable = asoc->peer.ecn_capable; + uint16_t sport = asoc->base.bind_addr.port; + uint16_t dport = asoc->peer.port; + uint32_t vtag = asoc->peer.i.init_tag; + /* This is the ECNE handler for singleton packets. */ + sctp_packet_phandler_t *s_ecne_handler = NULL; + sctp_packet_phandler_t *ecne_handler = NULL; + struct sk_buff_head *queue; + sctp_transport_t *transport = NULL; + sctp_transport_t *new_transport; + sctp_chunk_t *chunk; + sctp_xmit_t status; + int error = 0; + int start_timer = 0; + sctp_ulpevent_t *event; + + + /* These transports have chunks to send. */ + struct list_head transport_list; + struct list_head *ltransport; + + + INIT_LIST_HEAD(&transport_list); + packet = NULL; + + /* + * 6.10 Bundling + * ... + * When bundling control chunks with DATA chunks, an + * endpoint MUST place control chunks first in the outbound + * SCTP packet. The transmitter MUST transmit DATA chunks + * within a SCTP packet in increasing order of TSN. + * ... + */ + + if ( ecn_capable ) { + s_ecne_handler = &sctp_get_no_prepend; + ecne_handler = &sctp_get_ecne_prepend; + } + + queue = &q->control; + while (NULL != (chunk = (sctp_chunk_t *)skb_dequeue(queue))) { + + /* Pick the right transport to use. */ + new_transport = chunk->transport; + + if (new_transport == NULL ) { + new_transport = asoc->peer.active_path; + } else if (!new_transport->state.active) { + + /* If the chunk is Heartbeat, send it to + * chunk->transport, even it's inactive. + */ + if ( chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) { + new_transport = asoc->peer.active_path; + } + } + + /* Are we switching transports? + * Take care of transport locks. + */ + if ( new_transport != transport ) { + + transport = new_transport; + + if ( list_empty(&transport->send_ready) ) { + list_add_tail(&transport->send_ready, + &transport_list); + } + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + } + + switch(chunk->chunk_hdr->type) { + /* + * 6.10 Bundling + * ... + * An endpoint MUST NOT bundle INIT, INIT ACK or SHUTDOWN + * COMPLETE with any other chunks. [Send them immediately.] + */ + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + (*q->init_output)(&singleton, transport, sport, dport); + (*q->config_output)(&singleton, vtag, ecn_capable, + s_ecne_handler); + (void) (*q->build_output)(&singleton, chunk); + error = (*q->force_output)(&singleton); + if (error < 0) {return(error);} + break; + case SCTP_CID_ABORT: + case SCTP_CID_SACK: + case SCTP_CID_HEARTBEAT: + case SCTP_CID_HEARTBEAT_ACK: + case SCTP_CID_SHUTDOWN: + case SCTP_CID_SHUTDOWN_ACK: + case SCTP_CID_ERROR: + case SCTP_CID_COOKIE_ECHO: + case SCTP_CID_COOKIE_ACK: + case SCTP_CID_ECN_ECNE: + case SCTP_CID_ECN_CWR: + (void) (*q->build_output)(packet, chunk); + break; + case SCTP_CID_ASCONF: + case SCTP_CID_ASCONF_ACK: + (void) (*q->build_output)(packet, chunk); + break; + default: + /* We built a chunk with an illegal type! */ + BUG(); + } /* switch(type) */ + } /* while (more chunks in control queue) */ + + /* Is it OK to send data chunks? */ + switch (asoc->state) { + + case SCTP_STATE_COOKIE_ECHOED: + /* Only allow bundling, if this packet has a COOKIE-ECHO + * chunk. + */ + if (packet && !packet->has_cookie_echo) { + break; + } + + case SCTP_STATE_ESTABLISHED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_RECEIVED: + /* + * RFC 2960 6.1 Transmission of DATA Chunks + * + * C) When the time comes for the sender to transmit, + * before sending new DATA chunks, the sender MUST + * first transmit any outstanding DATA chunks which + * are marked for retransmission (limited by the + * current cwnd). + */ + + if ( !list_empty(&q->retransmit) ) { + if ( transport == asoc->peer.retran_path ) { + goto retran; + } + + /* Switch transports & prepare the packet. */ + + transport = asoc->peer.retran_path; + + if ( list_empty(&transport->send_ready) ) { + list_add_tail(&transport->send_ready, + &transport_list); + } + + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + retran: + error = sctp_flush_retran_queue(q, + packet, + rtx_timeout, + &start_timer); + + if (start_timer) { + sctp_transport_reset_timers(transport); + } + + } /* if (we have chunks for retransmission) */ + + /* Finally, transmit new packets. */ + start_timer = 0; + queue = &q->out; + while (NULL != (chunk = (sctp_chunk_t *) + skb_dequeue(queue))) { + + /* RFC 2960 6.5 Every DATA chunk MUST carry a valid + * stream identifier. + */ + if (chunk->sinfo.sinfo_stream >= + asoc->c.sinit_num_ostreams) { + + /* Generate a SEND FAILED event. */ + event = sctp_ulpevent_make_send_failed(asoc, + chunk, SCTP_DATA_UNSENT, + SCTP_ERROR_INV_STRM, + GFP_ATOMIC); + if (event) { + sctp_ulpqueue_tail_event(&asoc->ulpq, + event); + } + + /* Free the chunk. This chunk is not on any + * list yet, just free it. */ + sctp_free_chunk(chunk); + + continue; + + } + /* If there is a specified transport, use it. + * Otherwise, we want to use the active path. + */ + new_transport = chunk->transport; + + if ( new_transport == NULL + || !new_transport->state.active ) { + new_transport = asoc->peer.active_path; + } + + /* Change packets if necessary. */ + if ( new_transport != transport ) { + + transport = new_transport; + + /* Schedule to have this transport's + * packet flushed. + */ + if ( list_empty(&transport->send_ready) ) { + list_add_tail(&transport->send_ready, + &transport_list); + } + + packet = &transport->packet; + (*q->config_output)(packet, vtag, + ecn_capable, ecne_handler); + } + + SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ", + q, chunk, + chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK( + chunk->chunk_hdr->type)) + : "Illegal Chunk"); + + SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head " + "%p skb->users %d.\n", + ntohl(chunk->subh.data_hdr->tsn), + chunk->skb?chunk->skb->head:0, + chunk->skb? + (int)atomic_read(&chunk->skb->users) + :-1); + + /* Add the chunk to the packet. */ + status = (*q->build_output)(packet, chunk); + + switch (status) { + case SCTP_XMIT_PMTU_FULL: + case SCTP_XMIT_RWND_FULL: + /* We could not append this chunk, so put + * the chunk back on the output queue. + */ + SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could" + "not transmit TSN: 0x%x, status: %d\n", + ntohl(chunk->subh.data_hdr->tsn), status); + skb_queue_head(queue, (struct sk_buff *)chunk); + goto sctp_flush_out; + break; + case SCTP_XMIT_MUST_FRAG: + { + sctp_chunk_t *frag; + + frag = sctp_fragment_chunk(chunk, + packet->transport->asoc->frag_point); + if (!frag) { + /* We could not fragment due to out of + * memory condition. Free the original + * chunk and return ENOMEM. + */ + sctp_free_chunk(chunk); + error = -ENOMEM; + return (error); + } + + sctp_xmit_fragmented_chunks(q, packet, frag); + goto sctp_flush_out; + break; + } + case SCTP_XMIT_OK: + break; + default: + BUG(); + } + + /* BUG: We assume that the (*q->force_output()) + * call below will succeed all the time and add the + * chunk to the transmitted list and restart the + * timers. + * It is possible that the call can fail under OOM + * conditions. + * + * Is this really a problem? Won't this behave + * like a lost TSN? + */ + list_add_tail(&chunk->transmitted_list, + &transport->transmitted); + + sctp_transport_reset_timers(transport); + + q->empty = 0; + } + break; + default: + /* Do nothing. */ + break; + } /* switch ()(case It is OK to send data chunks:) */ + + sctp_flush_out: + /* Before returning, examine all the transports touched in + * this call. Right now, we bluntly force clear all the + * transports. Things might change after we implement Nagle. + * But such an examination is still required. + * + * --xguo + */ + while ( (ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { + sctp_transport_t *t = list_entry(ltransport, + sctp_transport_t, send_ready); + if ( t != transport ) { + transport = t; + } + + packet = &transport->packet; + if ( packet->size != SCTP_IP_OVERHEAD ) { + error = (*q->force_output)(packet); + } + } + + return(error); + +} /* sctp_flush_outqueue() */ + +/* Set the various output handling callbacks. */ +int +sctp_outqueue_set_output_handlers(sctp_outqueue_t *q, + sctp_outqueue_ohandler_init_t init, + sctp_outqueue_ohandler_config_t config, + sctp_outqueue_ohandler_t append, + sctp_outqueue_ohandler_t build, + sctp_outqueue_ohandler_force_t force) +{ + q->init_output = init; + q->config_output = config; + q->append_output = append; + q->build_output = build; + q->force_output = force; + return 0; + +} /* sctp_outqueue_set_out_handler() */ + + +/* Update unack_data based on the incoming SACK chunk */ +static void +sctp_sack_update_unack_data(sctp_association_t *assoc, sctp_sackhdr_t *sack) +{ + sctp_sack_variable_t *frags; + uint16_t unack_data; + int i; + + unack_data = assoc->next_tsn - assoc->ctsn_ack_point - 1; + + frags = sack->variable; + for (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) { + unack_data -= ((ntohs(frags[i].gab.end) - + ntohs(frags[i].gab.start) + 1)); + } + + assoc->unack_data = unack_data; +} + +/* This is where we REALLY process a SACK. + * + * Process the sack against the outqueue. Mostly, this just frees + * things off the transmitted queue. + */ +int +sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) +{ + sctp_chunk_t *tchunk; + list_t *lchunk, *transport_list, *pos; + uint32_t tsn; + uint32_t sack_ctsn; + uint32_t ctsn; + sctp_transport_t *transport; + int outstanding; + uint32_t sack_a_rwnd; + + /* Grab the association's destination address list. */ + transport_list = &q->asoc->peer.transport_addr_list; + + /* Run through the retransmit queue. Credit bytes received + * and free those chunks that we can. + */ + sctp_check_transmitted(q, &q->retransmit, NULL, sack); + + /* Run through the transmitted queue. + * Credit bytes received and free those chunks which we can. + * + * This is a MASSIVE candidate for optimization. + */ + list_for_each(pos, transport_list) { + transport = list_entry(pos, sctp_transport_t, transports); + sctp_check_transmitted(q, &transport->transmitted, + transport, sack); + } + + /* Move the Cumulative TSN Ack Point if appropriate. */ + sack_ctsn = ntohl(sack->cum_tsn_ack); + if (TSN_lt(q->asoc->ctsn_ack_point, sack_ctsn)) { + q->asoc->ctsn_ack_point = sack_ctsn; + } + + /* Update unack_data field in the assoc. */ + sctp_sack_update_unack_data(q->asoc, sack); + + ctsn = q->asoc->ctsn_ack_point; + + SCTP_DEBUG_PRINTK(__FUNCTION__ ": sack Cumulative TSN Ack is 0x%x.\n", + sack_ctsn); + SCTP_DEBUG_PRINTK(__FUNCTION__ ": Cumulative TSN Ack of association " + "%p is 0x%x.\n",q->asoc, ctsn); + + /* Throw away stuff rotting on the sack queue. */ + list_for_each(lchunk, &q->sacked) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + if (TSN_lte(tsn, ctsn)){ + lchunk = lchunk->prev; + sctp_free_chunk(tchunk); + } + } + + /* ii) Set rwnd equal to the newly received a_rwnd minus the + * number of bytes still outstanding after processing the + * Cumulative TSN Ack and the Gap Ack Blocks. + */ + + sack_a_rwnd = ntohl(sack->a_rwnd); + outstanding = q->outstanding_bytes; + + if (outstanding < sack_a_rwnd) { + sack_a_rwnd -= outstanding; + } else { + sack_a_rwnd = 0; + } + + q->asoc->peer.rwnd = sack_a_rwnd; + + + /* See if all chunks are acked. + * Make sure the empty queue handler will get run later. + */ + + q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit); + if (!q->empty) { goto finish; } + + list_for_each(pos, transport_list) { + transport = list_entry(pos, sctp_transport_t, transports); + q->empty = q->empty && list_empty(&transport->transmitted); + if (!q->empty) { goto finish; } + } + + SCTP_DEBUG_PRINTK("sack queue is empty.\n"); + + finish: + return(q->empty); + +} /* sctp_sack_outqueue() */ + +/* Is the outqueue empty? */ +int +sctp_outqueue_is_empty(const sctp_outqueue_t *q) +{ + return(q->empty); + +} /* sctp_outqueue_is_empty() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Go through a transport's transmitted list or the assocication's retransmit + * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. + * The retransmit list will not have an associated transport. In case of a + * transmitted list with a transport, the transport's congestion, rto and fast + * retransmit parameters are also updated and if needed a fast retransmit + * process is started. + * + * I added coherent debug information output. --xguo + * + * Instead of printing 'sacked' or 'kept' for each TSN on the + * transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5. + * KEPT TSN6-TSN7, etc. + */ +static void +sctp_check_transmitted(sctp_outqueue_t *q, + struct list_head *transmitted_queue, + sctp_transport_t *transport, + sctp_sackhdr_t *sack) +{ + struct list_head *lchunk; + sctp_chunk_t *tchunk; + struct list_head tlist; + uint32_t tsn; + uint32_t sack_ctsn; + uint32_t rtt; + uint32_t highest_new_tsn_in_sack; + uint8_t restart_timer = 0; + uint8_t do_fast_retransmit = 0; + int bytes_acked = 0; + + /* These state variables are for coherent debug output. --xguo */ + +#if SCTP_DEBUG + uint32_t dbg_ack_tsn = 0; /* An ACKed TSN range starts here... */ + uint32_t dbg_last_ack_tsn = 0; /* ...and finishes here. */ + uint32_t dbg_kept_tsn = 0; /* An un-ACKed range starts here... */ + uint32_t dbg_last_kept_tsn = 0; /* ...and finishes here. */ + + /* 0 : The last TSN was ACKed. + * 1 : The last TSN was NOT ACKed (i.e. KEPT). + * -1: We need to initialize. + */ + int dbg_prt_state = -1; +#endif /* SCTP_DEBUG */ + + sack_ctsn = ntohl(sack->cum_tsn_ack); + highest_new_tsn_in_sack = sack_ctsn; + + INIT_LIST_HEAD(&tlist); + + /* The while loop will skip empty transmitted queues. */ + while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { + + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + + tsn = ntohl(tchunk->subh.data_hdr->tsn); + + if (sctp_acked(sack, tsn)) { + + /* If this queue is the retransmit queue, the + * retransmit timer has already reclaimed + * the outstanding bytes for this chunk, so only + * count bytes associated with a transport. + */ + if (transport) { + + /* If this chunk is being used for RTT + * measurement, calculate the RTT and update + * the RTO using this value. + * + * 6.3.1 C5) Karn's algorithm: RTT measurements + * MUST NOT be made using packets that were + * retransmitted (and thus for which it is + * ambiguous whether the reply was for the first + * instance of the packet or a later instance). + */ + if ((!tchunk->tsn_gap_acked) && + (1 == tchunk->num_times_sent) && + (tchunk->rtt_in_progress)) { + rtt = jiffies - tchunk->sent_at; + sctp_transport_update_rto(transport, + rtt); + } + } + + if (TSN_lte(tsn, sack_ctsn)) { + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R3) Whenever a SACK is received + * that acknowledges the DATA chunk + * with the earliest outstanding TSN + * for that address, restart T3-rtx + * timer for that address with its + * current RTO. + */ + restart_timer = 1; + + if (!tchunk->tsn_gap_acked) { + tchunk->tsn_gap_acked = 1; + bytes_acked += sctp_data_size(tchunk); + } + + list_add_tail(&tchunk->transmitted_list, + &q->sacked); + } else { + /* RFC2960 7.2.4, sctpimpguide-05 2.8.2 + * M2) Each time a SACK arrives reporting + * 'Stray DATA chunk(s)' record the highest TSN + * reported as newly acknowledged, call this + * value 'HighestTSNinSack'. A newly + * acknowledged DATA chunk is one not previously + * acknowledged in a SACK. + * + * When the SCTP sender of data receives a SACK + * chunk that acknowledges, for the first time, + * the receipt of a DATA chunk, all the still + * unacknowledged DATA chunks whose TSN is older + * than that newly acknowledged DATA chunk, are + * qualified as 'Stray DATA chunks'. + */ + if (!tchunk->tsn_gap_acked) { + tchunk->tsn_gap_acked = 1; + bytes_acked += sctp_data_size(tchunk); + if (TSN_lt(highest_new_tsn_in_sack, + tsn)) { + highest_new_tsn_in_sack = tsn; + } + } + + list_add_tail(lchunk, &tlist); + } + +#if SCTP_DEBUG + switch ( dbg_prt_state ) { + case 0: /* last TSN was ACKed */ + if ( dbg_last_ack_tsn + 1 == tsn ) { + /* This TSN belongs to the + * current ACK range. + */ + break; + } + + if ( dbg_last_ack_tsn != dbg_ack_tsn ) { + /* Display the end of the + * current range. + */ + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_ack_tsn); + } + + /* Start a new range. */ + SCTP_DEBUG_PRINTK(",%08x",tsn); + dbg_ack_tsn = tsn; + + break; + case 1: /* The last TSN was NOT ACKed. */ + if ( dbg_last_kept_tsn != dbg_kept_tsn ) { + /* Display the end of current range. */ + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_kept_tsn); + } + + SCTP_DEBUG_PRINTK("\n"); + + /* FALL THROUGH... */ + default: + /* This is the first-ever TSN we examined. */ + /* Start a new range of ACK-ed TSNs. */ + SCTP_DEBUG_PRINTK("ACKed: %08x",tsn); + dbg_prt_state = 0; + dbg_ack_tsn = tsn; + } + dbg_last_ack_tsn = tsn; +#endif /* SCTP_DEBUG */ + + } else { + if (tchunk->tsn_gap_acked) { + SCTP_DEBUG_PRINTK(__FUNCTION__ + ": Receiver reneged on data " + "TSN: 0x%x\n", tsn); + tchunk->tsn_gap_acked = 0; + + bytes_acked -= sctp_data_size(tchunk); + + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R4) Whenever a SACK is received missing a TSN + * that was previously acknowledged via a Gap Ack + * Block, start T3-rtx for the destination + * address to which the DATA chunk was originally + * transmitted if it is not already running. + */ + restart_timer = 1; + } + + list_add_tail(lchunk, &tlist); + +#if SCTP_DEBUG + /* See the above comments on ACK-ed TSNs. */ + switch ( dbg_prt_state ) { + case 1: + if ( dbg_last_kept_tsn + 1 == tsn ) { break; } + + if ( dbg_last_kept_tsn != dbg_kept_tsn ) + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_kept_tsn); + + SCTP_DEBUG_PRINTK(",%08x",tsn); + dbg_kept_tsn = tsn; + break; + case 0: + if ( dbg_last_ack_tsn != dbg_ack_tsn ) + SCTP_DEBUG_PRINTK("-%08x", + dbg_last_ack_tsn); + SCTP_DEBUG_PRINTK("\n"); + + /* FALL THROUGH... */ + default: + SCTP_DEBUG_PRINTK("KEPT: %08x",tsn); + dbg_prt_state = 1; + dbg_kept_tsn = tsn; + } + dbg_last_kept_tsn = tsn; +#endif /* SCTP_DEBUG */ + + } /* if (TSN has just been ACKd) */ + }; /* while (transmitted queue is not empty) */ + +#if SCTP_DEBUG + /* Finish off the last range, displaying its ending TSN. */ + switch ( dbg_prt_state ) { + case 0: if ( dbg_last_ack_tsn != dbg_ack_tsn ) { + SCTP_DEBUG_PRINTK("-%08x\n",dbg_last_ack_tsn); + } else { SCTP_DEBUG_PRINTK("\n"); } + break; + case 1: if ( dbg_last_kept_tsn != dbg_kept_tsn ) { + SCTP_DEBUG_PRINTK("-%08x\n",dbg_last_kept_tsn); + } else { SCTP_DEBUG_PRINTK("\n"); } + } + +#endif /* SCTP_DEBUG */ + + if (transport) { + if (bytes_acked) { + /* 8.2. When an outstanding TSN is acknowledged, + * the endpoint shall clear the error counter of + * the destination transport address to which the + * DATA chunk was last sent. + * The association's overall error counter is + * also cleared. + */ + transport->error_count = 0; + transport->asoc->overall_error_count = 0; + + /* Mark the destination transport address as + * active if it is not so marked. + */ + if (!transport->state.active) { + sctp_assoc_control_transport( + transport->asoc, + transport, + SCTP_TRANSPORT_UP, + SCTP_RECEIVED_SACK); + } + + sctp_transport_raise_cwnd(transport, sack_ctsn, + bytes_acked); + + transport->flight_size -= bytes_acked; + q->outstanding_bytes -= bytes_acked; + } else { + /* RFC 2960 6.1, sctpimpguide-06 2.15.2 + * When a sender is doing zero window probing, it + * should not timeout the association if it continues + * to receive new packets from the receiver. The + * reason is that the receiver MAY keep its window + * closed for an indefinite time. + * A sender is doing zero window probing when the + * receiver's advertised window is zero, and there is + * only one data chunk in flight to the receiver. + */ + if ((0 == q->asoc->peer.rwnd) + && (!list_empty(&tlist)) + && (sack_ctsn+2 == q->asoc->next_tsn)) { + SCTP_DEBUG_PRINTK("%s: SACK received for zero " + "window probe: %u\n", + __FUNCTION__, sack_ctsn); + q->asoc->overall_error_count = 0; + transport->error_count = 0; + } + } + + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R2) Whenever all outstanding data sent to an address have + * been acknowledged, turn off the T3-rtx timer of that + * address. + */ + if (!transport->flight_size) { + if (timer_pending(&transport->T3_rtx_timer) && + del_timer(&transport->T3_rtx_timer)) { + sctp_transport_put(transport); + } + } else if (restart_timer) { + if (!mod_timer(&transport->T3_rtx_timer, + jiffies + transport->rto)) { + sctp_transport_hold(transport); + } + } + + } + + /* Reconstruct the transmitted list with chunks that are not yet + * acked by the Cumulative TSN Ack. + */ + while( NULL != (lchunk = sctp_list_dequeue(&tlist))) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + + /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all + * 'Unacknowledged TSN's', if the TSN number of an + * 'Unacknowledged TSN' is smaller than the 'HighestTSNinSack' + * value, increment the 'TSN.Missing.Report' count on that + * chunk if it has NOT been fast retransmitted or marked for + * fast retransmit already. + * + * M4) If any DATA chunk is found to have a + * 'TSN.Missing.Report' + * value larger than or equal to 4, mark that chunk for + * retransmission and start the fast retransmit procedure. + */ + if ((!tchunk->fast_retransmit) + && (!tchunk->tsn_gap_acked) + && (TSN_lt(tsn, highest_new_tsn_in_sack))) { + tchunk->tsn_missing_report++; + SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", + __FUNCTION__, tsn, + tchunk->tsn_missing_report); + } + if (tchunk->tsn_missing_report >= 4) { + tchunk->fast_retransmit = 1; + do_fast_retransmit = 1; + } + + list_add_tail(lchunk, transmitted_queue); + } + + if (transport) { + if (do_fast_retransmit) { + sctp_retransmit(q, transport, do_fast_retransmit); + } + SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p, cwnd: %d, " + "ssthresh: %d, flight_size: %d, pba: %d\n", + transport, transport->cwnd, + transport->ssthresh, transport->flight_size, + transport->partial_bytes_acked); + } + +} /* sctp_check_transmitted() */ + +/* Is the given TSN acked by this packet? */ +static int +sctp_acked(sctp_sackhdr_t *sack, uint32_t tsn) +{ + int i; + sctp_sack_variable_t *frags; + uint16_t gap; + uint32_t ctsn = ntohl(sack->cum_tsn_ack); + + if (TSN_lte(tsn, ctsn)) { + goto pass; + } + + /* 3.3.4 Selective Acknowledgement (SACK) (3): + * + * Gap Ack Blocks: + * These fields contain the Gap Ack Blocks. They are repeated + * for each Gap Ack Block up to the number of Gap Ack Blocks + * defined in the Number of Gap Ack Blocks field. All DATA + * chunks with TSNs greater than or equal to (Cumulative TSN + * Ack + Gap Ack Block Start) and less than or equal to + * (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack + * Block are assumed to have been received correctly. + */ + + frags = sack->variable; + gap = tsn - ctsn; + for (i = 0; i < ntohs(sack->num_gap_ack_blocks); ++i) { + if (TSN_lte(ntohs(frags[i].gab.start), gap) + && TSN_lte(gap, ntohs(frags[i].gab.end))) { + goto pass; + } + } + + return 0; +pass: + return 1; + +} /* sctp_acked() */ + + diff --git a/net/sctp/sctp_primitive.c b/net/sctp/sctp_primitive.c new file mode 100644 index 000000000000..bed944950a3e --- /dev/null +++ b/net/sctp/sctp_primitive.c @@ -0,0 +1,195 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_primitive.c,v 1.5 2002/04/24 16:33:39 jgrimm Exp $ + * + * These functions implement the SCTP primitive functions from Section 10. + * + * Note that the descriptions from the specification are USER level + * functions--this file is the functions which populate the struct proto + * for SCTP which is the BOTTOM of the sockets interface. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Narasimha Budihal + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_primitive.c,v 1.5 2002/04/24 16:33:39 jgrimm Exp $"; + +#include +#include +#include /* For struct list_head */ +#include +#include +#include /* For struct timeval */ +#include +#include +#include + + +#define DECLARE_PRIMITIVE(name) \ +/* This is called in the code as sctp_primitive_ ## name. */ \ +int \ +sctp_primitive_ ## name(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_PRIMITIVE; \ + subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ + state = asoc ? asoc->state : SCTP_STATE_CLOSED; \ + ep = asoc ? asoc->ep : NULL; \ + \ + error = sctp_do_sm(event_type, subtype, state, ep, asoc, arg, GFP_KERNEL); \ + return(error); \ +} /* sctp_primitive_ ## name() */ + +/* 10.1 ULP-to-SCTP + * B) Associate + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) + * -> association id [,destination transport addr list] [,outbound stream + * count] + * + * This primitive allows the upper layer to initiate an association to a + * specific peer endpoint. + * + * This version assumes that asoc is fully populated with the initial + * parameters. We then return a traditional kernel indicator of + * success or failure. + */ + +/* This is called in the code as sctp_primitive_ASSOCIATE. */ + +DECLARE_PRIMITIVE(ASSOCIATE) + +/* 10.1 ULP-to-SCTP + * C) Shutdown + * + * Format: SHUTDOWN(association id) + * -> result + * + * Gracefully closes an association. Any locally queued user data + * will be delivered to the peer. The association will be terminated only + * after the peer acknowledges all the SCTP packets sent. A success code + * will be returned on successful termination of the association. If + * attempting to terminate the association results in a failure, an error + * code shall be returned. + */ + +DECLARE_PRIMITIVE(SHUTDOWN); + +/* 10.1 ULP-to-SCTP + * E) Send + * + * Format: SEND(association id, buffer address, byte count [,context] + * [,stream id] [,life time] [,destination transport address] + * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) + * -> result + * + * This is the main method to send user data via SCTP. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o buffer address - the location where the user message to be + * transmitted is stored; + * + * o byte count - The size of the user data in number of bytes; + * + * Optional attributes: + * + * o context - an optional 32 bit integer that will be carried in the + * sending failure notification to the ULP if the transportation of + * this User Message fails. + * + * o stream id - to indicate which stream to send the data on. If not + * specified, stream 0 will be used. + * + * o life time - specifies the life time of the user data. The user data + * will not be sent by SCTP after the life time expires. This + * parameter can be used to avoid efforts to transmit stale + * user messages. SCTP notifies the ULP if the data cannot be + * initiated to transport (i.e. sent to the destination via SCTP's + * send primitive) within the life time variable. However, the + * user data will be transmitted if SCTP has attempted to transmit a + * chunk before the life time expired. + * + * o destination transport address - specified as one of the destination + * transport addresses of the peer endpoint to which this packet + * should be sent. Whenever possible, SCTP should use this destination + * transport address for sending the packets, instead of the current + * primary path. + * + * o unorder flag - this flag, if present, indicates that the user + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * message). + * + * o no-bundle flag - instructs SCTP not to bundle this user data with + * other outbound DATA chunks. SCTP MAY still bundle even when + * this flag is present, when faced with network congestion. + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data + * being transmitted. This value is passed as opaque data by SCTP. + */ + +DECLARE_PRIMITIVE(SEND); + + +/* 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); +} /* sctp_other_icmp_unreachfrag() */ + diff --git a/net/sctp/sctp_protocol.c b/net/sctp/sctp_protocol.c new file mode 100644 index 000000000000..c3cbdd5c9a5f --- /dev/null +++ b/net/sctp/sctp_protocol.c @@ -0,0 +1,646 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_protocol.c,v 1.35 2002/08/16 19:30:49 jgrimm Exp $ + * + * Initialization/cleanup for SCTP protocol support. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_protocol.c,v 1.35 2002/08/16 19:30:49 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global data structures. */ +sctp_protocol_t sctp_proto; +struct proc_dir_entry *proc_net_sctp; + +/* This is the global socket data structure used for responding to + * the Out-of-the-blue (OOTB) packets. A control sock will be created + * for this socket at the initialization time. + */ +static struct socket *sctp_ctl_socket; + +extern struct net_proto_family inet_family_ops; + + +/* Return the address of the control sock. */ +struct sock *sctp_get_ctl_sock(void) +{ + return(sctp_ctl_socket->sk); + +} /* sctp_get_ctl_sock() */ + +/* Set up the proc fs entry for the SCTP protocol. */ +void +sctp_proc_init(void) +{ + if (!proc_net_sctp) { + struct proc_dir_entry *ent; + ent = proc_mkdir("net/sctp", 0); + if (ent) { + ent->owner = THIS_MODULE; + proc_net_sctp= ent; + } + } + +} /* sctp_proc_init() */ + +/* Clean up the proc fs entry for the SCTP protocol. */ +void +sctp_proc_exit(void) +{ + if (proc_net_sctp) { + proc_net_sctp= NULL; + remove_proc_entry("net/sctp", 0); + } + +} /* sctp_proc_exit() */ + + + +/* Private helper to extract ipv4 address and stash them in + * the protocol structure. + */ +static inline void +sctp_v4_get_local_addr_list(sctp_protocol_t *proto, + struct net_device *dev) +{ + struct in_device *in_dev; + struct in_ifaddr *ifa; + struct sockaddr_storage_list *addr; + + read_lock(&inetdev_lock); + if ((in_dev = __in_dev_get(dev)) == NULL) { + read_unlock(&inetdev_lock); + return; + } + + read_lock(&in_dev->lock); + + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + /* Add the address to the local list. */ + addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); + if (addr) { + INIT_LIST_HEAD(&addr->list); + addr->a.v4.sin_family = AF_INET; + addr->a.v4.sin_port = 0; + addr->a.v4.sin_addr.s_addr = ifa->ifa_local; + list_add_tail(&addr->list, &proto->local_addr_list); + } + } + + read_unlock(&in_dev->lock); + read_unlock(&inetdev_lock); + return; + +} /* sctp_v4_get_local_addr_list() */ + +/* Private helper to extract ipv6 address and stash them in + * the protocol structure. + * FIXME: Make this an address family function. + */ +static inline void +sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) +{ +#ifdef SCTP_V6_SUPPORT + /* FIXME: The testframe doesn't support this function. */ +#ifndef TEST_FRAME + struct inet6_dev *in6_dev; + struct inet6_ifaddr *ifp; + struct sockaddr_storage_list *addr; + + read_lock(&addrconf_lock); + if ((in6_dev = __in6_dev_get(dev)) == NULL) { + read_unlock(&addrconf_lock); + return; + } + + read_lock_bh(&in6_dev->lock); + for (ifp=in6_dev->addr_list; ifp; ifp=ifp->if_next) { + /* Add the address to the local list. */ + addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); + if (addr) { + addr->a.v6.sin6_family = AF_INET6; + addr->a.v6.sin6_port = 0; + addr->a.v6.sin6_addr = ifp->addr; + INIT_LIST_HEAD(&addr->list); + list_add_tail(&addr->list, &proto->local_addr_list); + } + } + + read_unlock_bh(&in6_dev->lock); + read_unlock(&addrconf_lock); + +#endif /* TEST_FRAME */ + return; +#endif /* SCTP_V6_SUPPORT */ +} /* sctp_v6_get_local_addr_list() */ + + +/* Extract our IP addresses from the system and stash them in the + * protocol structure. + */ +static void +__sctp_get_local_addr_list(sctp_protocol_t *proto) +{ + struct net_device *dev; + + read_lock(&dev_base_lock); + + for (dev=dev_base; dev; dev = dev->next) { + sctp_v4_get_local_addr_list(proto, dev); + sctp_v6_get_local_addr_list(proto, dev); + } + + read_unlock(&dev_base_lock); + +} /* __sctp_get_local_addr_list() */ + + +static void +sctp_get_local_addr_list(sctp_protocol_t *proto) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); + __sctp_get_local_addr_list(&sctp_proto); + sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); + +} /* sctp_get_local_addr_list() */ + + +/* Free the existing local addresses. */ +static void +__sctp_free_local_addr_list(sctp_protocol_t *proto) +{ + struct sockaddr_storage_list *addr; + list_t *pos, *temp; + + list_for_each_safe(pos, temp, &proto->local_addr_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + list_del(pos); + kfree(addr); + } + +} /* __sctp_free_local_addr_list() */ + +/* Free the existing local addresses. */ +static void +sctp_free_local_addr_list(sctp_protocol_t *proto) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); + __sctp_free_local_addr_list(proto); + sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); + +} /* sctp_free_local_addr_list() */ + + +/* Copy the local addresses which are valid for 'scope' into 'bp'. */ +int +sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, + sctp_scope_t scope, int priority, int copy_flags) +{ + + struct sockaddr_storage_list *addr; + int error = 0; + list_t *pos; + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); + list_for_each(pos, &proto->local_addr_list) { + addr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_in_scope(&addr->a, scope)) { + /* Now that the address is in scope, check to see if + * the address type is really supported by the local + * sock as well as the remote peer. + */ + if ((((AF_INET == addr->a.sa.sa_family) + && (copy_flags & SCTP_ADDR4_PEERSUPP))) + || (((AF_INET6 == addr->a.sa.sa_family) + && (copy_flags & SCTP_ADDR6_ALLOWED) + && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { + + error = sctp_add_bind_addr(bp, + &addr->a, + priority); + if (0 != error) { goto end_copy; } + } + } + } + +end_copy: + sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); + + return(error); + +} /* sctp_copy_local_addr_list() */ + + +/* Returns the mtu for the given v4 destination address. */ +int +sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) +{ + int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; + + struct rtable *rt; + struct rt_key key = { + .dst = address->v4.sin_addr.s_addr, + .src = 0, + .iif = 0, + .oif = 0, + .tos = 0, + .scope = 0 + }; + + if (ip_route_output_key(&rt, &key)) { + SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key" + " failed, returning %d as dst_mtu\n", + dst_mtu); + } else { + dst_mtu = rt->u.dst.pmtu; + SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: " + "ip_route_output_key: dev:%s pmtu:%d\n", + rt->u.dst.dev->name, dst_mtu); + ip_rt_put(rt); + } + + return (dst_mtu); + +} /* sctp_v4_get_dst_mtu() */ + + +/* Event handler for inet device events. + * Basically, whenever there is an event, we re-build our local address list. + */ +static int +sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + long flags __attribute__ ((unused)); + + sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); + __sctp_free_local_addr_list(&sctp_proto); + __sctp_get_local_addr_list(&sctp_proto); + sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); + + return NOTIFY_DONE; + +} /* sctp_netdev_event() */ + +/* + * Initialize the control inode/socket with a control endpoint data + * structure. This endpoint is reserved exclusively for the OOTB processing. + */ +int +sctp_ctl_sock_init(void) +{ + int err = 0; + int family = PF_INET; + + SCTP_V6(family = PF_INET6;) + + err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, + &sctp_ctl_socket); + if (err < 0) { + printk(KERN_ERR + "SCTP: Failed to create the SCTP control socket.\n"); + return err; + } + sctp_ctl_socket->sk->allocation = GFP_ATOMIC; + inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL; + + return 0; + +} /* sctp_ctl_sock_init() */ + +/* Get the table of functions for manipulating a particular address + * family. + */ +sctp_func_t * +sctp_get_af_specific(const sockaddr_storage_t *address) +{ + list_t *pos; + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *retval, *af; + + retval = NULL; + + /* Cycle through all AF specific functions looking for a + * match. + */ + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + + if (address->sa.sa_family == af->sa_family) { + retval = af; + break; + } + } + + return retval; + +} /* sctp_get_af_specific() */ + +/* Registration for netdev events. */ +struct notifier_block sctp_netdev_notifier = { + .notifier_call = sctp_netdev_event, +}; + +/* Socket operations. */ +struct proto_ops inet_seqpacket_ops = { + .family = PF_INET, + .release = inet_release, /* Needs to be wrapped... */ + .bind = inet_bind, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = inet_accept, + .getname = inet_getname, /* Semantics are different. */ + .poll = sctp_poll, + .ioctl = inet_ioctl, + .listen = sctp_inet_listen, + .shutdown = inet_shutdown, /* Looks harmless. */ + .setsockopt = inet_setsockopt, /* IP_SOL IP_OPTION is a problem. */ + .getsockopt = inet_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +/* Registration with AF_INET family. */ +struct inet_protosw sctp_protosw = +{ + .type = SOCK_SEQPACKET, + .protocol = IPPROTO_SCTP, + .prot = &sctp_prot, + .ops = &inet_seqpacket_ops, + .capability = -1, + .no_check = 0, + .flags = SCTP_PROTOSW_FLAG +}; + +/* Register with IP layer. */ +static struct inet_protocol sctp_protocol = +{ + .handler = sctp_rcv, /* SCTP input handler. */ + .err_handler = sctp_v4_err, /* SCTP error control */ + .protocol = IPPROTO_SCTP, /* protocol ID */ + .name = "SCTP" /* name */ +}; + +/* IPv4 address related functions. */ +sctp_func_t sctp_ipv4_specific = { + .queue_xmit = ip_queue_xmit, + .setsockopt = ip_setsockopt, + .getsockopt = ip_getsockopt, + .get_dst_mtu = sctp_v4_get_dst_mtu, + .net_header_len = sizeof(struct iphdr), + .sockaddr_len = sizeof(struct sockaddr_in), + .sa_family = AF_INET, +}; + + +/* Initialize the universe into something sensible. */ +int +sctp_init(void) +{ + int i; + int status = 0; + + /* Add SCTP to inetsw linked list. */ + inet_register_protosw(&sctp_protosw); + + /* Add SCTP to inet_protos hash table. */ + inet_add_protocol(&sctp_protocol); + + /* Initialize proc fs directory. */ + sctp_proc_init(); + + /* Initialize object count debugging. */ + sctp_dbg_objcnt_init(); + + /* + * 14. Suggested SCTP Protocol Parameter Values + */ + /* The following protocol parameters are RECOMMENDED: */ + /* RTO.Initial - 3 seconds */ + sctp_proto.rto_initial = SCTP_RTO_INITIAL; + /* RTO.Min - 1 second */ + sctp_proto.rto_min = SCTP_RTO_MIN; + /* RTO.Max - 60 seconds */ + sctp_proto.rto_max = SCTP_RTO_MAX; + /* RTO.Alpha - 1/8 */ + sctp_proto.rto_alpha = SCTP_RTO_ALPHA; + /* RTO.Beta - 1/4 */ + sctp_proto.rto_beta = SCTP_RTO_BETA; + + /* Valid.Cookie.Life - 60 seconds + */ + sctp_proto.valid_cookie_life = 60 * HZ; + + /* Max.Burst - 4 */ + sctp_proto.max_burst = SCTP_MAX_BURST; + + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + sctp_proto.max_retrans_association = 10; + sctp_proto.max_retrans_path = 5; + sctp_proto.max_retrans_init = 8; + + /* HB.interval - 30 seconds */ + sctp_proto.hb_interval = 30 * HZ; + + /* 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; + + /* Allocate and initialize the association hash table. */ + sctp_proto.assoc_hashsize = 4096; + sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) + kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.assoc_hashbucket) { + printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); + status = -ENOMEM; + goto err_ahash_alloc; + } + for (i = 0; i < sctp_proto.assoc_hashsize; i++) { + sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED; + sctp_proto.assoc_hashbucket[i].chain = NULL; + } + + /* Allocate and initialize the endpoint hash table. */ + sctp_proto.ep_hashsize = 64; + sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) + kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.ep_hashbucket) { + printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); + status = -ENOMEM; + goto err_ehash_alloc; + } + + for (i = 0; i < sctp_proto.ep_hashsize; i++) { + sctp_proto.ep_hashbucket[i].lock = RW_LOCK_UNLOCKED; + sctp_proto.ep_hashbucket[i].chain = NULL; + } + + /* Allocate and initialize the SCTP port hash table. */ + sctp_proto.port_hashsize = 4096; + sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) + kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); + if (!sctp_proto.port_hashtable) { + printk (KERN_ERR "SCTP: Failed bind hash alloc."); + status = -ENOMEM; + goto err_bhash_alloc; + } + + + sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED; + sctp_proto.port_rover = sysctl_local_port_range[0] - 1; + for (i = 0; i < sctp_proto.port_hashsize; i++) { + sctp_proto.port_hashtable[i].lock = SPIN_LOCK_UNLOCKED; + sctp_proto.port_hashtable[i].chain = NULL; + } + + sctp_sysctl_register(); + + INIT_LIST_HEAD(&sctp_proto.address_families); + INIT_LIST_HEAD(&sctp_ipv4_specific.list); + list_add_tail(&sctp_ipv4_specific.list, &sctp_proto.address_families); + + status = sctp_v6_init(); + if (status != 0) { + goto err_v6_init; + } + + /* Initialize the control inode/socket for handling OOTB packets. */ + if (0 != (status = sctp_ctl_sock_init())) { + printk (KERN_ERR + "SCTP: Failed to initialize the SCTP control sock.\n"); + goto err_ctl_sock_init; + } + + /* Initialize the local address list. */ + INIT_LIST_HEAD(&sctp_proto.local_addr_list); + sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; + + register_inetaddr_notifier(&sctp_netdev_notifier); + sctp_get_local_addr_list(&sctp_proto); + + return 0; + +err_ctl_sock_init: + sctp_v6_exit(); +err_v6_init: + sctp_sysctl_unregister(); + list_del(&sctp_ipv4_specific.list); + kfree(sctp_proto.port_hashtable); +err_bhash_alloc: + kfree(sctp_proto.ep_hashbucket); +err_ehash_alloc: + kfree(sctp_proto.assoc_hashbucket); +err_ahash_alloc: + sctp_dbg_objcnt_exit(); + sctp_proc_exit(); + inet_del_protocol(&sctp_protocol); + inet_unregister_protosw(&sctp_protosw); + return status; + +} /* sctp_init() */ + + +/* Exit handler for the SCTP protocol. */ +void +sctp_exit(void) +{ + /* BUG. This should probably do something useful like clean + * up all the remaining associations and all that memory. + */ + + /* Free the local address list. */ + unregister_inetaddr_notifier(&sctp_netdev_notifier); + sctp_free_local_addr_list(&sctp_proto); + + /* Free the control endpoint. */ + sock_release(sctp_ctl_socket); + + sctp_v6_exit(); + sctp_sysctl_unregister(); + list_del(&sctp_ipv4_specific.list); + + kfree(sctp_proto.assoc_hashbucket); + kfree(sctp_proto.ep_hashbucket); + kfree(sctp_proto.port_hashtable); + + sctp_dbg_objcnt_exit(); + sctp_proc_exit(); + + inet_del_protocol(&sctp_protocol); + inet_unregister_protosw(&sctp_protosw); + +} /* sctp_exit() */ + +module_init(sctp_init); +module_exit(sctp_exit); + +MODULE_AUTHOR("Linux Kernel SCTP developers "); +MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)"); +MODULE_LICENSE("GPL"); + diff --git a/net/sctp/sctp_sla1.c b/net/sctp/sctp_sla1.c new file mode 100644 index 000000000000..ce6a65bec0cc --- /dev/null +++ b/net/sctp/sctp_sla1.c @@ -0,0 +1,285 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sla1.c,v 1.4 2002/07/19 22:00:33 jgrimm Exp $ + * + * (It's really SHA-1 but Hey I was tired when I created this + * file, and on a plane to France :-) + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Randall Stewart + * kmorneau@cisco.com + * qxie1@email.mot.com + * + * Based on: + * Randy Stewart, et al. SCTP Reference Implementation which is licenced + * under the GPL. + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sla1.c,v 1.4 2002/07/19 22:00:33 jgrimm Exp $"; + + +#include +#include +#include +#include +#include /* for memcpy */ +#include /* dead chicken for in.h */ +#include /* for htonl and ntohl */ + +#include + +void +SLA1_Init(struct SLA_1_Context *ctx) +{ + /* Init the SLA-1 context structure */ + ctx->A = 0; + ctx->B = 0; + ctx->C = 0; + ctx->D = 0; + ctx->E = 0; + ctx->H0 = H0INIT; + ctx->H1 = H1INIT; + ctx->H2 = H2INIT; + ctx->H3 = H3INIT; + ctx->H4 = H4INIT; + ctx->TEMP = 0; + memset(ctx->words,0,sizeof(ctx->words)); + ctx->howManyInBlock = 0; + ctx->runningTotal = 0; +} + +void +SLA1processABlock(struct SLA_1_Context *ctx,unsigned int *block) +{ + int i; + /* init the W0-W15 to the block of words being + * hashed. + */ + /* step a) */ + + for(i=0;i<16;i++){ + ctx->words[i] = ntohl(block[i]); + } + /* now init the rest based on the SLA-1 formula, step b) */ + for(i=16;i<80;i++){ + ctx->words[i] = CSHIFT(1,((ctx->words[(i-3)]) ^ (ctx->words[(i-8)]) ^ (ctx->words[(i-14)]) ^ (ctx->words[(i-16)]))); + } + /* step c) */ + ctx->A = ctx->H0; + ctx->B = ctx->H1; + ctx->C = ctx->H2; + ctx->D = ctx->H3; + ctx->E = ctx->H4; + + /* step d) */ + for(i=0;i<80;i++){ + if(i < 20){ + ctx->TEMP = ((CSHIFT(5,ctx->A)) + + (F1(ctx->B,ctx->C,ctx->D)) + + (ctx->E) + + ctx->words[i] + + K1 + ); + }else if(i < 40){ + ctx->TEMP = ((CSHIFT(5,ctx->A)) + + (F2(ctx->B,ctx->C,ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K2 + ); + }else if(i < 60){ + ctx->TEMP = ((CSHIFT(5,ctx->A)) + + (F3(ctx->B,ctx->C,ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K3 + ); + }else{ + ctx->TEMP = ((CSHIFT(5,ctx->A)) + + (F4(ctx->B,ctx->C,ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K4 + ); + } + ctx->E = ctx->D; + ctx->D = ctx->C; + ctx->C = CSHIFT(30,ctx->B); + ctx->B = ctx->A; + ctx->A = ctx->TEMP; + } + /* step e) */ + ctx->H0 = (ctx->H0) + (ctx->A); + ctx->H1 = (ctx->H1) + (ctx->B); + ctx->H2 = (ctx->H2) + (ctx->C); + ctx->H3 = (ctx->H3) + (ctx->D); + ctx->H4 = (ctx->H4) + (ctx->E); +} + + +void +SLA1_Process(struct SLA_1_Context *ctx, const unsigned char *ptr, int siz) +{ + int numberLeft,leftToFill; + numberLeft = siz; + while(numberLeft > 0){ + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if(leftToFill > numberLeft){ + /* can only partially fill up this one */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock],ptr,numberLeft); + ctx->howManyInBlock += siz; + ctx->runningTotal += siz; + break; + }else{ + /* block is now full, process it */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock],ptr,leftToFill); + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + numberLeft -= leftToFill; + ctx->runningTotal += leftToFill; + ctx->howManyInBlock = 0; + } + } +} + +void +SLA1_Final(struct SLA_1_Context *ctx,unsigned char *digestBuf) +{ + /* if any left in block fill with padding + * and process. Then transfer the digest to + * the pointer. At the last block some special + * rules need to apply. We must add a 1 bit + * following the message, then we pad with + * 0's. The total size is encoded as a 64 bit + * number at the end. Now if the last buffer has + * more than 55 octets in it we cannot fit + * the 64 bit number + 10000000 pad on the end + * and must add the 10000000 pad, pad the rest + * of the message with 0's and then create a + * all 0 message with just the 64 bit size + * at the end and run this block through by itself. + * Also the 64 bit int must be in network byte + * order. + */ + int i,leftToFill; + unsigned int *ptr; + if(ctx->howManyInBlock > 55){ + /* special case, we need to process two + * blocks here. One for the current stuff + * plus possibly the pad. The other for + * the size. + */ + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if(leftToFill == 0){ + /* Should not really happen but I am paranoid */ + /* Not paranoid enough! It is possible for leftToFill to become + * negative! AAA!!!! This is another reason to pick MD5 :-)... + */ + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + /* init last block, a bit different then the rest :-) */ + ctx->SLAblock[0] = 0x80; + for(i=1;iSLAblock);i++){ + ctx->SLAblock[i] = 0x0; + } + }else if(leftToFill == 1){ + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock,0,sizeof(ctx->SLAblock)); + }else{ + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for(i=(ctx->howManyInBlock+1);iSLAblock);i++){ + ctx->SLAblock[i] = 0x0; + } + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock,0,sizeof(ctx->SLAblock)); + } + /* This is in bits so multiply by 8 */ + ctx->runningTotal *= 8; + ptr = (unsigned int *)&ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + }else{ + /* easy case, we just pad this + * message to size - end with 0 + * add the magic 0x80 to the next + * word and then put the network byte + * order size in the last spot and + * process the block. + */ + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for(i=(ctx->howManyInBlock+1);iSLAblock);i++){ + ctx->SLAblock[i] = 0x0; + } + /* get last int spot */ + ctx->runningTotal *= 8; + ptr = (unsigned int *)&ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); + } + /* Now at this point all we need do is transfer the + * digest back to the user + */ + digestBuf[3] = (ctx->H0 & 0xff); + digestBuf[2] = ((ctx->H0 >> 8) & 0xff); + digestBuf[1] = ((ctx->H0 >> 16) & 0xff); + digestBuf[0] = ((ctx->H0 >> 24) & 0xff); + + digestBuf[7] = (ctx->H1 & 0xff); + digestBuf[6] = ((ctx->H1 >> 8) & 0xff); + digestBuf[5] = ((ctx->H1 >> 16) & 0xff); + digestBuf[4] = ((ctx->H1 >> 24) & 0xff); + + digestBuf[11] = (ctx->H2 & 0xff); + digestBuf[10] = ((ctx->H2 >> 8) & 0xff); + digestBuf[9] = ((ctx->H2 >> 16) & 0xff); + digestBuf[8] = ((ctx->H2 >> 24) & 0xff); + + digestBuf[15] = (ctx->H3 & 0xff); + digestBuf[14] = ((ctx->H3 >> 8) & 0xff); + digestBuf[13] = ((ctx->H3 >> 16) & 0xff); + digestBuf[12] = ((ctx->H3 >> 24) & 0xff); + + digestBuf[19] = (ctx->H4 & 0xff); + digestBuf[18] = ((ctx->H4 >> 8) & 0xff); + digestBuf[17] = ((ctx->H4 >> 16) & 0xff); + digestBuf[16] = ((ctx->H4 >> 24) & 0xff); + +} + + + + + + + diff --git a/net/sctp/sctp_sm_make_chunk.c b/net/sctp/sctp_sm_make_chunk.c new file mode 100644 index 000000000000..7846eb77294a --- /dev/null +++ b/net/sctp/sctp_sm_make_chunk.c @@ -0,0 +1,1859 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_make_chunk.c,v 1.38 2002/07/26 22:52:32 jgrimm Exp $ + * + * This file includes part of the implementation of the add-IP extension, + * based on June 29, 2001, + * for the SCTP kernel reference Implementation. + * + * These functions work with the state functions in sctp_sm_statefuns.c + * to implement the state operations. These functions implement the + * steps which require modifying existing data structures. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * C. Robin + * Jon Grimm + * Xingang Guo + * Dajiang Zhang + * Sridhar Samudrala + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_make_chunk.c,v 1.38 2002/07/26 22:52:32 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* for get_random_bytes */ +#include +#include + +/* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 4: This parameter, when present, specifies all the + * address types the sending endpoint can support. The absence + * of this parameter indicates that the sending endpoint can + * support any address type. + */ +static const sctp_supported_addrs_param_t sat_param= { + { + SCTP_PARAM_SUPPORTED_ADDRESS_TYPES, + __constant_htons(SCTP_SAT_LEN), + }, + { /* types[] */ + SCTP_PARAM_IPV4_ADDRESS, + SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) + } +}; + +/* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 2: The ECN capable field is reserved for future use of + * Explicit Congestion Notification. + */ + +static const sctp_ecn_capable_param_t ecap_param = {{ + SCTP_PARAM_ECN_CAPABLE, + __constant_htons(sizeof(sctp_ecn_capable_param_t)), +}}; + + +/* A helper to initilize to initilize an op error inside a + * provided chunk, as most cause codes will be embedded inside an + * abort chunk. + */ +void +sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, + size_t paylen) +{ + sctp_errhdr_t err; + int padlen; + uint16_t len; + + /* Cause code constants are now defined in network order. */ + err.cause = cause_code; + len = sizeof(sctp_errhdr_t) + paylen; + padlen = len % 4; + len += padlen; + err.length = htons(len); + sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); + chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload); + + return; + +} /* sctp_init_cause() */ + + +/* 3.3.2 Initiation (INIT) (1) + * + * This chunk is used to initiate a SCTP association between two + * endpoints. The format of the INIT chunk is shown below: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 1 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initiate Tag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Advertised Receiver Window Credit (a_rwnd) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Outbound Streams | Number of Inbound Streams | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initial TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Optional/Variable-Length Parameters / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * The INIT chunk contains the following parameters. Unless otherwise + * noted, each parameter MUST only be included once in the INIT chunk. + * + * Fixed Parameters Status + * ---------------------------------------------- + * Initiate Tag Mandatory + * Advertised Receiver Window Credit Mandatory + * Number of Outbound Streams Mandatory + * Number of Inbound Streams Mandatory + * Initial TSN Mandatory + * + * Variable Parameters Status Type Value + * ------------------------------------------------------------- + * IPv4 Address (Note 1) Optional 5 + * IPv6 Address (Note 1) Optional 6 + * Cookie Preservative Optional 9 + * Reserved for ECN Capable (Note 2) Optional 32768 (0x8000) + * Host Name Address (Note 3) Optional 11 + * Supported Address Types (Note 4) Optional 12 + */ + +sctp_chunk_t * +sctp_make_init(const sctp_association_t *asoc, const sctp_bind_addr_t *bp, + int priority) +{ + sctp_inithdr_t init; + sctpParam_t addrs; + size_t chunksize; + sctp_chunk_t *retval = NULL; + int addrs_len = 0; + + /* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 1: The INIT chunks can contain multiple addresses that + * can be IPv4 and/or IPv6 in any combination. + */ + retval = NULL; + addrs.v = NULL; + + /* Convert the provided bind address list to raw format */ + addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); + if (NULL == addrs.v) { goto nodata; } + + init.init_tag = htonl(asoc->c.my_vtag); + init.a_rwnd = htonl(asoc->rwnd); + init.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + init.initial_tsn = htonl(asoc->c.initial_tsn); + + chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; + chunksize += sizeof(ecap_param); + + + /* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 3: An INIT chunk MUST NOT contain more than one Host + * Name address parameter. Moreover, the sender of the INIT + * MUST NOT combine any other address types with the Host Name + * address in the INIT. The receiver of INIT MUST ignore any + * other address types if the Host Name address parameter is + * present in the received INIT chunk. + * + * PLEASE DO NOT FIXME [This version does not support Host Name.] + */ + + retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); + if (NULL == retval) { goto nodata; } + + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(init), &init); + retval->param_hdr.v = + sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, SCTP_SAT_LEN, &sat_param); + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + + +nodata: + if (NULL != addrs.v) { kfree(addrs.v); } + return retval; + +}; /* sctp_chunk_t *sctp_make_init() */ + +sctp_chunk_t * +sctp_make_init_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk, + int priority) +{ + sctp_inithdr_t initack; + sctp_chunk_t *retval; + sctpParam_t addrs; + int addrs_len; + sctp_cookie_param_t *cookie; + int cookie_len; + size_t chunksize; + int error; + sctp_scope_t scope; + sctp_bind_addr_t *bp = NULL; + int flags; + + + retval = NULL; + + /* Build up the bind address list for the association based on + * info from the local endpoint and the remote peer. + */ + bp = sctp_bind_addr_new(priority); + if (NULL == bp) { goto nomem_bindaddr; } + + /* Look for supported address types parameter and then build + * our address list based on that. + */ + scope = sctp_scope(&asoc->peer.active_path->ipaddr); + flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + if (asoc->peer.ipv4_address) { + flags |= SCTP_ADDR4_PEERSUPP; + } + if (asoc->peer.ipv6_address) { + flags |= SCTP_ADDR6_PEERSUPP; + } + error = sctp_bind_addr_copy(bp, &asoc->ep->base.bind_addr, + scope, priority, flags); + if (0 != error) { goto nomem_copyaddr; } + + addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); + if (NULL == addrs.v) { goto nomem_rawaddr; } + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(asoc->rwnd); + initack.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + initack.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + initack.initial_tsn = htonl(asoc->c.initial_tsn); + + /* FIXME: We really ought to build the cookie right + * into the packet instead of allocating more fresh memory. + */ + cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len, + addrs.v, addrs_len); + if (NULL == cookie) { goto nomem_cookie; } + + chunksize = sizeof(initack) + addrs_len + cookie_len; + + /* Tell peer that we'll do ECN only if peer advertised such cap. */ + if (asoc->peer.ecn_capable) { + chunksize += sizeof(ecap_param); + } + + /* Now allocate and fill out the chunk. */ + + retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); + if (NULL == retval) { goto nomem_chunk; } + + /* Per the advice in RFC 2960 6.4, send this reply to + * the source of the INIT packet. + */ + retval->transport = chunk->transport; + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(initack), &initack); + retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, cookie_len, cookie); + if (asoc->peer.ecn_capable) { + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); + } + + /* We need to remove the const qualifier at this point. */ + retval->asoc = (sctp_association_t *) asoc; + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it received the DATA or control chunk + * to which it is replying. + * + * [INIT ACK back to where the INIT came from.] + */ + if (NULL != chunk) { + retval->transport = chunk->transport; + } + +nomem_chunk: + kfree(cookie); +nomem_cookie: + kfree(addrs.v); +nomem_rawaddr: +nomem_copyaddr: + sctp_bind_addr_free(bp); +nomem_bindaddr: + return retval; + +} /* sctp_make_init_ack() */ + +/* 3.3.11 Cookie Echo (COOKIE ECHO) (10): + * + * This chunk is used only during the initialization of an association. + * It is sent by the initiator of an association to its peer to complete + * the initialization process. This chunk MUST precede any DATA chunk + * sent within the association, but MAY be bundled with one or more DATA + * chunks in the same packet. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 10 |Chunk Flags | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Cookie / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bit + * + * Set to zero on transmit and ignored on receipt. + * + * Length: 16 bits (unsigned integer) + * + * Set to the size of the chunk in bytes, including the 4 bytes of + * the chunk header and the size of the Cookie. + * + * Cookie: variable size + * + * This field must contain the exact cookie received in the + * State Cookie parameter from the previous INIT ACK. + * + * An implementation SHOULD make the cookie as small as possible + * to insure interoperability. + */ +sctp_chunk_t * +sctp_make_cookie_echo(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + void *cookie; + int cookie_len; + + cookie = asoc->peer.cookie; + cookie_len = asoc->peer.cookie_len; + + /* Build a cookie echo chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); + if (NULL == retval) { goto nodata; } + retval->subh.cookie_hdr = + sctp_addto_chunk(retval, cookie_len, cookie); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [COOKIE ECHO back to where the INIT ACK came from.] + */ + if (NULL != chunk) { + retval->transport = chunk->transport; + } + +nodata: + return retval; + +} /* sctp_make_cookie_echo() */ + + +/* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11): + * + * This chunk is used only during the initialization of an + * association. It is used to acknowledge the receipt of a COOKIE + * ECHO chunk. This chunk MUST precede any DATA or SACK chunk sent + * within the association, but MAY be bundled with one or more DATA + * chunks or SACK chunk in the same SCTP packet. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 11 |Chunk Flags | Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Chunk Flags: 8 bits + * + * + * Set to zero on transmit and ignored on receipt. + */ +sctp_chunk_t * +sctp_make_cookie_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [COOKIE ACK back to where the COOKIE ECHO came from.] + */ + if (NULL != retval && NULL != chunk) { + retval->transport = chunk->transport; + } + + return retval; + +} /* sctp_make_cookie_ack() */ + +/* + * Appendix A: Explicit Congestion Notification: + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in the header of + * its next outbound TCP segment to indicate to its peer that it has + * reduced its congestion window. This is termed the CWR bit. For + * SCTP the same indication is made by including the CWR chunk. + * This chunk contains one data element, i.e. the TSN number that + * was sent in the ECNE chunk. This element represents the lowest + * TSN number in the datagram that was originally marked with the + * CE bit. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Chunk Type=13 | Flags=00000000| Chunk Length = 8 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Lowest TSN Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Note: The CWR is considered a Control chunk. + */ +sctp_chunk_t * +sctp_make_cwr(const sctp_association_t *asoc, const uint32_t lowest_tsn, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + sctp_cwrhdr_t cwr; + + cwr.lowest_tsn = htonl(lowest_tsn); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, + sizeof(sctp_cwrhdr_t)); + + if (NULL == retval) { goto nodata; } + retval->subh.ecn_cwr_hdr = + sctp_addto_chunk(retval, sizeof(cwr), &cwr); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [Report a reduced congestion window back to where the ECNE + * came from.] + */ + if (NULL != chunk) { + retval->transport = chunk->transport; + } + + nodata: + return retval; + +} /* sctp_make_cwr() */ + +/* Make an ECNE chunk. This is a congestion experienced report. */ +sctp_chunk_t * +sctp_make_ecne(const sctp_association_t *asoc, const uint32_t lowest_tsn) +{ + sctp_chunk_t *retval; + sctp_ecnehdr_t ecne; + + ecne.lowest_tsn = htonl(lowest_tsn); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, + sizeof(sctp_ecnehdr_t)); + if (NULL == retval) { goto nodata; } + retval->subh.ecne_hdr = + sctp_addto_chunk(retval, sizeof(ecne), &ecne); + +nodata: + return retval; + +} /* sctp_make_ecne() */ + + +/* Make a DATA chunk for the given association from the provided + * parameters. However, do not populate the data payload. + */ +sctp_chunk_t * +sctp_make_datafrag_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, uint8_t flags, uint16_t ssn) +{ + sctp_chunk_t *retval; + sctp_datahdr_t dp; + int chunk_len; + + retval = NULL; + + /* We assign the TSN as LATE as possible, not here when + * creating the chunk. + */ + dp.tsn= 1000000; /* This marker is a debugging aid. */ + dp.stream = htons(sinfo->sinfo_stream); + dp.ppid = htonl(sinfo->sinfo_ppid); + dp.ssn = htons(ssn); + + /* Set the flags for an unordered send. */ + if (sinfo->sinfo_flags & MSG_UNORDERED) { + flags |= SCTP_DATA_UNORDERED; + } + + chunk_len = sizeof(dp) + data_len; + + retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); + if (NULL == retval) { goto nodata; } + + retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); + memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); + +nodata: + return retval; + +} /* sctp_make_datafrag_empty() */ + +/* Make a DATA chunk for the given association. Populate the data + * payload. + */ +sctp_chunk_t * +sctp_make_datafrag(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const uint8_t *data, + uint8_t flags, uint16_t ssn) +{ + sctp_chunk_t *retval; + + retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); + if (NULL != retval) { + sctp_addto_chunk(retval, data_len, data); + } + + return retval; + +} /* sctp_make_datafrag() */ + +/* Make a DATA chunk for the given association to ride on stream id + * 'stream', with a payload id of 'payload', and a body of 'data'. + */ +sctp_chunk_t * +sctp_make_data(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const uint8_t *data) +{ + sctp_chunk_t *retval = NULL; + + retval = sctp_make_data_empty(asoc, sinfo, data_len); + + if (NULL != retval) { + sctp_addto_chunk(retval, data_len, data); + } + + return retval; + +} /* sctp_make_data() */ + +/* Make a DATA chunk for the given association to ride on stream id + * 'stream', with a payload id of 'payload', and a body big enough to + * hold 'data_len' octets of data. We use this version when we need + * to build the message AFTER allocating memory. + */ +sctp_chunk_t * +sctp_make_data_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len) +{ + sctp_chunk_t *retval; + uint16_t ssn; + uint8_t flags = SCTP_DATA_NOT_FRAG; + + /* Sockets API Extensions for SCTP 5.2.2 + * MSG_UNORDERED - This flag requests the un-ordered delivery of the + * message. If this flag is clear, the datagram is considered an + * ordered send and a new ssn is generated. The flags field is set + * in the inner routine - sctp_make_datafrag_empty(). + */ + if (sinfo->sinfo_flags & MSG_UNORDERED) { + ssn = 0; + } else { + ssn = __sctp_association_get_next_ssn(asoc, + sinfo->sinfo_stream); + } + + retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); + if (NULL == retval) { goto nodata; } + +nodata: + return retval; + +} /* sctp_make_data_empty() */ + +/* Create a selective ackowledgement (SACK) for the given + * association. This reports on which TSN's we've seen to date, + * including duplicates and gaps. + */ +sctp_chunk_t * +sctp_make_sack(const sctp_association_t *asoc) +{ + sctp_chunk_t *retval; + sctp_sackhdr_t sack; + sctp_gap_ack_block_t gab; + int length; + uint32_t ctsn; + sctp_tsnmap_iter_t iter; + uint16_t num_gabs; + uint16_t num_dup_tsns = asoc->peer.next_dup_tsn; + const sctp_tsnmap_t *map = &asoc->peer.tsn_map; + + ctsn = sctp_tsnmap_get_ctsn(map); + SCTP_DEBUG_PRINTK("make_sack: sackCTSNAck sent is 0x%x.\n", + ctsn); + + /* Count the number of Gap Ack Blocks. */ + sctp_tsnmap_iter_init(map, &iter); + for (num_gabs = 0; + sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); + num_gabs++) { + /* Do nothing. */ + } + + + /* Initialize the SACK header. */ + sack.cum_tsn_ack = htonl(ctsn); + sack.a_rwnd = htonl(asoc->rwnd); + sack.num_gap_ack_blocks = htons(num_gabs); + sack.num_dup_tsns = htons(num_dup_tsns); + + length = sizeof(sack) + + sizeof(sctp_gap_ack_block_t) * num_gabs + + sizeof(sctp_dup_tsn_t) * num_dup_tsns; + + /* Create the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); + if (NULL == retval) { goto nodata; } + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, etc.) to the same destination transport + * address from which it received the DATA or control chunk to + * which it is replying. This rule should also be followed if + * the endpoint is bundling DATA chunks together with the + * reply chunk. + * + * However, when acknowledging multiple DATA chunks received + * in packets from different source addresses in a single + * SACK, the SACK chunk may be transmitted to one of the + * destination transport addresses from which the DATA or + * control chunks being acknowledged were received. + * + * [BUG: We do not implement the following paragraph. + * Perhaps we should remember the last transport we used for a + * SACK and avoid that (if possible) if we have seen any + * duplicates. --piggy] + * + * When a receiver of a duplicate DATA chunk sends a SACK to a + * multi- homed endpoint it MAY be beneficial to vary the + * destination address and not use the source address of the + * DATA chunk. The reason being that receiving a duplicate + * from a multi-homed endpoint might indicate that the return + * path (as specified in the source address of the DATA chunk) + * for the SACK is broken. + * + * + * [Send to the address from which we last received a DATA chunk.] + */ + retval->transport = asoc->peer.last_data_from; + + retval->subh.sack_hdr = + sctp_addto_chunk(retval, sizeof(sack), &sack); + + /* Put the Gap Ack Blocks into the chunk. */ + sctp_tsnmap_iter_init(map, &iter); + while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { + gab.start = htons(gab.start); + gab.end = htons(gab.end); + sctp_addto_chunk(retval, + sizeof(sctp_gap_ack_block_t), + &gab); + } + + /* Register the duplicates. */ + sctp_addto_chunk(retval, + sizeof(sctp_dup_tsn_t) * num_dup_tsns, + &asoc->peer.dup_tsns); + nodata: + return retval; + +} /* sctp_make_sack() */ + +sctp_chunk_t * +sctp_make_shutdown(const sctp_association_t *asoc) +{ + sctp_chunk_t *retval; + sctp_shutdownhdr_t shut; + uint32_t ctsn; + + ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + shut.cum_tsn_ack = htonl(ctsn); + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, + sizeof(sctp_shutdownhdr_t)); + if (NULL == retval) { goto nodata; } + + retval->subh.shutdown_hdr = + sctp_addto_chunk(retval, sizeof(shut), &shut); + + nodata: + return retval; + +} /* sctp_make_shutdown() */ + +sctp_chunk_t * +sctp_make_shutdown_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ACK back to where the SHUTDOWN came from.] + */ + if (NULL != retval && NULL != chunk) { + retval->transport = chunk->transport; + } + + return retval; + +} /* sctp_make_shutdown_ack() */ + +sctp_chunk_t * +sctp_make_shutdown_complete(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_chunk_t *retval; + uint8_t flags = 0; + + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK + * came from.] + */ + if (NULL != retval && NULL != chunk) { + retval->transport = chunk->transport; + } + + return retval; + +} /* sctp_make_shutdown_complete() */ + +/* Create an ABORT. Note that we set the T bit if we have no + * association. + */ +sctp_chunk_t * +sctp_make_abort(const sctp_association_t *asoc, const sctp_chunk_t *chunk, + const size_t hint) +{ + sctp_chunk_t *retval; + uint8_t flags = 0; + + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + + retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ABORT back to where the offender came from.] + */ + if (NULL != retval && NULL != chunk) { + retval->transport = chunk->transport; + } + + return retval; + +} /* sctp_make_abort() */ + +/* Helper to create ABORT with a NO_USER_DATA error. */ +sctp_chunk_t * +sctp_make_abort_no_data(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, uint32_t tsn) +{ + sctp_chunk_t *retval; + uint32_t payload; + + retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + + sizeof(tsn)); + + if (!retval) { goto no_mem; } + + /* Put the tsn back into network byte order. */ + payload = htonl(tsn); + sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, + sizeof(payload)); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [ABORT back to where the offender came from.] + */ + if (chunk) { + retval->transport = chunk->transport; + } + +no_mem: + return retval; + +} /* sctp_make_abort_no_data() */ + + +/* Make a HEARTBEAT chunk. */ +sctp_chunk_t * +sctp_make_heartbeat(const sctp_association_t *asoc, + const sctp_transport_t *transport, + const void *payload, const size_t paylen) +{ + sctp_chunk_t *retval; + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, paylen); + if (NULL == retval) { goto nodata; } + + /* Cast away the 'const', as this is just telling the chunk + * what transport it belongs to. + */ + retval->transport = (sctp_transport_t *)transport; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + nodata: + return retval; + +} /* sctp_make_heartbeat() */ + +sctp_chunk_t * +sctp_make_heartbeat_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + const void *payload, const size_t paylen) +{ + sctp_chunk_t *retval; + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); + if (NULL == retval) { goto nodata; } + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + * [HBACK back to where the HEARTBEAT came from.] + */ + if (NULL != chunk) { + retval->transport = chunk->transport; + } + + nodata: + return retval; + +} /* sctp_make_heartbeat_ack() */ + + + +/* Create an Operation Error chunk. */ +sctp_chunk_t * +sctp_make_op_error(const sctp_association_t *asoc, const sctp_chunk_t *chunk, + uint16_t cause_code, const void *payload, size_t paylen) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, + sizeof(sctp_errhdr_t) + paylen); + if (NULL == retval) { goto nodata; } + + sctp_init_cause(retval, cause_code, payload, paylen); + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, * etc.) to the same destination transport + * address from which it * received the DATA or control chunk + * to which it is replying. + * + */ + if (NULL != chunk) { + retval->transport = chunk->transport; + } + + nodata: + return retval; + +} /* sctp_make_op_error() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + + +/* Turn an skb into a chunk. + * FIXME: Eventually move the structure directly inside the skb->cb[]. + */ +sctp_chunk_t * +sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, + struct sock *sk) +{ + sctp_chunk_t *retval; + + retval = t_new(sctp_chunk_t, GFP_ATOMIC); + if (NULL == retval) { goto nodata; } + memset(retval, 0, sizeof(sctp_chunk_t)); + + if (!sk) { + SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); + } + + retval->skb = skb; + retval->asoc = (sctp_association_t *)asoc; + retval->num_times_sent = 0; + retval->has_tsn = 0; + retval->rtt_in_progress = 0; + retval->sent_at = jiffies; + retval->singleton = 1; + retval->end_of_packet = 0; + retval->ecn_ce_done = 0; + retval->pdiscard = 0; + + /* sctpimpguide-05.txt Section 2.8.2 + * M1) Each time a new DATA chunk is transmitted + * set the 'TSN.Missing.Report' count for that TSN to 0. The + * 'TSN.Missing.Report' count will be used to determine missing chunks + * and when to fast retransmit. + */ + retval->tsn_missing_report = 0; + retval->tsn_gap_acked = 0; + retval->fast_retransmit = 0; + + /* Polish the bead hole. */ + INIT_LIST_HEAD(&retval->transmitted_list); + INIT_LIST_HEAD(&retval->frag_list); + SCTP_DBG_OBJCNT_INC(chunk); + + nodata: + return retval; + +} /* sctp_chunkify() */ + +/* Set chunk->source based on the IP header in chunk->skb. */ +void +sctp_init_source(sctp_chunk_t *chunk) +{ + sockaddr_storage_t *source; + struct sk_buff *skb; + struct sctphdr *sh; + struct iphdr *ih4; + struct ipv6hdr *ih6; + + source = &chunk->source; + skb = chunk->skb; + ih4 = skb->nh.iph; + ih6 = skb->nh.ipv6h; + sh = chunk->sctp_hdr; + + switch (ih4->version) { + case 4: + source->v4.sin_family = AF_INET; + source->v4.sin_port = ntohs(sh->source); + source->v4.sin_addr.s_addr = ih4->saddr; + break; + case 6: + SCTP_V6( + source->v6.sin6_family = AF_INET6; + source->v6.sin6_port = ntohs(sh->source); + source->v6.sin6_addr = ih6->saddr; + /* FIXME: What do we do with scope, etc. ? + */ + break; + ) + default: + /* This is a bogus address type, just bail. */ + break; + } /* switch (IP version of header) */ + +} /* sctp_init_source() */ + +/* Extract the source address from a chunk. */ +const sockaddr_storage_t * +sctp_source(const sctp_chunk_t *chunk) +{ + + /* If we have a known transport, use that. */ + if (chunk->transport) { + return &chunk->transport->ipaddr; + } else { + /* Otherwise, extract it from the IP header. */ + return &chunk->source; + } + +} /* sctp_source() */ + +/* Create a new chunk, setting the type and flags headers from the + * arguments, reserving enough space for a 'paylen' byte payload. + */ +sctp_chunk_t * +sctp_make_chunk(const sctp_association_t *asoc, uint8_t type, uint8_t flags, + int paylen) +{ + sctp_chunk_t *retval; + sctp_chunkhdr_t *chunk_hdr; + struct sk_buff *skb; + struct sock *sk; + + skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen)); + if (NULL == skb) { goto nodata; } + + /* Make room for the chunk header. */ + chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); + skb_pull(skb, sizeof(sctp_chunkhdr_t)); + + chunk_hdr->type = type; + chunk_hdr->flags = flags; + chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); + + /* Move the data pointer back up to the start of the chunk. */ + skb_push(skb, sizeof(sctp_chunkhdr_t)); + + sk = asoc ? asoc->base.sk : NULL; + retval = sctp_chunkify(skb, asoc, sk); + if (NULL == retval) { + dev_kfree_skb(skb); + goto nodata; + } + + retval->chunk_hdr = chunk_hdr; + retval->chunk_end = ((uint8_t *)chunk_hdr) + + sizeof(sctp_chunkhdr_t); + + /* Set the skb to the belonging sock for accounting. */ + skb->sk = sk; + + return retval; + nodata: + return NULL; + +} /* sctp_make_chunk() */ + +/* Release the memory occupied by a chunk. */ +void +sctp_free_chunk(sctp_chunk_t *chunk) +{ + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *)chunk); + list_del(&chunk->transmitted_list); + + /* Free the chunk skb data and the SCTP_chunk stub itself. */ + dev_kfree_skb(chunk->skb); + + kfree(chunk); + SCTP_DBG_OBJCNT_DEC(chunk); + +} /* sctp_free_chunk() */ + +/* Do a deep copy of a chunk. */ +sctp_chunk_t * +sctp_copy_chunk(sctp_chunk_t *chunk, const int priority) +{ + sctp_chunk_t *retval; + long offset; + + retval = t_new(sctp_chunk_t, priority); + if (NULL == retval) { goto nodata; } + + /* Do the shallow copy. */ + *retval = *chunk; + + /* Make sure that the copy does NOT think it is on any lists. */ + retval->next = NULL; + retval->prev = NULL; + retval->list = NULL; + INIT_LIST_HEAD(&retval->transmitted_list); + INIT_LIST_HEAD(&retval->frag_list); + + /* Now we copy the deep structure. */ + retval->skb = skb_copy(chunk->skb, priority); + if (NULL == retval->skb) { + kfree(retval); + goto nodata; + } + + /* Move the copy headers to point into the new skb. */ + offset = ((uint8_t *)retval->skb->head) + - ((uint8_t *)chunk->skb->head); + + if (NULL != retval->param_hdr.v) { + retval->param_hdr.v += offset; + } + if (NULL != retval->subh.v) { + (retval->subh.v) += offset; + } + if (NULL != retval->chunk_end) { + ((uint8_t *)retval->chunk_end) += offset; + } + if (NULL != retval->chunk_hdr) { + ((uint8_t *)retval->chunk_hdr) += offset; + } + if (NULL != retval->sctp_hdr) { + ((uint8_t *)retval->sctp_hdr) += offset; + } + SCTP_DBG_OBJCNT_INC(chunk); + return retval; + nodata: + return NULL; + +} /* sctp_copy_chunk() */ + + +/* Append bytes to the end of a chunk. Will panic if chunk is not big + * enough. + */ +void * +sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +{ + void *target; + void *padding; + int chunklen = ntohs(chunk->chunk_hdr->length); + int padlen = chunklen % 4; + + padding = skb_put(chunk->skb, padlen); + target = skb_put(chunk->skb, len); + + memset(padding, 0, padlen); + memcpy(target, data, len); + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = htons(chunklen + padlen + len); + chunk->chunk_end = chunk->skb->tail; + + return target; + +} /* sctp_addto_chunk() */ + +/* Append bytes from user space to the end of a chunk. Will panic if + * chunk is not big enough. + * Returns a kernel err value. + */ +int +sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data) +{ + uint8_t *target; + int err = 0; + + /* Make room in chunk for data */ + target = skb_put(chunk->skb, len); + + /* Copy data (whole iovec) into chunk */ + if ((err = memcpy_fromiovec(target, data, len))) { + goto out; + } + + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = + htons(ntohs(chunk->chunk_hdr->length) + len); + chunk->chunk_end = chunk->skb->tail; + +out: + return err; + +} /* sctp_user_addto_chunk() */ + +/* Helper function to assign a TSN if needed. This assumes that both + * the data_hdr and association have already been assigned. + */ +void +sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +{ + if (!chunk->has_tsn) { + /* This is the last possible instant to + * assign a TSN. + */ + chunk->subh.data_hdr->tsn = + htonl(__sctp_association_get_next_tsn(chunk->asoc)); + chunk->has_tsn = 1; + } + +} + + +/* Create a CLOSED association to use with an incoming packet. */ +sctp_association_t * +sctp_make_temp_asoc(const sctp_endpoint_t *ep, sctp_chunk_t *chunk, + int priority) +{ + sctp_association_t *asoc; + sctp_scope_t scope; + + /* Create the bare association. */ + scope = sctp_scope(sctp_source(chunk)); + asoc = sctp_association_new(ep, ep->base.sk, scope, priority); + if (NULL == asoc) { goto nodata; } + + /* Create an entry for the source address of the packet. */ + switch (chunk->skb->nh.iph->version) { + case 4: + asoc->c.peer_addr.v4.sin_family = AF_INET; + asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source); + asoc->c.peer_addr.v4.sin_addr.s_addr = + chunk->skb->nh.iph->saddr; + break; + case 6: + asoc->c.peer_addr.v6.sin6_family = AF_INET6; + asoc->c.peer_addr.v6.sin6_port + = ntohs(chunk->sctp_hdr->source); + asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */ + asoc->c.peer_addr.v6.sin6_addr = chunk->skb->nh.ipv6h->saddr; + asoc->c.peer_addr.v6.sin6_scope_id = 0; /* BUG BUG BUG */ + break; + default: + /* Yikes! I never heard of this kind of address. */ + goto fail; + } + +nodata: + return asoc; +fail: + sctp_association_free(asoc); + return NULL; + +} /* sctp_make_temp_asoc() */ + + +/* Build a cookie representing asoc. + * This INCLUDES the param header needed to put the cookie in the INIT ACK. + */ +sctp_cookie_param_t * +sctp_pack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, + const sctp_chunk_t *init_chunk, int *cookie_len, + const uint8_t *raw_addrs, int addrs_len) + +{ + sctp_cookie_param_t *retval; + sctp_signed_cookie_t *cookie; + int headersize, bodysize; + + headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; + bodysize = sizeof(sctp_cookie_t) + + ntohs(init_chunk->chunk_hdr->length) + addrs_len; + + + /* Pad out the cookie to a multiple to make the signature + * functions simpler to write. + */ + if (bodysize % SCTP_COOKIE_MULTIPLE) { + bodysize += SCTP_COOKIE_MULTIPLE + - (bodysize % SCTP_COOKIE_MULTIPLE); + } + *cookie_len = headersize + bodysize; + + retval = (sctp_cookie_param_t *) + kmalloc(*cookie_len, GFP_ATOMIC); + + if (NULL == retval) { + *cookie_len = 0; + goto nodata; + } + + /* Clear this memory since we are sending this data structure + * out on the network. + */ + + memset(retval, 0x00, *cookie_len); + + cookie = (sctp_signed_cookie_t *)retval->body; + + /* Set up the parameter header. */ + retval->p.type = SCTP_PARAM_STATE_COOKIE; + retval->p.length = htons(*cookie_len); + + /* Copy the cookie part of the association itself. */ + cookie->c = asoc->c; + /* Save the raw address list length in the cookie. */ + cookie->c.raw_addr_list_len = addrs_len; + + /* Set an expiration time for the cookie. */ + do_gettimeofday(&cookie->c.expiration); + tv_add(&asoc->cookie_life, &cookie->c.expiration); + + /* Copy the peer's init packet. */ + memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, + ntohs(init_chunk->chunk_hdr->length)); + + /* Copy the raw local address list of the association. */ + memcpy((uint8_t *)&cookie->c.peer_init[0] + + ntohs(init_chunk->chunk_hdr->length), raw_addrs, + addrs_len); + + /* Sign the message. */ + sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, + (uint8_t *)&cookie->c, bodysize, cookie->signature); + +nodata: + return retval; + +} /* sctp_pack_cookie() */ + +/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ +sctp_association_t * +sctp_unpack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, + sctp_chunk_t *chunk, int priority, int *error) +{ + sctp_association_t *retval = NULL; + sctp_signed_cookie_t *cookie; + sctp_cookie_t *bear_cookie; + int headersize, bodysize; + int fixed_size, var_size1, var_size2, var_size3; + uint8_t digest_buf[SCTP_SIGNATURE_SIZE]; + int secret; + sctp_scope_t scope; + uint8_t *raw_addr_list; + + headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; + bodysize = ntohs(chunk->chunk_hdr->length) - headersize; + fixed_size = headersize + sizeof(sctp_cookie_t); + + /* Verify that the chunk looks like it even has a cookie. + * There must be enough room for our cookie and our peer's + * INIT chunk. + */ + if (ntohs(chunk->chunk_hdr->length) < + (fixed_size + sizeof(sctp_chunkhdr_t))) { + goto malformed; + } + + /* Verify that the cookie has been padded out. */ + if (bodysize % SCTP_COOKIE_MULTIPLE) { + goto malformed; + } + + + /* Process the cookie. */ + cookie = chunk->subh.cookie_hdr; + bear_cookie = &cookie->c; + var_size1 = ntohs(chunk->chunk_hdr->length) - fixed_size; + var_size2 = ntohs(bear_cookie->peer_init->chunk_hdr.length); + var_size3 = bear_cookie->raw_addr_list_len; + + + /* Check the signature. */ + secret = ep->current_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (uint8_t *)bear_cookie, bodysize, + digest_buf); + if (memcmp(digest_buf, cookie->signature, + SCTP_SIGNATURE_SIZE)) { + + /* Try the previous key. */ + secret = ep->last_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (uint8_t *)bear_cookie, bodysize, digest_buf); + if (memcmp(digest_buf, cookie->signature, + SCTP_SIGNATURE_SIZE)) { + /* Yikes! Still bad signature! */ + *error = -SCTP_IERROR_BAD_SIG; + goto fail; + } + } /* if (the current secret failed) */ + + /* Check to see if the cookie is stale. If there is already + * an association, there is no need to check cookie's expiration + * for init collision case of lost COOKIE ACK. + */ + if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { + *error = -SCTP_IERROR_STALE_COOKIE; + goto fail; + } + + /* Make a new base association. */ + scope = sctp_scope(sctp_source(chunk)); + retval = sctp_association_new(ep, ep->base.sk, scope, priority); + if (NULL == retval) { + *error = -SCTP_IERROR_NOMEM; + goto fail; + } + + /* Set up our peer's port number. */ + retval->peer.port = ntohs(chunk->sctp_hdr->source); + + /* Populate the association from the cookie. */ + retval->c = *bear_cookie; + /* Build the bind address list based on the cookie */ + raw_addr_list = (uint8_t *)bear_cookie + + sizeof(sctp_cookie_t) + var_size2; + if (sctp_raw_to_bind_addrs(&retval->base.bind_addr, raw_addr_list, + var_size3, retval->base.bind_addr.port, + priority)) { + *error = -SCTP_IERROR_NOMEM; + goto fail; + } + + retval->next_tsn = retval->c.initial_tsn; + retval->ctsn_ack_point = retval->next_tsn - 1; + + /* The INIT stuff will be done by the side effects. */ + + return retval; + fail: + if (retval) { + sctp_association_free(retval); + } + + return NULL; + + malformed: + /* Yikes! The packet is either corrupt or deliberately + * malformed. + */ + *error = -SCTP_IERROR_MALFORMED; + goto fail; + +} /* sctp_unpack_cookie() */ + + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + +/* Unpack the parameters in an INIT packet. + * FIXME: There is no return status to allow callers to do + * error handling. + */ +void +sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, + const sockaddr_storage_t *peer_addr, + sctp_init_chunk_t *peer_init, + int priority) +{ + sctpParam_t param; + uint8_t *end; + sctp_transport_t *transport; + list_t *pos, *temp; + + /* We must include the address that the INIT packet came from. + * This is the only address that matters for an INIT packet. + * When processing a COOKIE ECHO, we retrieve the from address + * of the INIT from the cookie. + */ + + /* This implementation defaults to making the first transport + * added as the primary transport. The source address seems to + * be a a better choice than any of the embedded addresses. + */ + if (NULL != peer_addr) { + sctp_assoc_add_peer(asoc, peer_addr, priority); + } + + /* Process the initialization parameters. */ + + end = ((uint8_t *)peer_init + + ntohs(peer_init->chunk_hdr.length)); + + for (param.v = peer_init->init_hdr.params; + param.v < end; + param.v += WORD_ROUND(ntohs(param.p->length))) { + + if (!sctp_process_param(asoc, param, peer_addr, cid, + priority)) { + goto clean_up; + } + + } /* for (loop through all parameters) */ + + + /* The fixed INIT headers are always in network byte + * order. + */ + asoc->peer.i.init_tag = + ntohl(peer_init->init_hdr.init_tag); + asoc->peer.i.a_rwnd = + ntohl(peer_init->init_hdr.a_rwnd); + asoc->peer.i.num_outbound_streams = + ntohs(peer_init->init_hdr.num_outbound_streams); + asoc->peer.i.num_inbound_streams = + ntohs(peer_init->init_hdr.num_inbound_streams); + asoc->peer.i.initial_tsn = + ntohl(peer_init->init_hdr.initial_tsn); + + /* Apply the upper bounds for output streams based on peer's + * number of inbound streams. + */ + if (asoc->c.sinit_num_ostreams + > ntohs(peer_init->init_hdr.num_inbound_streams)) { + asoc->c.sinit_num_ostreams = + ntohs(peer_init->init_hdr.num_inbound_streams); + } + + /* Copy Initiation tag from INIT to VT_peer in cookie */ + asoc->c.peer_vtag = asoc->peer.i.init_tag; + + /* Peer Rwnd : Current calculated value of the peer's rwnd. */ + asoc->peer.rwnd = asoc->peer.i.a_rwnd; + + /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily + * high (for example, implementations MAY use the size of the receiver + * advertised window). + */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + transport->ssthresh = asoc->peer.i.a_rwnd; + } + + /* Set up the TSN tracking pieces. */ + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, + asoc->peer.i.initial_tsn); + + /* ADDIP Section 4.1 ASCONF Chunk Procedures + * + * When an endpoint has an ASCONF signaled change to be sent to the + * remote endpoint it should do the following: + * ... + * A2) A serial number should be assigned to the Chunk. The serial + * number should be a monotonically increasing number. All serial + * numbers are defined to be initialized at the start of the + * association to the same value as the Initial TSN. + */ + asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; + + return; + clean_up: + /* Release the transport structures. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, sctp_transport_t, transports); + list_del(pos); + sctp_transport_free(transport); + } + return; + +} /* sctp_process_init() */ + + +/* Update asoc with the option described in param. + * + * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT + * + * asoc is the association to update. + * param is the variable length parameter to use for update. + * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO. + * If the current packet is an INIT we want to minimize the amount of + * work we do. In particular, we should not build transport + * structures for the addresses. + */ +int +sctp_process_param(sctp_association_t *asoc, sctpParam_t param, + const sockaddr_storage_t *peer_addr, + sctp_cid_t cid, int priority) +{ + sockaddr_storage_t addr; + int j; + int i; + int retval = 1; + sctp_scope_t scope; + +/* We maintain all INIT parameters in network byte order all the + * time. This allows us to not worry about whether the parameters + * came from a fresh INIT, and INIT ACK, or were stored in a cookie. + */ + + switch (param.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + if (SCTP_CID_INIT != cid) { + sctp_param2sockaddr(&addr, param, asoc->peer.port); + scope = sctp_scope(peer_addr); + if (sctp_in_scope(&addr, scope)) { + sctp_assoc_add_peer(asoc, &addr, priority); + } + } + break; + case SCTP_PARAM_IPV6_ADDRESS: + if (SCTP_CID_INIT != cid) { + if (PF_INET6 == asoc->base.sk->family) { + sctp_param2sockaddr(&addr, param, + asoc->peer.port); + scope = sctp_scope(peer_addr); + if (sctp_in_scope(&addr, scope)) { + sctp_assoc_add_peer(asoc, &addr, + priority); + } + } + } + break; + case SCTP_PARAM_COOKIE_PRESERVATIVE: + asoc->cookie_preserve + = ntohl(param.bht->lifespan_increment); + break; + case SCTP_PARAM_HOST_NAME_ADDRESS: + SCTP_DEBUG_PRINTK("unimplmented SCTP_HOST_NAME_ADDRESS\n"); + break; + case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: + /* Turn off the default values first so we'll know which + * ones are really set by the peer. + */ + asoc->peer.ipv4_address = 0; + asoc->peer.ipv6_address = 0; + + j = (ntohs(param.p->length) + - sizeof(sctp_paramhdr_t)) + / sizeof(uint16_t); + for (i = 0; i < j; ++i) { + switch (param.sat->types[i]) { + case SCTP_PARAM_IPV4_ADDRESS: + asoc->peer.ipv4_address = 1; + break; + case SCTP_PARAM_IPV6_ADDRESS: + asoc->peer.ipv6_address = 1; + break; + case SCTP_PARAM_HOST_NAME_ADDRESS: + asoc->peer.hostname_address = 1; + break; + default: /* Just ignore anything else. */ + break; + } + } + break; + case SCTP_PARAM_STATE_COOKIE: + asoc->peer.cookie_len = + ntohs(param.p->length) + - sizeof(sctp_paramhdr_t); + asoc->peer.cookie = param.cookie->body; + break; + case SCTP_PARAM_HEATBEAT_INFO: + SCTP_DEBUG_PRINTK("unimplmented " + "SCTP_PARAM_HEATBEAT_INFO\n"); + break; + case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: + SCTP_DEBUG_PRINTK("unimplemented " + "SCTP_PARAM_UNRECOGNIZED_PARAMETERS\n"); + break; + case SCTP_PARAM_ECN_CAPABLE: + asoc->peer.ecn_capable = 1; + break; + default: + SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", + ntohs(param.p->type), asoc); + /* FIXME: The entire parameter processing really needs + * redesigned. For now, always return success as doing + * otherwise craters the system. + */ + retval = 1; + + break; + } + return retval; + +} /* sctp_process_param() */ + +/* Select a new verification tag. */ +uint32_t +sctp_generate_tag(const sctp_endpoint_t *ep) +{ + /* I believe that this random number generator complies with RFC1750. + * A tag of 0 is reserved for special cases (e.g. INIT). + */ + uint32_t x; + do { get_random_bytes(&x, sizeof(uint32_t)); } while( x==0 ); + return x; + +} /* sctp_generate_tag() */ + +/* Select an initial TSN to send during startup. */ +uint32_t +sctp_generate_tsn(const sctp_endpoint_t *ep) +{ + /* I believe that this random number generator complies with RFC1750. + */ + + uint32_t retval; + get_random_bytes(&retval, sizeof(uint32_t)); + + return retval; + +} /* sctp_generate_tsn() */ + +/******************************************************************** + * 4th Level Abstractions + ********************************************************************/ + +/* Convert from an SCTP IP parameter to a sockaddr_storage_t. */ +void +sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, + uint16_t port) +{ + switch(param.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = port; + addr->v4.sin_addr.s_addr = param.v4->addr.s_addr; + break; + case SCTP_PARAM_IPV6_ADDRESS: + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = port; + addr->v6.sin6_flowinfo = 0; /* BUG */ + addr->v6.sin6_addr = param.v6->addr; + addr->v6.sin6_scope_id = 0; /* BUG */ + break; + default: + SCTP_DEBUG_PRINTK("Illegal address type %d\n", + ntohs(param.p->type)); + break; + } +} /* sctp_param2sockaddr() */ + +/* Convert an IP address in an SCTP param into a sockaddr_in. */ +/* Returns true if a valid conversion was possible. */ +int +sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) +{ + if (NULL == p.v) { + return 0; + } + switch (p.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); + sa->v4.sin_family = AF_INET; + break; + case SCTP_PARAM_IPV6_ADDRESS: + *((struct in6_addr *)&sa->v4.sin_addr) + = p.v6->addr; + sa->v4.sin_family = AF_INET6; + break; + default: + return 0; + } + return 1; + +} /* sctp_addr2sockaddr() */ + +/* Convert from an IP version number to an Address Family symbol. */ +int ipver2af(uint8_t ipver) +{ + int family; + switch (ipver) { + case 4: + family = AF_INET; + break; + case 6: + family = AF_INET6; + break; + default: + family = 0; + break; + } /* switch (ipversion) */ + + return family; + +} /* ipver2af() */ + +/* Convert a sockaddr_in to IP address in an SCTP para. */ +/* Returns true if a valid conversion was possible. */ +int +sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctpParam_t p) +{ + int len = 0; + + switch (sa->v4.sin_family) { + case AF_INET: + p.p->type = SCTP_PARAM_IPV4_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv4addr_param_t)); + len = sizeof(sctp_ipv4addr_param_t); + p.v4->addr.s_addr = sa->v4.sin_addr.s_addr; + break; + case AF_INET6: + p.p->type = SCTP_PARAM_IPV6_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv6addr_param_t)); + len = sizeof(sctp_ipv6addr_param_t); + p.v6->addr = *(&sa->v6.sin6_addr); + break; + default: + printk(KERN_WARNING "sockaddr2sctp_addr: Illegal family %d.\n", + sa->v4.sin_family); + return 0; + } + + return len; + +} /* sockaddr2sctp_addr() */ diff --git a/net/sctp/sctp_sm_sideeffect.c b/net/sctp/sctp_sm_sideeffect.c new file mode 100644 index 000000000000..9cbafa30b839 --- /dev/null +++ b/net/sctp/sctp_sm_sideeffect.c @@ -0,0 +1,1280 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 1999 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_sideeffect.c,v 1.44 2002/08/16 19:30:50 jgrimm Exp $ + * + * These functions work with the state functions in sctp_sm_statefuns.c + * to implement that state operations. These functions implement the + * steps which require modifying existing data structures. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Hui Huang + * Dajiang Zhang + * Daisy Chang + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_sideeffect.c,v 1.44 2002/08/16 19:30:50 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Do forward declarations of static functions. */ +static void sctp_do_ecn_ce_work(sctp_association_t *asoc, + uint32_t lowest_tsn); +static +sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, + uint32_t lowest_tsn, + sctp_chunk_t *); +static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, + uint32_t lowest_tsn); + +static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, + sctp_transport_t *transport); +static void +sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); + +static void +sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); + +static void +sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, + sctp_chunk_t *chunk, sctp_init_chunk_t *peer_init, + int priority); +static void +sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); +static void +sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, + sctp_bind_addr_t *); + +static void +sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *); +static void +sctp_cmd_transport_on(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *, sctp_chunk_t *); +static int +sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, + sctp_sackhdr_t *); + +static void +sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, sctp_chunk_t *); + + +/* These three macros allow us to pull the debugging code out of the + * main flow of sctp_do_sm() to keep attention focused on the real + * functionality there. + */ +#define DEBUG_PRE \ + SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \ + "ep %p, %s, %s, asoc %p[%s], %s\n", \ + ep, sctp_evttype_tbl[event_type], \ + (*debug_fn)(subtype), asoc, \ + sctp_state_tbl[state], state_fn->name) + +#define DEBUG_POST \ + SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \ + "asoc %p, status: %s\n", \ + asoc, sctp_status_tbl[status]) + +#define DEBUG_POST_SFX \ + SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \ + error, asoc, \ + sctp_state_tbl[sctp_id2assoc(ep->base.sk, \ + sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED]) + + +/* + * This is the master state machine processing function. + * + * If you want to understand all of lksctp, this is a + * good place to start. + */ +int +sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + int priority) +{ + sctp_cmd_seq_t commands; + sctp_sm_table_entry_t *state_fn; + sctp_disposition_t status; + int error = 0; + typedef const char *(printfn_t)(sctp_subtype_t); + + static printfn_t *table[] = { + NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname, + }; + printfn_t *debug_fn __attribute__ ((unused)) = table[event_type]; + + /* Look up the state function, run it, and then process the + * side effects. These three steps are the heart of lksctp. + */ + + state_fn = sctp_sm_lookup_event(event_type, state, subtype); + + sctp_init_cmd_seq(&commands); + + DEBUG_PRE; + status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands); + DEBUG_POST; + + error = sctp_side_effects(event_type, subtype, state, + ep, asoc, event_arg, + status, &commands, + priority); + DEBUG_POST_SFX; + + return error; + +} /* sctp_do_sm() */ + +#undef DEBUG_PRE +#undef DEBUG_POST + +/***************************************************************** + * This the master state function side effect processing function. + *****************************************************************/ +int +sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *commands, + int priority) +{ + int error; + sctp_chunk_t *chunk; + chunk = (sctp_chunk_t *)event_arg; + + /* FIXME - Most of the dispositions left today would be categorized + * as "exceptional" dispositions. For those dispositions, it + * may not be proper to run through any of the commands at all. + * For example, the command interpreter might be run only with + * disposition SCTP_DISPOSITION_CONSUME. + */ + if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, + ep, asoc, + event_arg, status, + commands, priority))) { + goto bail; + } + + switch (status) { + case SCTP_DISPOSITION_DISCARD: + SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + break; + case SCTP_DISPOSITION_NOMEM: + /* We ran out of memory, so we need to discard this + * packet. + */ + /* BUG--we should now recover some memory, probably by + * reneging... + */ + break; + case SCTP_DISPOSITION_DELETE_TCB: + /* This should now be a command. */ + break; + case SCTP_DISPOSITION_CONSUME: + case SCTP_DISPOSITION_ABORT: + /* + * We should no longer have much work to do here as the + * real work has been done as explicit commands above. + */ + break; + case SCTP_DISPOSITION_VIOLATION: + printk(KERN_ERR "sctp protocol violation state %d " + "chunkid %d\n", state, subtype.chunk); + break; + case SCTP_DISPOSITION_NOT_IMPL: + printk(KERN_WARNING "sctp unimplemented feature in state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + + break; + case SCTP_DISPOSITION_BUG: + printk(KERN_ERR "sctp bug in state %d, " + "event_type %d, event_id %d\n", + state, event_type, subtype.chunk); + BUG(); + break; + default: + printk(KERN_ERR "sctp impossible disposition %d " + "in state %d, event_type %d, event_id %d\n", + status, state, event_type, subtype.chunk); + BUG(); + break; + } /* switch (status) */ + + bail: + return error; + +} /* sctp_side_effects() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* This is the side-effect interpreter. */ +int +sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, sctp_endpoint_t *ep, + sctp_association_t *asoc, void *event_arg, + sctp_disposition_t status, sctp_cmd_seq_t *commands, + int priority) +{ + int error = 0; + int force; + sctp_cmd_t *command; + sctp_chunk_t *new_obj; + sctp_chunk_t *chunk; + sctp_packet_t *packet; + struct timer_list *timer; + unsigned long timeout; + sctp_transport_t *t; + sctp_sackhdr_t sackh; + + + chunk = (sctp_chunk_t *)event_arg; + + /* Note: This whole file is a huge candidate for rework. + * For example, each command could either have its own handler, so + * the loop would look like: + * while (cmds) + * cmd->handle(x, y, z) + * --jgrimm + */ + + while (NULL != (command = sctp_next_cmd(commands))) { + switch (command->verb) { + case SCTP_CMD_NOP: + /* Do nothing. */ + break; + + case SCTP_CMD_NEW_ASOC: + /* Register a new association. */ + asoc = command->obj.ptr; + /* Register with the endpoint. */ + sctp_endpoint_add_asoc(ep, asoc); + sctp_hash_established(asoc); + break; + + case SCTP_CMD_UPDATE_ASSOC: + sctp_assoc_update(asoc, command->obj.ptr); + break; + + case SCTP_CMD_PURGE_OUTQUEUE: + sctp_outqueue_teardown(&asoc->outqueue); + break; + + case SCTP_CMD_DELETE_TCB: + /* Delete the current association. */ + sctp_unhash_established(asoc); + sctp_association_free(asoc); + asoc = NULL; + break; + + case SCTP_CMD_NEW_STATE: + /* Enter a new state. */ + asoc->state = command->obj.state; + asoc->state_timestamp = jiffies; + break; + + case SCTP_CMD_REPORT_TSN: + /* Record the arrival of a TSN. */ + sctp_tsnmap_mark(&asoc->peer.tsn_map, + command->obj.u32); + break; + + case SCTP_CMD_GEN_SACK: + /* Generate a Selective ACK. + * The argument tells us whether to just count + * the packet and MAYBE generate a SACK, or + * force a SACK out. + */ + force = command->obj.i32; + error = sctp_gen_sack(asoc, force, commands); + break; + + case SCTP_CMD_PROCESS_SACK: + /* Process an inbound SACK. */ + error = sctp_cmd_process_sack(commands, asoc, + command->obj.ptr); + break; + + + case SCTP_CMD_GEN_INIT_ACK: + /* Generate an INIT ACK chunk. */ + new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC); + if (!new_obj) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_PEER_INIT: + /* Process a unified INIT from the peer. */ + sctp_cmd_process_init(commands, + asoc, chunk, command->obj.ptr, + priority); + break; + + case SCTP_CMD_GEN_COOKIE_ECHO: + /* Generate a COOKIE ECHO chunk. */ + new_obj = sctp_make_cookie_echo(asoc, chunk); + if (!new_obj) { goto nomem; } + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_GEN_SHUTDOWN: + /* Generate SHUTDOWN when in SHUTDOWN_SENT state. + * Reset error counts. + */ + asoc->overall_error_count = 0; + + + /* Generate a SHUTDOWN chunk. */ + new_obj = sctp_make_shutdown(asoc); + if (!new_obj) { goto nomem; } + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + break; + + case SCTP_CMD_CHUNK_ULP: + /* Send a chunk to the sockets layer. */ + SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", + "chunk_up:", + command->obj.ptr, + "ulpq:", + &asoc->ulpq); + sctp_ulpqueue_tail_data(&asoc->ulpq, + command->obj.ptr, + GFP_ATOMIC); + break; + + case SCTP_CMD_EVENT_ULP: + /* Send a notification to the sockets layer. */ + SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", + "event_up:", + command->obj.ptr, + "ulpq:", + &asoc->ulpq); + sctp_ulpqueue_tail_event(&asoc->ulpq, + command->obj.ptr); + break; + + case SCTP_CMD_REPLY: + /* Send a chunk to our peer. */ + error = sctp_push_outqueue(&asoc->outqueue, + command->obj.ptr); + break; + + case SCTP_CMD_SEND_PKT: + /* Send a full packet to our peer. */ + packet = command->obj.ptr; + sctp_packet_transmit(packet); + sctp_transport_free(packet->transport); + sctp_packet_free(packet); + break; + + case SCTP_CMD_RETRAN: + /* Mark a transport for retransmission. */ + sctp_retransmit(&asoc->outqueue, + command->obj.transport, 0); + break; + + case SCTP_CMD_TRANSMIT: + /* Kick start transmission. */ + error = sctp_flush_outqueue(&asoc->outqueue, 0); + break; + + case SCTP_CMD_ECN_CE: + /* Do delayed CE processing. */ + sctp_do_ecn_ce_work(asoc, command->obj.u32); + break; + + case SCTP_CMD_ECN_ECNE: + /* Do delayed ECNE processing. */ + new_obj = sctp_do_ecn_ecne_work(asoc, + command->obj.u32, + chunk); + if (new_obj) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(new_obj)); + } + break; + + case SCTP_CMD_ECN_CWR: + /* Do delayed CWR processing. */ + sctp_do_ecn_cwr_work(asoc, command->obj.u32); + break; + + case SCTP_CMD_SETUP_T2: + sctp_cmd_setup_t2(commands, asoc, command->obj.ptr); + break; + + case SCTP_CMD_TIMER_START: + timer = &asoc->timers[command->obj.to]; + timeout = asoc->timeouts[command->obj.to]; + if (0 == timeout) { BUG(); } + + timer->expires = jiffies + timeout; + sctp_association_hold(asoc); + add_timer(timer); + break; + + case SCTP_CMD_TIMER_RESTART: + timer = &asoc->timers[command->obj.to]; + timeout = asoc->timeouts[command->obj.to]; + + if (!mod_timer(timer, jiffies + timeout)) { + sctp_association_hold(asoc); + } + break; + + case SCTP_CMD_TIMER_STOP: + timer = &asoc->timers[command->obj.to]; + if (timer_pending(timer) && del_timer(timer)) { + sctp_association_put(asoc); + } + break; + + case SCTP_CMD_INIT_RESTART: + /* Do the needed accounting and updates + * associated with restarting an initialization + * timer. + */ + asoc->counters[SCTP_COUNTER_INIT_ERROR]++; + asoc->timeouts[command->obj.to] *= 2; + + if (asoc->timeouts[command->obj.to] + > asoc->max_init_timeo) { + asoc->timeouts[command->obj.to] + = asoc->max_init_timeo; + } + + sctp_add_cmd_sf(commands, + SCTP_CMD_TIMER_RESTART, + SCTP_TO(command->obj.to)); + + break; + + case SCTP_CMD_INIT_FAILED: + sctp_cmd_init_failed(commands, asoc); + break; + + case SCTP_CMD_ASSOC_FAILED: + sctp_cmd_assoc_failed(commands, asoc); + break; + + case SCTP_CMD_COUNTER_INC: + asoc->counters[command->obj.counter]++; + break; + + case SCTP_CMD_COUNTER_RESET: + asoc->counters[command->obj.counter]=0; + break; + + case SCTP_CMD_REPORT_DUP: + if (asoc->peer.next_dup_tsn < SCTP_MAX_DUP_TSNS) { + asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] + = ntohl(command->obj.u32); + } + break; + + case SCTP_CMD_REPORT_BIGGAP: + SCTP_DEBUG_PRINTK("Big gap: %x to %x\n", + sctp_tsnmap_get_ctsn( + &asoc->peer.tsn_map), + command->obj.u32); + break; + case SCTP_CMD_REPORT_BAD_TAG: + SCTP_DEBUG_PRINTK("vtag mismatch!\n"); + break; + + case SCTP_CMD_SET_BIND_ADDR: + sctp_cmd_set_bind_addrs(commands, asoc, + command->obj.bp); + break; + + case SCTP_CMD_STRIKE: + /* Mark one strike against a transport. */ + sctp_do_8_2_transport_strike(asoc, + command->obj.transport); + break; + + case SCTP_CMD_TRANSPORT_RESET: + t = command->obj.transport; + sctp_cmd_transport_reset(commands, asoc, t); + break; + + case SCTP_CMD_TRANSPORT_ON: + t = command->obj.transport; + sctp_cmd_transport_on(commands, asoc, t, chunk); + break; + + case SCTP_CMD_HB_TIMERS_START: + sctp_cmd_hb_timers_start(commands, asoc); + break; + + case SCTP_CMD_REPORT_ERROR: + error = command->obj.error; + break; + + case SCTP_CMD_PROCESS_CTSN: + /* Dummy up a SACK for processing. */ + sackh.cum_tsn_ack = command->obj.u32; + sackh.a_rwnd = 0; + sackh.num_gap_ack_blocks = 0; + sackh.num_dup_tsns = 0; + sctp_add_cmd_sf(commands, + SCTP_CMD_PROCESS_SACK, + SCTP_SACKH(&sackh)); + break; + + case SCTP_CMD_DISCARD_PACKET: + /* We need to discard the whole packet. */ + chunk->pdiscard = 1; + break; + + default: + printk(KERN_WARNING "Impossible command: %u, %p\n", + command->verb, command->obj.ptr); + break; + } /* switch (cmd->verb) */ + } /* while (more commands) */ + + return error; + +nomem: + error = -ENOMEM; + return error; + +} /* sctp_cmd_interpreter() */ + + +/* A helper function for delayed processing of INET ECN CE bit. */ +static void +sctp_do_ecn_ce_work(sctp_association_t *asoc, uint32_t lowest_tsn) +{ + /* + * Save the TSN away for comparison when we receive CWR + * Note: dp->TSN is expected in host endian + */ + + asoc->last_ecne_tsn = lowest_tsn; + asoc->need_ecne = 1; + +} /* void sctp_do_ecn_ce_work(asoc, command) */ + + +/* Helper function for delayed processing of SCTP ECNE chunk. */ +/* RFC 2960 Appendix A + * + * RFC 2481 details a specific bit for a sender to send in + * the header of its next outbound TCP segment to indicate to + * its peer that it has reduced its congestion window. This + * is termed the CWR bit. For SCTP the same indication is made + * by including the CWR chunk. This chunk contains one data + * element, i.e. the TSN number that was sent in the ECNE chunk. + * This element represents the lowest TSN number in the datagram + * that was originally marked with the CE bit. + */ +static sctp_chunk_t * +sctp_do_ecn_ecne_work(sctp_association_t *asoc, + uint32_t lowest_tsn, + sctp_chunk_t *chunk) +{ + + sctp_chunk_t *repl; + sctp_transport_t *transport; + + + /* Our previously transmitted packet ran into some congestion + * so we should take action by reducing cwnd and ssthresh + * and then ACK our peer that we we've done so by + * sending a CWR. + */ + + + /* Find which transport's congestion variables + * need to be adjusted. + */ + + transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn); + + /* Update the congestion variables. */ + + if (transport) { + sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE); + } + + /* Save away a rough idea of when we last sent out a CWR. + * We compare against this value (see above) to decide if + * this is a fairly new request. + * Note that this is not a perfect solution. We may + * have moved beyond the window (several times) by the + * next time we get an ECNE. However, it is cute. This idea + * came from Randy's reference code. + * + * Here's what RFC 2960 has to say about CWR. This is NOT + * what we do. + * + * RFC 2960 Appendix A + * + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in + * the header of its next outbound TCP segment to indicate + * to its peer that it has reduced its congestion window. + * This is termed the CWR bit. For SCTP the same + * indication is made by including the CWR chunk. This + * chunk contains one data element, i.e. the TSN number + * that was sent in the ECNE chunk. This element + * represents the lowest TSN number in the datagram that + * was originally marked with the CE bit. + */ + asoc->last_cwr_tsn = asoc->next_tsn - 1; + + repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); + + /* If we run out of memory, it will look like a lost CWR. We'll + * get back in sync eventually. + */ + + return repl; + +} /* sctp_chunk_t *sctp_do_ecn_ecne_work(asoc, command) */ + +/* Helper function to do delayed processing of ECN CWR chunk */ +static void +sctp_do_ecn_cwr_work(sctp_association_t *asoc, + uint32_t lowest_tsn) +{ + + /* Turn off ECNE getting auto-prepended to every outgoing + * packet + */ + + asoc->need_ecne = 0; + +} /* void sctp_do_ecn_cwr_work(asoc, command) */ + +/* This macro is to compress the text a bit... */ +#define AP(v) asoc->peer.v + +/* Generate SACK if necessary. We call this at the end of a packet. */ +int +sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands) +{ + uint32_t ctsn, max_tsn_seen; + sctp_chunk_t *sack; + int error = 0; + + if (force) { + asoc->peer.sack_needed = 1; + } + + ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); + max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map); + + /* From 12.2 Parameters necessary per association (i.e. the TCB): + * + * Ack State : This flag indicates if the next received packet + * : is to be responded to with a SACK. ... + * : When DATA chunks are out of order, SACK's + * : are not delayed (see Section 6). + * + * [This is actually not mentioned in Section 6, but we + * implement it here anyway. --piggy] + */ + if (max_tsn_seen != ctsn) { + asoc->peer.sack_needed = 1; + } + + /* From 6.2 Acknowledgement on Reception of DATA Chunks: + * + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, + * an acknowledgement SHOULD be generated for at least every + * second packet (not every second DATA chunk) received, and + * SHOULD be generated within 200 ms of the arrival of any + * unacknowledged DATA chunk. ... + */ + if (!asoc->peer.sack_needed) { + /* We will need a SACK for the next packet. */ + asoc->peer.sack_needed = 1; + goto out; + } else { + sack = sctp_make_sack(asoc); + if (NULL == sack) { goto nomem; } + + asoc->peer.sack_needed = 0; + asoc->peer.next_dup_tsn = 0; + + error = sctp_push_outqueue(&asoc->outqueue, sack); + + /* Stop the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + + } /* else (we needed a sack) */ + + out: + return error; + nomem: + error = -ENOMEM; + return error; + +} /* sctp_gen_sack() */ + +/* Handle a duplicate TSN. */ +void +sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, + long gap) +{ +#if 0 + sctp_chunk_t *sack; + + /* Caution: gap < 2 * SCTP_TSN_MAP_SIZE + * so gap can be negative. + * + * --xguo + */ + + /* Count this TSN. */ + if (gap < SCTP_TSN_MAP_SIZE) { + asoc->peer.tsn_map[gap]++; + } else { + asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++; + } + + /* From 6.2 Acknowledgement on Reception of DATA Chunks + * + * When a packet arrives with duplicate DATA chunk(s) + * and with no new DATA chunk(s), the endpoint MUST + * immediately send a SACK with no delay. If a packet + * arrives with duplicate DATA chunk(s) bundled with + * new DATA chunks, the endpoint MAY immediately send a + * SACK. Normally receipt of duplicate DATA chunks + * will occur when the original SACK chunk was lost and + * the peer's RTO has expired. The duplicate TSN + * number(s) SHOULD be reported in the SACK as + * duplicate. + */ + asoc->counters[SctpCounterAckState] = 2; +#endif /* 0 */ +} /* sctp_do_TSNdup() */ + +#undef AP + +/* When the T3-RTX timer expires, it calls this function to create the + * relevant state machine event. + */ +void +sctp_generate_t3_rtx_event(unsigned long peer) +{ + int error; + sctp_transport_t *transport = (sctp_transport_t *)peer; + sctp_association_t *asoc = transport->asoc; + + /* Check whether a task is in the sock. */ + + sctp_bh_lock_sock(asoc->base.sk); + + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK(__FUNCTION__ ":Sock is busy.\n"); + + /* Try again later. */ + if (!mod_timer(&transport->T3_rtx_timer, + jiffies + (HZ/20))) { + sctp_transport_hold(transport); + } + goto out_unlock; + } + + /* Is this transport really dead and just waiting around for + * the timer to let go of the reference? + */ + if (transport->dead) { + goto out_unlock; + } + + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX), + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); + + if (error) { + asoc->base.sk->err = -error; + } + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_transport_put(transport); + +} /* sctp_generate_t3_rtx_event() */ + + +/* This is a sa interface for producing timeout events. It works + * for timeouts which use the association as their parameter. + */ +static void +sctp_generate_timeout_event(sctp_association_t *asoc, + sctp_event_timeout_t timeout_type) +{ + int error = 0; + + sctp_bh_lock_sock(asoc->base.sk); + + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK(__FUNCTION__ "Sock is busy: timer %d\n", + timeout_type); + /* Try again later. */ + if (!mod_timer(&asoc->timers[timeout_type], + jiffies + (HZ/20))) { + sctp_association_hold(asoc); + } + goto out_unlock; + } + + /* Is this association really dead and just waiting around for + * the timer to let go of the reference? + */ + if (asoc->base.dead) { + goto out_unlock; + } + + /* Run through the state machine. */ + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(timeout_type), + asoc->state, asoc->ep, asoc, + (void *)timeout_type, + GFP_ATOMIC); + + if (error) { asoc->base.sk->err = -error; } + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_association_put(asoc); + +} /* sctp_generate_timeout_event() */ + +void +sctp_generate_t1_cookie_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); + +} /* sctp_generate_t1_cookie_event() */ + +void +sctp_generate_t1_init_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); + +} /* sctp_generate_t1_init_event() */ + +void +sctp_generate_t2_shutdown_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); + +} /* sctp_generate_t2_shutdown_event() */ + +void +sctp_generate_autoclose_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); + +} /* sctp_generate_autoclose_event() */ + +/* Generate a heart beat event. If the sock is busy, reschedule. Make + * sure that the transport is still valid. + */ +void +sctp_generate_heartbeat_event(unsigned long data) +{ + int error = 0; + sctp_transport_t *transport = (sctp_transport_t *)data; + sctp_association_t *asoc = transport->asoc; + + sctp_bh_lock_sock(asoc->base.sk); + if (__sctp_sock_busy(asoc->base.sk)) { + SCTP_DEBUG_PRINTK(__FUNCTION__ ":Sock is busy.\n"); + + /* Try again later. */ + if (!mod_timer(&transport->hb_timer, + jiffies + (HZ/20))) { + sctp_transport_hold(transport); + } + goto out_unlock; + } + + /* Is this structure just waiting around for us to actually + * get destroyed? + */ + if (transport->dead) { + goto out_unlock; + } + + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); + + if (error) { + + asoc->base.sk->err = -error; + } + + +out_unlock: + sctp_bh_unlock_sock(asoc->base.sk); + sctp_transport_put(transport); + +} /* sctp_generate_heartbeat_event() */ + +/* Inject a SACK Timeout event into the state machine. */ +void +sctp_generate_sack_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); + +} /* sctp_generate_sack_event() */ + +void +sctp_generate_pmtu_raise_event(unsigned long data) +{ + sctp_association_t *asoc = (sctp_association_t *)data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_PMTU_RAISE); +} /* sctp_generate_pmtu_raise_event() */ + +sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { + NULL, + sctp_generate_t1_cookie_event, + sctp_generate_t1_init_event, + sctp_generate_t2_shutdown_event, + NULL, + NULL, + sctp_generate_heartbeat_event, + sctp_generate_sack_event, + sctp_generate_autoclose_event, + sctp_generate_pmtu_raise_event, +}; + +/******************************************************************** + * 3rd Level Abstractions + ********************************************************************/ + + +/* RFC 2960 8.2 Path Failure Detection + * + * When its peer endpoint is multi-homed, an endpoint should keep a + * error counter for each of the destination transport addresses of the + * peer endpoint. + * + * Each time the T3-rtx timer expires on any address, or when a + * HEARTBEAT sent to an idle address is not acknowledged within a RTO, + * the error counter of that destination address will be incremented. + * When the value in the error counter exceeds the protocol parameter + * 'Path.Max.Retrans' of that destination address, the endpoint should + * mark the destination transport address as inactive, and a + * notification SHOULD be sent to the upper layer. + * + * + */ + +static void +sctp_do_8_2_transport_strike(sctp_association_t *asoc, + sctp_transport_t *transport) +{ + /* The check for association's overall error counter exceeding the + * threshold is done in the state function. + */ + asoc->overall_error_count++; + + if ( transport->state.active + && (transport->error_count++ >= transport->error_threshold) ) { + SCTP_DEBUG_PRINTK("transport_strike: transport " + "IP:%d.%d.%d.%d failed.\n", + NIPQUAD(transport->ipaddr.v4.sin_addr)); + sctp_assoc_control_transport(asoc, transport, + SCTP_TRANSPORT_DOWN, + SCTP_FAILED_THRESHOLD); + } + + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ + transport->rto = min((transport->rto * 2), transport->asoc->rto_max); + +} /* sctp_do_8_2_transport_strike() */ + +/* Worker routine to handle INIT command failure. */ +static void +sctp_cmd_init_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + event = sctp_ulpevent_make_assoc_change(asoc, + 0, + SCTP_CANT_STR_ASSOC, + 0, 0, 0, + GFP_ATOMIC); + + if (event) { + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(event)); + } + + /* FIXME: We need to handle data possibly either + * sent via COOKIE-ECHO bundling or just waiting in + * the transmit queue, if the user has enabled + * SEND_FAILED notifications. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return; + +} /* sctp_cmd_init_failed() */ + + +/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */ +static void +sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + event = sctp_ulpevent_make_assoc_change(asoc, + 0, + SCTP_COMM_LOST, + 0, 0, 0, + GFP_ATOMIC); + + if (event) { + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(event)); + } + + /* FIXME: We need to handle data that could not be sent or was not + * acked, if the user has enabled SEND_FAILED notifications. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return; + +} /* sctp_cmd_assoc_failed() */ + +/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT + * inside the cookie. + */ +static void +sctp_cmd_process_init(sctp_cmd_seq_t *commands, sctp_association_t *asoc, + sctp_chunk_t *chunk, sctp_init_chunk_t *peer_init, + int priority) +{ + /* The command sequence holds commands assuming that the + * processing will happen successfully. If this is not the + * case, rewind the sequence and add appropriate error handling + * to the sequence. + */ + sctp_process_init(asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, + priority); + + +} /* sctp_cmd_process_init() */ + +/* Helper function to break out starting up of heartbeat timers. */ +static void +sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, sctp_association_t *asoc) +{ + sctp_transport_t *t; + list_t *pos; + + /* Start a heartbeat timer for each transport on the association. + * hold a reference on the transport to make sure none of + * the needed data structures go away. + */ + list_for_each(pos, &asoc->peer.transport_addr_list) { + t = list_entry(pos, sctp_transport_t, transports); + if (!mod_timer(&t->hb_timer, + t->hb_interval + t->rto + jiffies)) { + sctp_transport_hold(t); + } + } /* for (all transports) */ + +} /* sctp_cmd_hb_timers_start() */ + +/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ +void +sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_bind_addr_t *bp) +{ + list_t *pos, *temp; + + list_for_each_safe(pos, temp, &bp->address_list) { + list_del_init(pos); + list_add_tail(pos, &asoc->base.bind_addr.address_list); + } + + /* Free the temporary bind addr header, otherwise + * there will a memory leak. + */ + sctp_bind_addr_free(bp); + +} /* sctp_cmd_set_bind_addrs() */ + +/* Helper function to handle the reception of an HEARTBEAT ACK. */ +static void +sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_transport_t *t, sctp_chunk_t *chunk) +{ + sctp_sender_hb_info_t *hbinfo; + + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the + * HEARTBEAT should clear the error counter of the destination + * transport address to which the HEARTBEAT was sent. + * The association's overall error count is also cleared. + */ + t->error_count = 0; + t->asoc->overall_error_count = 0; + + /* Mark the destination transport address as active if it is not so + * marked. + */ + if (!t->state.active) { + sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, + SCTP_HEARTBEAT_SUCCESS); + } + + /* The receiver of the HEARTBEAT ACK should also perform an + * RTT measurement for that destination transport address + * using the time value carried in the HEARTBEAT ACK chunk. + */ + hbinfo = (sctp_sender_hb_info_t *)chunk->skb->data; + sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at)); + +} /* sctp_cmd_transport_on() */ + +/* Helper function to do a transport reset at the expiry of the hearbeat + * timer. + */ +static void +sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_transport_t *t) +{ + sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); + + /* Mark one strike against a transport. */ + sctp_do_8_2_transport_strike(asoc, t); + + /* Update the heartbeat timer. */ + if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) { + sctp_transport_hold(t); + } + +} /* sctp_cmd_transport_reset() */ + +/* Helper function to process the process SACK command. */ +static int +sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_sackhdr_t *sackh) +{ + int err; + + if (sctp_sack_outqueue(&asoc->outqueue, sackh)) { + /* There are no more TSNs awaiting SACK. */ + err = sctp_do_sm(SCTP_EVENT_T_OTHER, + SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), + asoc->state, asoc->ep, asoc, NULL, + GFP_ATOMIC); + } else { + /* Windows may have opened, so we need + * to check if we have DATA to transmit + */ + err = sctp_flush_outqueue(&asoc->outqueue, 0); + } + + return err; + +} /* sctp_cmd_process_sack() */ + + +/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set + * the transport for a shutdown chunk. + */ +static void +sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_chunk_t *chunk) +{ + sctp_transport_t *t; + + t = sctp_assoc_choose_shutdown_transport(asoc); + asoc->shutdown_last_sent_to = t; + asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; + chunk->transport = t; + + return; + +} /* sctp_cmd_setup_t2() */ + diff --git a/net/sctp/sctp_sm_statefuns.c b/net/sctp/sctp_sm_statefuns.c new file mode 100644 index 000000000000..54b7b19fd39f --- /dev/null +++ b/net/sctp/sctp_sm_statefuns.c @@ -0,0 +1,3825 @@ +/* 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) 2002 Nokia Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statefuns.c,v 1.48 2002/08/16 19:30:50 jgrimm Exp $ + * + * This is part of the SCTP Linux Kernel Reference Implementation. + * + * These are the state functions for the state machine. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Mathew Kotowsky + * Sridhar Samudrala + * Jon Grimm + * Hui Huang + * Dajiang Zhang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.48 2002/08/16 19:30:50 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef CONFIG_INET_ECN +#define CONFIG_INET_ECN +#endif /* CONFIG_INET_ECN */ +#include +#include +#include +#include +#include + + +/********************************************************** + * These are the state functions for handling chunk events. + **********************************************************/ + +/* + * Process the final SHUTDOWN COMPLETE. + * + * Section: 4 (C) (diagram), 9.2 + * Upon reception of the SHUTDOWN COMPLETE chunk the endpoint will verify + * that it is in SHUTDOWN-ACK-SENT state, if it is not the chunk should be + * discarded. If the endpoint is in the SHUTDOWN-ACK-SENT state the endpoint + * should stop the T2-shutdown timer and remove all knowledge of the + * association (and thus the association enters the CLOSED state). + * + * Verification Tag: 8.5.1(C) + * C) Rules for packet carrying SHUTDOWN COMPLETE: + * ... + * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the + * Verification Tag field of the packet matches its own tag OR it is + * set to its peer's tag and the T bit is set in the Chunk Flags. + * Otherwise, the receiver MUST silently discard the packet and take + * no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if + * it is not in the SHUTDOWN-ACK-SENT state. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_4_C(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_ulpevent_t *ev; + + /* RFC 2960 6.10 Bundling + * + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) { + return SCTP_DISPOSITION_VIOLATION; + } + + /* RFC 2960 8.5.1 Exceptions in Verification Tag Rules + * + * (C) The receiver of a SHUTDOWN COMPLETE shall accept the + * packet if the Verification Tag field of the packet + * matches its own tag OR it is set to its peer's tag and + * the T bit is set in the Chunk Flags. Otherwise, the + * receiver MUST silently discard the packet and take no + * further action.... + */ + if ((ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + && !(sctp_test_T_bit(chunk) + || (ntohl(chunk->sctp_hdr->vtag) + != asoc->peer.i.init_tag))) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + /* RFC 2960 10.2 SCTP-to-ULP + * + * H) SHUTDOWN COMPLETE notification + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, + 0, 0, 0, GFP_ATOMIC); + if (!ev) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + + /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint + * will verify that it is in SHUTDOWN-ACK-SENT state, if it is + * not the chunk should be discarded. If the endpoint is in + * the SHUTDOWN-ACK-SENT state the endpoint should stop the + * T2-shutdown timer and remove all knowledge of the + * association (and thus the association enters the CLOSED + * state). + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + + nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_4_C() */ + + +/* + * Discard the whole packet. + * + * Section: 8.4 2) + * + * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST + * silently discard the OOTB packet and take no further action. + * Otherwise, + * + * Verification Tag: No verification necessary + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_pdiscard(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_pdiscard() */ + + +/* + * Respond to a normal INIT chunk. + * We are the side that is being asked for an association. + * + * Section: 5.1 Normal Establishment of an Association, B + * B) "Z" shall respond immediately with an INIT ACK chunk. The + * destination IP address of the INIT ACK MUST be set to the source + * IP address of the INIT to which this INIT ACK is responding. In + * the response, besides filling in other parameters, "Z" must set the + * Verification Tag field to Tag_A, and also provide its own + * Verification Tag (Tag_Z) in the Initiate Tag field. + * + * Verification Tag: No checking. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *repl; + sctp_association_t *new_asoc; + + /* If the packet is an OOTB packet which is temporarily on the + * control endpoint, responding with an ABORT. + */ + + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { + return sctp_sf_ootb(ep, asoc, type, arg, commands); + } + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) { + return SCTP_DISPOSITION_VIOLATION; + } + + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + + /* Tag the variable length parameters. */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); + if (NULL == new_asoc) { goto nomem; } + + /* FIXME: sctp_process_init can fail, but there is no + * status nor handling. + */ + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + + /* B) "Z" shall respond immediately with an INIT ACK chunk. + */ + + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + if (!repl) { goto nomem_ack; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* + * Note: After sending out INIT ACK with the State Cookie parameter, + * "Z" MUST NOT allocate any resources, nor keep any states for the + * new association. Otherwise, "Z" will be vulnerable to resource + * attacks. + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + +nomem_ack: + sctp_association_free(new_asoc); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_5_1B_init() */ + +/* + * Respond to a normal INIT ACK chunk. + * We are the side that is initiating the association. + * + * Section: 5.1 Normal Establishment of an Association, C + * C) Upon reception of the INIT ACK from "Z", "A" shall stop the T1-init + * timer and leave COOKIE-WAIT state. "A" shall then send the State + * Cookie received in the INIT ACK chunk in a COOKIE ECHO chunk, start + * the T1-cookie timer, and enter the COOKIE-ECHOED state. + * + * Note: The COOKIE ECHO chunk can be bundled with any pending outbound + * DATA chunks, but it MUST be the first chunk in the packet and + * until the COOKIE ACK is returned the sender MUST NOT send any + * other packets to the peer. + * + * Verification Tag: 3.3.3 + * If the value of the Initiate Tag in a received INIT ACK chunk is + * found to be 0, the receiver MUST treat it as an error and close the + * association by transmitting an ABORT. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_init_chunk_t *initchunk; + uint32_t init_tag; + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) { + return SCTP_DISPOSITION_VIOLATION; + } + + /* Grab the INIT header. + */ + chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + + init_tag = ntohl(chunk->subh.init_hdr->init_tag); + + /* Verification Tag: 3.3.3 + * If the value of the Initiate Tag in a received INIT ACK + * chunk is found to be 0, the receiver MUST treat it as an + * error and close the association by transmitting an ABORT. + */ + if (0 == init_tag) { + sctp_chunk_t *reply; + reply = sctp_make_abort(asoc, chunk, 0); + if (!reply) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(reply)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* Tag the variable length paramters. Note that we never + * convert the parameters in an INIT chunk. + */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + initchunk = (sctp_init_chunk_t *)chunk->chunk_hdr; + + sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, + SCTP_PEER_INIT(initchunk)); + + + /* 5.1 C) "A" shall stop the T1-init timer and leave + * COOKIE-WAIT state. "A" shall then ... start the T1-cookie + * timer, and enter the COOKIE-ECHOED state. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, + SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); + + /* 5.1 C) "A" shall then send the State Cookie received in the + * INIT ACK chunk in a COOKIE ECHO chunk, ... + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, SCTP_NULL()); + + return SCTP_DISPOSITION_CONSUME; + nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_5_1C_ack() */ + +/* + * Respond to a normal COOKIE ECHO chunk. + * We are the side that is being asked for an association. + * + * Section: 5.1 Normal Establishment of an Association, D + * D) Upon reception of the COOKIE ECHO chunk, Endpoint "Z" will reply + * with a COOKIE ACK chunk after building a TCB and moving to + * the ESTABLISHED state. A COOKIE ACK chunk may be bundled with + * any pending DATA chunks (and/or SACK chunks), but the COOKIE ACK + * chunk MUST be the first chunk in the packet. + * + * IMPLEMENTATION NOTE: An implementation may choose to send the + * Communication Up notification to the SCTP user upon reception + * of a valid COOKIE ECHO chunk. + * + * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules + * D) Rules for packet carrying a COOKIE ECHO + * + * - When sending a COOKIE ECHO, the endpoint MUST use the value of the + * Initial Tag received in the INIT ACK. + * + * - The receiver of a COOKIE ECHO follows the procedures in Section 5. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_association_t *new_asoc; + sctp_init_chunk_t *peer_init; + sctp_chunk_t *repl; + sctp_ulpevent_t *ev; + int error = 0; + + /* If the packet is an OOTB packet which is temporarily on the + * control endpoint, responding with an ABORT. + */ + + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { + return sctp_sf_ootb(ep, asoc, type, arg, commands); + } + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ + chunk->subh.cookie_hdr = + (sctp_signed_cookie_t *)chunk->skb->data; + skb_pull(chunk->skb, + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + + /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint + * "Z" will reply with a COOKIE ACK chunk after building a TCB + * and moving to the ESTABLISHED state. + */ + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + + /* FIXME: + * If the re-build failed, what is the proper error path + * from here? + * + * [We should abort the association. --piggy] + */ + + if (!new_asoc) { + /* FIXME: Several errors are possible. A bad cookie should + * be silently discarded, but think about logging it too. + */ + switch (error) { + case -SCTP_IERROR_NOMEM: + goto nomem; + case -SCTP_IERROR_BAD_SIG: + default: + return sctp_sf_pdiscard(ep, asoc, type, + arg, commands); + } + + } + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + if (new_asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* Re-build the bind address for the association is done in + * the sctp_unpack_cookie() already. + */ + + /* This is a brand-new association, so these are not yet side + * effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + &chunk->subh.cookie_hdr->c.peer_addr, peer_init, + GFP_ATOMIC); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) { goto nomem_repl; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose to + * send the Communication Up notification to the SCTP user + * upon reception of a valid COOKIE ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + GFP_ATOMIC); + if (!ev) { goto nomem_ev; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + return SCTP_DISPOSITION_CONSUME; + +nomem_ev: + sctp_free_chunk(repl); +nomem_repl: + sctp_association_free(new_asoc); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_5_1D_ce() */ + + +/* + * Respond to a normal COOKIE ACK chunk. + * We are the side that is being asked for an association. + * + * RFC 2960 5.1 Normal Establishment of an Association + * + * E) Upon reception of the COOKIE ACK, endpoint "A" will move from the + * COOKIE-ECHOED state to the ESTABLISHED state, stopping the T1-cookie + * timer. It may also notify its ULP about the successful + * establishment of the association with a Communication Up + * notification (see Section 10). + * + * Verification Tag: + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_ulpevent_t *ev; + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * E) Upon reception of the COOKIE ACK, endpoint "A" will move + * from the COOKIE-ECHOED state to the ESTABLISHED state, + * stopping the T1-cookie timer. + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* It may also notify its ULP about the successful + * establishment of the association with a Communication Up + * notification (see Section 10). + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, + 0, asoc->c.sinit_num_ostreams, + asoc->c.sinit_max_instreams, + GFP_ATOMIC); + + if (!ev) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + return SCTP_DISPOSITION_CONSUME; + nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_5_1E_ca() */ + + +/* Generate a HEARTBEAT packet on the given transport. */ +sctp_disposition_t +sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = (sctp_transport_t *) arg; + sctp_chunk_t *reply; + sctp_sender_hb_info_t hbinfo; + size_t paylen = 0; + + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* Section 3.3.5. + * The Sender-specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent (see Section 8.3). + */ + + hbinfo.param_hdr.type = SCTP_PARAM_HEATBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; + + /* Set rto_pending indicating that an RTT measurement is started + * with this heartbeat chunk. + */ + transport->rto_pending = 1; + + /* Send a heartbeat to our peer. */ + + paylen = sizeof ( sctp_sender_hb_info_t ); + reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); + if (NULL == reply) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(reply)); + + /* Set transport error counter and association error counter + * when sending heartbeat. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, + SCTP_TRANSPORT(transport)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_sendbeat_8_3() */ + +/* + * Process an heartbeat request. + * + * Section: 8.3 Path Heartbeat + * The receiver of the HEARTBEAT should immediately respond with a + * HEARTBEAT ACK that contains the Heartbeat Information field copied + * from the received HEARTBEAT chunk. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * When receiving an SCTP packet, the endpoint MUST ensure that the + * value in the Verification Tag field of the received SCTP packet + * matches its own Tag. If the received Verification Tag value does not + * match the receiver's own tag value, the receiver shall silently + * discard the packet and shall not process it any further except for + * those cases listed in Section 8.5.1 below. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_beat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *reply; + size_t paylen = 0; + + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + /* 8.3 The receiver of the HEARTBEAT should immediately + * respond with a HEARTBEAT ACK that contains the Heartbeat + * Information field copied from the received HEARTBEAT chunk. + */ + + chunk->subh.hb_hdr = (sctp_heartbeathdr_t *)chunk->skb->data; + paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); + skb_pull(chunk->skb, paylen); + + reply = sctp_make_heartbeat_ack(asoc, chunk, + chunk->subh.hb_hdr, paylen); + if (NULL == reply) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; + nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_beat_8_3() */ + +/* + * Process the returning HEARTBEAT ACK. + * + * Section: 8.3 Path Heartbeat + * Upon the receipt of the HEARTBEAT ACK, the sender of the HEARTBEAT + * should clear the error counter of the destination transport + * address to which the HEARTBEAT was sent, and mark the destination + * transport address as active if it is not so marked. The endpoint may + * optionally report to the upper layer when an inactive destination + * address is marked as active due to the reception of the latest + * HEARTBEAT ACK. The receiver of the HEARTBEAT ACK must also + * clear the association overall error count as well (as defined + * in section 8.1). + * + * The receiver of the HEARTBEAT ACK should also perform an RTT + * measurement for that destination transport address using the time + * value carried in the HEARTBEAT ACK chunk. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sockaddr_storage_t from_addr; + sctp_transport_t *link; + sctp_sender_hb_info_t *hbinfo; + unsigned long max_interval; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + hbinfo= (sctp_sender_hb_info_t *)chunk->skb->data; + from_addr = hbinfo->daddr; + link = sctp_assoc_lookup_paddr(asoc, &from_addr); + + /* This should never happen, but lets log it if so. */ + if (!link) { + printk(KERN_WARNING __FUNCTION__ + ": Could not find address %d.%d.%d.%d\n", + NIPQUAD(from_addr.v4.sin_addr)); + return SCTP_DISPOSITION_DISCARD; + } + + max_interval = link->hb_interval + link->rto; + + /* Check if the timestamp looks valid. */ + + if (time_after(hbinfo->sent_at, jiffies) + || time_after(jiffies, hbinfo->sent_at + max_interval)) { + SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp + received for transport: %p\n", + __FUNCTION__, link); + return SCTP_DISPOSITION_DISCARD; + } + + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of + * the HEARTBEAT should clear the error counter of the + * destination transport address to which the HEARTBEAT was + * sent and mark the destination transport address as active if + * it is not so marked. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, + SCTP_TRANSPORT(link)); + + return SCTP_DISPOSITION_CONSUME; + +nomem:__attribute__((unused)) + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_backbeat_8_3() */ + +/* Populate the verification/tie tags based on overlapping INIT + * scenario. + * + * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. + */ +static void +sctp_tietags_populate(sctp_association_t *new_asoc, + const sctp_association_t *asoc) +{ + switch (asoc->state) { + + /* 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State */ + + case SCTP_STATE_COOKIE_WAIT: + new_asoc->c.my_vtag = asoc->c.my_vtag; + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = 0; + break; + case SCTP_STATE_COOKIE_ECHOED: + new_asoc->c.my_vtag = asoc->c.my_vtag; + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = asoc->c.peer_vtag; + break; + + /* 5.2.2 Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED, + * COOKIE-WAIT and SHUTDOWN-ACK-SENT + */ + default: + new_asoc->c.my_ttag = asoc->c.my_vtag; + new_asoc->c.peer_ttag = asoc->c.peer_vtag; + break; + } + + /* Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of + * outbound streams) into the INIT ACK and cookie. + */ + new_asoc->rwnd = asoc->rwnd; + new_asoc->c.sinit_num_ostreams = asoc->c.sinit_num_ostreams; + new_asoc->c.sinit_max_instreams = asoc->c.sinit_max_instreams; + new_asoc->c.initial_tsn = asoc->c.initial_tsn; + + return; + +} /* sctp_tietags_populate() */ + + +/* + * Compare vtag/tietag values to determine unexpected COOKIE-ECHO + * handling action. + * + * RFC 2960 5.2.4 Handle a COOKIE ECHO when a TCB exists. + * + * Returns value representing action to be taken. These action values + * correspond to Action/Description values in RFC 2960, Table 2. + */ +static char +sctp_tietags_compare(sctp_association_t *new_asoc, + const sctp_association_t *asoc) +{ + + /* In this case, the peer may have restarted. */ + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) + && (asoc->c.peer_vtag != new_asoc->c.peer_vtag) + && (asoc->c.my_vtag == new_asoc->c.my_ttag) + && (asoc->c.peer_vtag == new_asoc->c.peer_ttag)) { + + return 'A'; + } + + /* Collision case D. + * Note: Test case D first, otherwise it may be incorrectly + * identified as second case of B if the value of the Tie_tag is + * not filled into the state cookie. + */ + if ((asoc->c.my_vtag == new_asoc->c.my_vtag) + && (asoc->c.peer_vtag == new_asoc->c.peer_vtag)) { + + return 'D'; + } + + /* Collision case B. */ + if (( asoc->c.my_vtag == new_asoc->c.my_vtag) + && ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) + || (!new_asoc->c.my_ttag && !new_asoc->c.peer_ttag))) { + + return 'B'; + } + + /* Collision case C. */ + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) + && ( asoc->c.peer_vtag == new_asoc->c.peer_vtag) + && (0 == new_asoc->c.my_ttag) + && (0 == new_asoc->c.peer_ttag)) { + return 'C'; + } + + return 'E'; /* No such case available. */ + +} /* sctp_tietags_compare() */ + + +/* Common helper routine for both duplicate and simulataneous INIT + * chunk handling. + */ +static sctp_disposition_t +sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *repl; + sctp_association_t *new_asoc; + + /* 6.10 Bundling + * An endpoint MUST NOT bundle INIT, INIT ACK or + * SHUTDOWN COMPLETE with any other chunks. + */ + if (!chunk->singleton) { + return SCTP_DISPOSITION_VIOLATION; + } + + + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + + /* Tag the variable length parameters. + */ + chunk->param_hdr.v = + skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + + /* + * Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of + * outbound streams) into the INIT ACK and cookie. + * FIXME: We are copying parameters from the endpoint not the + * association. + */ + new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); + if (!new_asoc) { goto nomem; } + + /* In the outbound INIT ACK the endpoint MUST copy its current + * Verification Tag and Peers Verification tag into a reserved + * place (local tie-tag and per tie-tag) within the state cookie. + */ + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, + GFP_ATOMIC); + sctp_tietags_populate(new_asoc, asoc); + + + /* B) "Z" shall respond immediately with an INIT ACK chunk. + */ + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + if (!repl) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* + * Note: After sending out INIT ACK with the State Cookie parameter, + * "Z" MUST NOT allocate any resources for this new association. + * Otherwise, "Z" will be vulnerable to resource attacks. + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_CONSUME; + +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_unexpected_init() */ + +/* + * Handle simultanous INIT. + * This means we started an INIT and then we got an INIT request from + * our peer. + * + * Section: 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State (Item B) + * This usually indicates an initialization collision, i.e., each + * endpoint is attempting, at about the same time, to establish an + * association with the other endpoint. + * + * Upon receipt of an INIT in the COOKIE-WAIT or COOKIE-ECHOED state, an + * endpoint MUST respond with an INIT ACK using the same parameters it + * sent in its original INIT chunk (including its Verification Tag, + * unchanged). These original parameters are combined with those from the + * newly received INIT chunk. The endpoint shall also generate a State + * Cookie with the INIT ACK. The endpoint uses the parameters sent in its + * INIT to calculate the State Cookie. + * + * After that, the endpoint MUST NOT change its state, the T1-init + * timer shall be left running and the corresponding TCB MUST NOT be + * destroyed. The normal procedures for handling State Cookies when + * a TCB exists will resolve the duplicate INITs to a single association. + * + * For an endpoint that is in the COOKIE-ECHOED state it MUST populate + * its Tie-Tags with the Tag information of itself and its peer (see + * section 5.2.2 for a description of the Tie-Tags). + * + * Verification Tag: Not explicit, but an INIT can not have a valid + * verification tag, so we skip the check. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_disposition_t retval; + + /* Call helper to do the real work for both simulataneous and + * duplicate INIT chunk handling. + */ + + retval = sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); + + return retval; + +} /* sctp_sf_do_5_2_1_siminit() */ + + + +/* + * Handle duplicated INIT messages. These are usually delayed + * restransmissions. + * + * Section: 5.2.2 Unexpected INIT in States Other than CLOSED, + * COOKIE-ECHOED and COOKIE-WAIT + * + * Unless otherwise stated, upon reception of an unexpected INIT for + * this association, the endpoint shall generate an INIT ACK with a + * State Cookie. In the outbound INIT ACK the endpoint MUST copy its + * current Verification Tag and peer's Verification Tag into a reserved + * place within the state cookie. We shall refer to these locations as + * the Peer's-Tie-Tag and the Local-Tie-Tag. The outbound SCTP packet + * containing this INIT ACK MUST carry a Verification Tag value equal to + * the Initiation Tag found in the unexpected INIT. And the INIT ACK + * MUST contain a new Initiation Tag (randomly generated see Section + * 5.3.1). Other parameters for the endpoint SHOULD be copied from the + * existing parameters of the association (e.g. number of outbound + * streams) into the INIT ACK and cookie. + * + * After sending out the INIT ACK, the endpoint shall take no further + * actions, i.e., the existing association, including its current state, + * and the corresponding TCB MUST NOT be changed. + * + * Note: Only when a TCB exists and the association is not in a COOKIE- + * WAIT state are the Tie-Tags populated. For a normal association INIT + * (i.e. the endpoint is in a COOKIE-WAIT state), the Tie-Tags MUST be + * set to 0 (indicating that no previous TCB existed). The INIT ACK and + * State Cookie are populated as specified in section 5.2.1. + * + * Verification Tag: Not specifed, but an INIT has no way of knowing + * what the verification tag could be, so we ignore it. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. */ +sctp_disposition_t +sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_disposition_t retval; + + /* Call helper to do the real work for both simulataneous and + * duplicate INIT chunk handling. + */ + + retval = sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); + return retval; + +} /* sctp_sf_do_5_2_2_dupinit() */ + +/* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A') + * + * Section 5.2.4 + * A) In this case, the peer may have restarted. + */ +static sctp_disposition_t +sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_init_chunk_t *peer_init; + sctp_ulpevent_t *ev; + sctp_chunk_t *repl; + sctp_transport_t *new_addr, *addr; + list_t *pos, *pos2, *temp; + int found, error; + + /* new_asoc is a brand-new association, so these are not yet + * side effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC); + + + /* Make sure peer is not adding new addresses. */ + found = 0; + new_addr = NULL; + list_for_each(pos, &new_asoc->peer.transport_addr_list) { + new_addr = list_entry(pos, sctp_transport_t, transports); + found = 1; + list_for_each_safe(pos2, temp, + &asoc->peer.transport_addr_list) { + addr = list_entry(pos2, sctp_transport_t, transports); + if (!sctp_cmp_addr_exact(&new_addr->ipaddr, + &addr->ipaddr)){ + found = 0; + break; + } + } + if (!found){ break; } + } /* list_for_each(...) */ + + if (!found){ + sctp_bind_addr_t *bp; + sctpParam_t rawaddr; + int len; + + bp = sctp_bind_addr_new(GFP_ATOMIC); + if (!bp) { goto nomem; } + + error = sctp_add_bind_addr(bp, &new_addr->ipaddr, GFP_ATOMIC); + if (error) { goto nomem_add; } + + rawaddr = sctp_bind_addrs_to_raw(bp, &len, GFP_ATOMIC); + if (!rawaddr.v) { goto nomem_raw; } + + repl = sctp_make_abort(asoc, chunk, len+sizeof(sctp_errhdr_t)); + + if (!repl) { goto nomem_abort; } + sctp_init_cause(repl, SCTP_ERROR_RESTART, rawaddr.v, len); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + return SCTP_DISPOSITION_CONSUME; + nomem_abort: + kfree(rawaddr.v); + nomem_raw: + nomem_add: + sctp_bind_addr_free(bp); + goto nomem; + } + + /* For now, fail any unsent/unacked data. Consider the optional + * choice of resending of this data. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); + + /* Update the content of current association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* Report association restart to upper layer. */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + GFP_ATOMIC); + if (NULL == ev) { goto nomem_ev; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + return SCTP_DISPOSITION_CONSUME; + +nomem_ev: + sctp_free_chunk(repl); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_dupcook_a() */ + +/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'B') + * + * Section 5.2.4 + * B) In this case, both sides may be attempting to start an association + * at about the same time but the peer endpoint started its INIT + * after responding to the local endpoint's INIT + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t +sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_init_chunk_t *peer_init; + sctp_ulpevent_t *ev; + sctp_chunk_t *repl; + + /* new_asoc is a brand-new association, so these are not yet + * side effects--it is safe to run them here. + */ + peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; + sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_source(chunk), peer_init, GFP_ATOMIC); + + /* Update the content of current association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (NULL == repl) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose to + * send the Communication Up notification to the SCTP user + * upon reception of a valid COOKIE ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + GFP_ATOMIC); + if (NULL == ev) { goto nomem_ev; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + return SCTP_DISPOSITION_CONSUME; +nomem_ev: + sctp_free_chunk(repl); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_dupcook_b() */ + +/* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'C') + * + * Section 5.2.4 + * C) In this case, the local endpoint's cookie has arrived late. + * Before it arrived, the local endpoint sent an INIT and received an + * INIT-ACK and finally sent a COOKIE ECHO with the peer's same tag + * but a new tag of its own. + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t +sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + /* The cookie should be silently discarded. + * The endpoint SHOULD NOT change states and should leave + * any timers running. + */ + return SCTP_DISPOSITION_DISCARD; + +} /* sctp_sf_do_dupcook_c() */ + +/* Unexpected COOKIE-ECHO handler lost chunk (Table 2, action 'D') + * + * Section 5.2.4 + * + * D) When both local and remote tags match the endpoint should always + * enter the ESTABLISHED state, if it has not already done so. + */ +/* This case represents an intialization collision. */ +static sctp_disposition_t +sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) +{ + sctp_ulpevent_t *ev = NULL; + sctp_chunk_t *repl; + + /* The local endpoint cannot use any value from the received + * state cookie and need to immediately resend a COOKIE-ACK + * and move into ESTABLISHED if it hasn't done so. + */ + if (SCTP_STATE_ESTABLISHED != asoc->state) { + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_ESTABLISHED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, + SCTP_NULL()); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * D) IMPLEMENTATION NOTE: An implementation may choose + * to send the Communication Up notification to the + * SCTP user upon reception of a valid COOKIE + * ECHO chunk. + */ + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, + SCTP_COMM_UP, 0, + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + GFP_ATOMIC); + + if (NULL == ev) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); + } + + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (NULL == repl) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + + return SCTP_DISPOSITION_CONSUME; +nomem: + if (ev) { sctp_ulpevent_free(ev); } + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_dupcook_c() */ + +/* + * Handle a duplicate COOKIE-ECHO. This usually means a cookie-carrying + * chunk was retransmitted and then delayed in the network. + * + * Section: 5.2.4 Handle a COOKIE ECHO when a TCB exists + * + * Verification Tag: None. Do cookie validation. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_disposition_t retval; + sctp_chunk_t *chunk = arg; + sctp_association_t *new_asoc; + int error = 0; + char action; + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ + chunk->subh.cookie_hdr = + (sctp_signed_cookie_t *)chunk->skb->data; + skb_pull(chunk->skb, + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + + /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie + * of a duplicate COOKIE ECHO match the Verification Tags of the + * current association, consider the State Cookie valid even if + * the lifespan is exceeded. + */ + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + + /* FIXME: + * If the re-build failed, what is the proper error path + * from here? + * + * [We should abort the association. --piggy] + */ + + if (NULL == new_asoc) { + /* FIXME: Several errors are possible. A bad cookie should + * be silently discarded, but think about logging it too. + */ + switch (error) { + case -SCTP_IERROR_NOMEM: + goto nomem; + case -SCTP_IERROR_BAD_SIG: + default: + return sctp_sf_pdiscard(ep, asoc, type, + arg, commands); + } + } + + /* Compare the tie_tag in cookie with the verification tag of + * current association. + */ + action = sctp_tietags_compare(new_asoc, asoc); + + switch (action) { + case 'A': /* Association restart. */ + retval = sctp_sf_do_dupcook_a(ep, asoc, chunk, commands, + new_asoc); + break; + case 'B': /* Collision case B. */ + retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands, + new_asoc); + break; + case 'C': /* Collisioun case C. */ + retval = sctp_sf_do_dupcook_c(ep, asoc, chunk, commands, + new_asoc); + break; + + case 'D': /* Collision case D. */ + retval = sctp_sf_do_dupcook_d(ep, asoc, chunk, commands, + new_asoc); + break; + + default: /* No such case, discard it. */ + printk(KERN_WARNING __FUNCTION__ ":unknown case\n"); + retval = SCTP_DISPOSITION_DISCARD; + break; + } /* switch */ + + /* Delete the tempory new association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return retval; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_5_2_4_dupcook() */ + + +#if 0 +/* + * Handle a Stale COOKIE Error + * + * Section: 5.2.6 Handle Stale COOKIE Error + * If the association is in the COOKIE-ECHOED state, the endpoint may elect + * one of the following three alternatives. + * ... + * 3) Send a new INIT chunk to the endpoint, adding a Cookie + * Preservative parameter requesting an extension to the lifetime of + * the State Cookie. When calculating the time extension, an + * implementation SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no more + * than 1 second beyond the measured RTT, due to long State Cookie + * lifetimes making the endpoint more subject to a replay attack. + * + * Verification Tag: Not explicit, but safe to ignore. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +do_5_2_6_stale(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* This is not a real chunk type. It is a subtype of the + * ERROR chunk type. The ERROR chunk processing will bring us + * here. + */ + sctp_chunk_t *in_packet; + stp_chunk_t *reply; + sctp_inithdr_t initack; + uint8_t *addrs; + int addrs_len; + time_t rtt; + extern struct timespec now; + + struct sctpCookiePreserve bht; + + /* If we have gotten too many failures, give up. */ + if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts){ + /* FIXME: Move to new ulpevent. */ + retval->event_up = sctp_make_ulp_init_timeout(asoc); + if (NULL == retval->event_up) { goto nomem; } + sctp_add_cmd_sf(retval->commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + retval->counters[0] = SCTP_COUNTER_INCR; + retval->counters[0] = SctpCounterInits; + retval->counters[1] = 0; + retval->counters[1] = 0; + + /* Calculate the RTT in ms. */ + /* BUG--we should get the send time of the HEARTBEAT REQUEST. */ + in_packet = chunk; + rtt = 1000 * timeval_sub(in_packet->skb->stamp, + asoc->c.state_timestamp); + + /* When calculating the time extension, an implementation + * SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no + * more than 1 second beyond the measured RTT, due to long + * State Cookie lifetimes making the endpoint more subject to + * a replay attack. + */ + bht.p = {SCTP_COOKIE_PRESERVE, 8}; + bht.extraTime = htonl(rtt + 1000); + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(atomic_read(&asoc->rnwd)); + initack.num_outbound_streams = htons(asoc->streamoutcnt); + initack.num_inbound_streams = htons(asoc->streamincnt); + initack.initial_tsn = htonl(asoc->c.initSeqNumber); + + sctp_get_my_addrs(asoc, &addrs, &addrs_len); + + /* Build that new INIT chunk. */ + reply = sctp_make_chunk(SCTP_INITIATION, 0, + sizeof(initack) + + sizeof(bht) + + addrs_len); + if (NULL == reply) { goto nomem; } + sctp_addto_chunk(reply, sizeof(initack), &initack); + sctp_addto_chunk(reply, sizeof(bht), &bht); + sctp_addto_chunk(reply, addrs_len, addrs); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* sctp_disposition_t do_5_2_6_stale (...) */ +#endif /* 0 */ + + +/* + * Process an ABORT. + * + * Section: 9.1 + * After checking the Verification Tag, the receiving endpoint shall + * remove the association from its record, and shall report the + * termination to its upper layer. + * + * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules + * B) Rules for packet carrying ABORT: + * + * - The endpoint shall always fill in the Verification Tag field of the + * outbound packet with the destination endpoint's tag value if it + * is known. + * + * - If the ABORT is sent in response to an OOTB packet, the endpoint + * MUST follow the procedure described in Section 8.4. + * + * - The receiver MUST accept the packet if the Verification Tag + * matches either its own tag, OR the tag of its peer. Otherwise, the + * receiver MUST silently discard the packet and take no further + * action. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + /* Check the verification tag. */ + /* BUG: WRITE ME. */ + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + /* BUG? This does not look complete... */ + return SCTP_DISPOSITION_ABORT; + +} /* sctp_sf_do_9_1_abort() */ + +/* + * Process an ABORT. (COOKIE-WAIT state) + * + * See sctp_sf_do_9_1_abort() above. + */ +sctp_disposition_t +sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + /* CMD_INIT_FAILED will DELETE_TCB. */ + sctp_add_cmd_sf(commands,SCTP_CMD_INIT_FAILED, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + +} /* sctp_sf_cookie_wait_abort() */ + +/* + * Process an ABORT. (COOKIE-ECHOED state) + * + * See sctp_sf_do_9_1_abort() above. + */ +sctp_disposition_t +sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands); + +} /* sctp_sf_cookie_echoed_abort() */ + +#if 0 +/* + * Handle a shutdown timeout or INIT during a shutdown phase. + * + * Section: 9.2 + * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk + * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination + * transport addresses (either in the IP addresses or in the INIT chunk) + * that belong to this association, it should discard the INIT chunk and + * retransmit the SHUTDOWN ACK chunk. + *... + * While in SHUTDOWN-SENT state ... If the timer expires, the endpoint + * must re-send the SHUTDOWN ACK. + * + * Verification Tag: Neither the INIT nor the timeout will have a + * valid verification tag, so it is safe to ignore. + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_do_9_2_reshutack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* If this was a timeout (not an INIT), then do the counter + * work. We might need to just dump the association. + */ + if (!chunk) { + if (1 + asoc->counters[SctpCounterRetran] > + asoc->maxRetrans){ + sctp_add_cmd(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + retval->counters[0] = SCTP_COUNTER_INCR; + retval->counters[0] = SctpCounterRetran; + retval->counters[1] = 0; + retval->counters[1] = 0; + } + + reply = sctp_make_shutdown_ack(asoc, chunk); + if (!reply) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_disposition_t sctp_do_9_2_reshutack(...) */ +#endif /* 0 */ + +/* + * sctp_sf_do_9_2_shut + * + * Section: 9.2 + * Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, + * + * - stop accepting new data from its SCTP user + * + * - verify, by checking the Cumulative TSN Ack field of the chunk, + * that all its outstanding DATA chunks have been received by the + * SHUTDOWN sender. + * + * Once an endpoint as reached the SHUTDOWN-RECEIVED state it MUST NOT + * send a SHUTDOWN in response to a ULP request. And should discard + * subsequent SHUTDOWN chunks. + * + * If there are still outstanding DATA chunks left, the SHUTDOWN + * receiver shall continue to follow normal data transmission + * procedures defined in Section 6 until all outstanding DATA chunks + * are acknowledged; however, the SHUTDOWN receiver MUST NOT accept + * new data from its SCTP user. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. */ +sctp_disposition_t +sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_shutdownhdr_t *sdh; + sctp_disposition_t disposition; + + /* Convert the elaborate header. */ + sdh = (sctp_shutdownhdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); + chunk->subh.shutdown_hdr = sdh; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + /* Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, + * - stop accepting new data from its SCTP user + * + * [This is implicit in the new state.] + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED)); + + disposition = SCTP_DISPOSITION_CONSUME; + + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_shutdown_ack(ep, asoc, type, + arg, commands); + } + + /* - verify, by checking the Cumulative TSN Ack field of the + * chunk, that all its outstanding DATA chunks have been + * received by the SHUTDOWN sender. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, + SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); + + return disposition; + +} /* sctp_sf_do_9_2_shutdown() */ + + +/* + * sctp_sf_do_ecn_cwr + * + * Section: Appendix A: Explicit Congestion Notification + * + * CWR: + * + * RFC 2481 details a specific bit for a sender to send in the header of + * its next outbound TCP segment to indicate to its peer that it has + * reduced its congestion window. This is termed the CWR bit. For + * SCTP the same indication is made by including the CWR chunk. + * This chunk contains one data element, i.e. the TSN number that + * was sent in the ECNE chunk. This element represents the lowest + * TSN number in the datagram that was originally marked with the + * CE bit. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ + +sctp_disposition_t +sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_cwrhdr_t *cwr; + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + cwr = (sctp_cwrhdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t)); + + cwr->lowest_tsn = ntohl(cwr->lowest_tsn); + + /* Does this CWR ack the last sent congestion notification? */ + + if (TSN_lte(asoc->last_ecne_tsn, cwr->lowest_tsn)) { + + /* Stop sending ECNE. */ + sctp_add_cmd_sf(commands, + SCTP_CMD_ECN_CWR, + SCTP_U32(cwr->lowest_tsn)); + } + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_do_ecne_cwr() */ + + +/* + * sctp_sf_do_ecne + * + * Section: Appendix A: Explicit Congestion Notification + * + * ECN-Echo + * + * RFC 2481 details a specific bit for a receiver to send back in its + * TCP acknowledgements to notify the sender of the Congestion + * Experienced (CE) bit having arrived from the network. For SCTP this + * same indication is made by including the ECNE chunk. This chunk + * contains one data element, i.e. the lowest TSN associated with the IP + * datagram marked with the CE bit..... + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ + +sctp_disposition_t +sctp_sf_do_ecne(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_ecnehdr_t *ecne; + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + ecne = (sctp_ecnehdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t)); + ecne->lowest_tsn = ntohl(ecne->lowest_tsn); + + /* Casting away the const, as we are just modifying the spinlock, + * not the association itself. This should go away in the near + * future when we move to an endpoint based lock. + */ + + /* If this is a newer ECNE than the last CWR packet we sent out */ + + if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)){ + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE, + SCTP_U32(ecne->lowest_tsn)); + } + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_do_ecne() */ + + +/* + * Section: 6.2 Acknowledgement on Reception of DATA Chunks + * + * The SCTP endpoint MUST always acknowledge the reception of each valid + * DATA chunk. + * + * The guidelines on delayed acknowledgement algorithm specified in + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, an + * acknowledgement SHOULD be generated for at least every second packet + * (not every second DATA chunk) received, and SHOULD be generated within + * 200 ms of the arrival of any unacknowledged DATA chunk. In some + * situations it may be beneficial for an SCTP transmitter to be more + * conservative than the algorithms detailed in this document allow. + * However, an SCTP transmitter MUST NOT be more aggressive than the + * following algorithms allow. + * + * A SCTP receiver MUST NOT generate more than one SACK for every + * incoming packet, other than to update the offered window as the + * receiving application consumes new data. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; + sctp_chunk_t *err; + size_t datalen; + int tmp; + uint32_t tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + } + + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + + tsn = ntohl(data_hdr->tsn); + + SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); + SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); + + + /* ASSERT: Now skb->data is really the user data. */ + + /* Process ECN based congestion. + * + * Since the chunk structure is reused for all chunks within + * a packet, we use ecn_ce_done to track if we've already + * done CE processing for this packet. + * + * We need to do ECN processing even if we plan to discard the + * chunk later. + */ + + if (!chunk->ecn_ce_done) { + chunk->ecn_ce_done = 1; + if ( INET_ECN_is_ce(chunk->skb->nh.iph->tos) + && asoc->peer.ecn_capable) { + + /* Do real work as sideffect. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + SCTP_U32(tsn)); + + } /* if (packet experienced congestion) */ + + } /* if (we have not done ecn_ce processing) */ + + tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); + if (tmp < 0) { + /* The TSN is too high--silently discard the chunk and + * count on it getting retransmitted later. + */ + goto discard_noforce; + } else if (tmp > 0) { + /* This is a duplicate. Record it. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + goto discard_force; + } + + /* This is a new TSN. */ + + /* If we don't have any room in our receive window, discard. + * Actually, allow a little bit of overflow (up to a MTU of + * of overflow). + */ + datalen = ntohs(chunk->chunk_hdr->length); + datalen -= sizeof(sctp_data_chunk_t); + + if (!asoc->rwnd || (datalen > asoc->frag_point)) { + SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %d, " + "rwnd: %d\n", tsn, datalen, asoc->rwnd); + goto discard_noforce; + } + + /* + * Section 3.3.10.9 No User Data (9) + * + * Cause of error + * --------------- + * No User Data: This error cause is returned to the originator of a + * DATA chunk if a received DATA chunk has no user data. + */ + if (unlikely(0 == datalen)) { + err = sctp_make_abort_no_data(asoc, chunk, tsn); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + } + + /* We are accepting this DATA chunk. */ + + /* Record the fact that we have received this TSN. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * If an endpoint receive a DATA chunk with an invalid stream + * identifier, it shall acknowledge the reception of the DATA chunk + * following the normal procedure, immediately send an ERROR chunk + * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) + * and discard the DATA chunk. + */ + if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { + + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, + sizeof(data_hdr->stream)); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + goto discard_noforce; + + } + + /* Send the data up to the user. Note: Schedule the + * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK + * chunk needs the updated rwnd. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_CHUNK_ULP, SCTP_CHUNK(chunk)); + + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + /* If this is the last chunk in a packet, we need to count it + * toward sack generation. Note that we need to SACK every + * OTHER packet containing data chunks, EVEN IF WE DISCARD + * THEM. We elect to NOT generate SACK's if the chunk fails + * the verification tag test. + * + * RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks + * + * The SCTP endpoint MUST always acknowledge the reception of + * each valid DATA chunk. + * + * The guidelines on delayed acknowledgement algorithm + * specified in Section 4.2 of [RFC2581] SHOULD be followed. + * Specifically, an acknowledgement SHOULD be generated for at + * least every second packet (not every second DATA chunk) + * received, and SHOULD be generated within 200 ms of the + * arrival of any unacknowledged DATA chunk. In some + * situations it may be beneficial for an SCTP transmitter to + * be more conservative than the algorithms detailed in this + * document allow. However, an SCTP transmitter MUST NOT be + * more aggressive than the following algorithms allow. + */ + if (chunk->end_of_packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + + /* Start the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } + + return SCTP_DISPOSITION_CONSUME; + + discard_force: + /* RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks + * + * When a packet arrives with duplicate DATA chunk(s) and with + * no new DATA chunk(s), the endpoint MUST immediately send a + * SACK with no delay. If a packet arrives with duplicate + * DATA chunk(s) bundled with new DATA chunks, the endpoint + * MAY immediately send a SACK. Normally receipt of duplicate + * DATA chunks will occur when the original SACK chunk was lost + * and the peer's RTO has expired. The duplicate TSN number(s) + * SHOULD be reported in the SACK as duplicate. + */ + /* In our case, we split the MAY SACK advice up whether or not + * the last chunk is a duplicate.' + */ + if (chunk->end_of_packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + } + return SCTP_DISPOSITION_DISCARD; + +discard_noforce: + if (chunk->end_of_packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); + + /* Start the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } + return SCTP_DISPOSITION_DISCARD; + +} /* sctp_sf_eat_data_6_2() */ + + +/* + * sctp_sf_eat_data_fast_4_4 + * + * Section: 4 (4) + * (4) In SHUTDOWN-SENT state the endpoint MUST acknowledge any received + * DATA chunks without delay. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; + sctp_chunk_t *err; + size_t datalen; + int tmp; + uint32_t tsn; + + /* RFC 2960 8.5 Verification Tag + * + * When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. + */ + + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + SCTP_NULL()); + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + + tsn = ntohl(data_hdr->tsn); + + SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); + + /* ASSERT: Now skb->data is really the user data. */ + + /* Process ECN based congestion. + * + * Since the chunk structure is reused for all chunks within + * a packet, we use ecn_ce_done to track if we've already + * done CE processing for this packet. + * + * We need to do ECN processing even if we plan to discard the + * chunk later. + */ + + if (!chunk->ecn_ce_done) { + chunk->ecn_ce_done = 1; + if ( INET_ECN_is_ce(chunk->skb->nh.iph->tos) + && asoc->peer.ecn_capable) { + + /* Do real work as sideffect. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + SCTP_U32(tsn)); + + } /* if (packet experienced congestion) */ + + } /* if (we have not done ecn_ce processing) */ + + tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); + if (tmp < 0) { + /* The TSN is too high--silently discard the chunk and + * count on it getting retransmitted later. + */ + goto gen_shutdown; + } else if (tmp > 0) { + /* This is a duplicate. Record it. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_DUP, SCTP_U32(tsn)); + goto gen_shutdown; + } + + /* This is a new TSN. */ + + datalen = ntohs(chunk->chunk_hdr->length); + datalen -= sizeof(sctp_data_chunk_t); + + /* + * Section 3.3.10.9 No User Data (9) + * + * Cause of error + * --------------- + * No User Data: This error cause is returned to the originator of a + * DATA chunk if a received DATA chunk has no user data. + */ + if (unlikely(0 == datalen)) { + err = sctp_make_abort_no_data(asoc, chunk, tsn); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + } + + /* We are accepting this DATA chunk. */ + + /* Record the fact that we have received this TSN. */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); + + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number + * + * If an endpoint receive a DATA chunk with an invalid stream + * identifier, it shall acknowledge the reception of the DATA chunk + * following the normal procedure, immediately send an ERROR chunk + * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) + * and discard the DATA chunk. + */ + if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { + + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, + sizeof(data_hdr->stream)); + if (err) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(err)); + } + } + + /* Go a head and force a SACK, since we are shutting down. */ +gen_shutdown: + /* Implementor's Guide. + * + * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately + * respond to each received packet containing one or more DATA chunk(s) + * with a SACK, a SHUTDOWN chunk, and restart the T2-shutdown timer + */ + if (chunk->end_of_packet) { + /* We must delay the chunk creation since the cumulative + * TSN has not been updated yet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + } + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_eat_data_fast4_4() */ + + +/* + * Section: 6.2 Processing a Received SACK + * D) Any time a SACK arrives, the endpoint performs the following: + * + * i) If Cumulative TSN Ack is less than the Cumulative TSN Ack Point, + * then drop the SACK. Since Cumulative TSN Ack is monotonically + * increasing, a SACK whose Cumulative TSN Ack is less than the + * Cumulative TSN Ack Point indicates an out-of-order SACK. + * + * ii) Set rwnd equal to the newly received a_rwnd minus the number + * of bytes still outstanding after processing the Cumulative TSN Ack + * and the Gap Ack Blocks. + * + * iii) If the SACK is missing a TSN that was previously + * acknowledged via a Gap Ack Block (e.g., the data receiver + * reneged on the data), then mark the corresponding DATA chunk + * as available for retransmit: Mark it as missing for fast + * retransmit as described in Section 7.2.4 and if no retransmit + * timer is running for the destination address to which the DATA + * chunk was originally transmitted, then T3-rtx is started for + * that destination address. + * + * Verification Tag: 8.5 Verification Tag [Normal verification] + * + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_sackhdr_t *sackh; + uint32_t ctsn; + + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + /* Pull the SACK chunk from the data buffer */ + sackh = sctp_sm_pull_sack(chunk); + chunk->subh.sack_hdr = sackh; + ctsn = ntohl(sackh->cum_tsn_ack); + + /* i) If Cumulative TSN Ack is less than the Cumulative TSN + * Ack Point, then drop the SACK. Since Cumulative TSN + * Ack is monotonically increasing, a SACK whose + * Cumulative TSN Ack is less than the Cumulative TSN Ack + * Point indicates an out-of-order SACK. + */ + if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { + + SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); + SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", + asoc->ctsn_ack_point); + return SCTP_DISPOSITION_DISCARD; + } + + /* Return this SACK for further processing. */ + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, + SCTP_SACKH(sackh)); + + /* Note: We do the rest of the work on the PROCESS_SACK + * sideeffect. + */ + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_eat_sack_6_2() */ + + +/* + * Generate an ABORT in response to a packet. + * + * Section: 8.4 Handle "Out of the blue" Packets + * + * 8) The receiver should respond to the sender of the OOTB packet + * with an ABORT. When sending the ABORT, the receiver of the + * OOTB packet MUST fill in the Verification Tag field of the + * outbound packet with the value found in the Verification Tag + * field of the OOTB packet and set the T-bit in the Chunk Flags + * to indicate that no TCB was found. After sending this ABORT, + * the receiver of the OOTB packet shall discard the OOTB packet + * and take no further action. + * + * Verification Tag: + * + * The return value is the disposition of the chunk. */ +sctp_disposition_t +sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *abort; + uint16_t sport; + uint16_t dport; + uint32_t vtag; + + + /* Grub in chunk and endpoint for kewl bitz. */ + sport = ntohs(chunk->sctp_hdr->dest); + dport = ntohs(chunk->sctp_hdr->source); + /* -- Make sure the ABORT packet's V-tag is the same as the + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + if (asoc) { + vtag = asoc->peer.i.init_tag; + } else { + vtag = ntohl(chunk->sctp_hdr->vtag); + } + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + + if (!transport) { + goto nomem; + } + + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) { + goto nomem_packet; + } + packet = sctp_packet_init(packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0, NULL); + + /* Make an ABORT. + * This will set the T bit since we have no association. + */ + abort = sctp_make_abort(NULL, chunk, 0); + if (NULL == abort) { + goto nomem_chunk; + } + + /* Set the skb to the belonging sock for accounting. */ + abort->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, abort); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + + return SCTP_DISPOSITION_DISCARD; + +nomem_chunk: + sctp_packet_free(packet); +nomem_packet: + sctp_transport_free(transport); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_tabort_8_4_8() */ + +/* + * Received an ERROR chunk from peer. Generate SCTP_REMOTE_ERROR + * event as ULP notification for each cause included in the chunk. + * + * API 5.3.1.3 - SCTP_REMOTE_ERROR + * + * The return value is the disposition of the chunk. */ +sctp_disposition_t +sctp_sf_operr_notify(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_chunk_t *chunk = arg; + sctp_ulpevent_t *ev; + + + while (chunk->chunk_end > chunk->skb->data) { + ev = sctp_ulpevent_make_remote_error(asoc,chunk,0, GFP_ATOMIC); + + if (!ev) { goto nomem; } + + if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev))) { + sctp_ulpevent_free(ev); + goto nomem; + } + } + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_operr_notify() */ + +/* + * Process an inbound SHUTDOWN ACK. + * + * From Section 9.2: + * Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall + * stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its + * peer, and remove all record of the association. + * + * The return value is the disposition. */ +sctp_disposition_t +sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_chunk_t *reply; + sctp_ulpevent_t *ev; + + + /* 10.2 H) SHUTDOWN COMPLETE notification + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ + + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, + 0, 0, 0, GFP_ATOMIC); + if (!ev) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + + + /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall + * stop the T2-shutdown timer, + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ + reply = sctp_make_shutdown_complete(asoc, chunk); + if (!reply) { goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + /* ...and remove all record of the association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + + nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_9_2_final() */ + +/* + * RFC 2960, 8.4 - Handle "Out of the blue" Packets + * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB + * packet must fill in the Verification Tag field of the outbound + * packet with the Verification Tag received in the SHUTDOWN ACK and + * set the T-bit in the Chunk Flags to indicate that no TCB was + * found. Otherwise, + * + * 8) The receiver should respond to the sender of the OOTB packet with + * an ABORT. When sending the ABORT, the receiver of the OOTB packet + * MUST fill in the Verification Tag field of the outbound packet + * with the value found in the Verification Tag field of the OOTB + * packet and set the T-bit in the Chunk Flags to indicate that no + * TCB was found. After sending this ABORT, the receiver of the OOTB + * packet shall discard the OOTB packet and take no further action. + */ +sctp_disposition_t +sctp_sf_ootb(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + struct sk_buff *skb = chunk->skb; + sctp_chunkhdr_t *ch; + uint8_t *ch_end; + int ootb_shut_ack = 0; + + ch = (sctp_chunkhdr_t *)chunk->chunk_hdr; + + do { + ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); + + if (SCTP_CID_SHUTDOWN_ACK == ch->type) { + ootb_shut_ack = 1; + } + + ch = (sctp_chunkhdr_t *)ch_end; + + } while (ch_end < skb->tail); + + + if (ootb_shut_ack) { + sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); + } else { + sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); + } + + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + +} /* sctp_sf_ootb() */ + +/* + * Handle an "Out of the blue" SHUTDOWN ACK. + * + * Section: 8.4 5) + * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet + * must fill in the Verification Tag field of the outbound packet with + * the Verification Tag received in the SHUTDOWN ACK and set the + * T-bit in the Chunk Flags to indicate that no TCB was found. + * + * Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK + * If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the + * procedures in section 8.4 SHOULD be followed, in other words it + * should be treated as an Out Of The Blue packet. + * [This means that we do NOT check the Verification Tag on these + * chunks. --piggy ] + * + * Inputs + * (endpoint, asoc, type, arg, commands) + * + * Outputs + * (sctp_disposition_t) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *shut; + uint16_t sport; + uint16_t dport; + uint32_t vtag; + + + /* Grub in chunk and endpoint for kewl bitz. */ + sport = ntohs(chunk->sctp_hdr->dest); + dport = ntohs(chunk->sctp_hdr->source); + + /* Make sure the ABORT packet's V-tag is the same as the + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + vtag = ntohl(chunk->sctp_hdr->vtag); + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + + if (!transport) { + goto nomem; + } + + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) { + goto nomem_packet; + } + packet = sctp_packet_init(packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0, NULL); + + /* Make an ABORT. + * This will set the T bit since we have no association. + */ + shut = sctp_make_shutdown_complete(NULL, chunk); + if (!shut) { + goto nomem_chunk; + } + + /* Set the skb to the belonging sock for accounting. */ + shut->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, shut); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + + return SCTP_DISPOSITION_CONSUME; + +nomem_chunk: + sctp_packet_free(packet); +nomem_packet: + sctp_transport_free(transport); +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_shut_8_4_5() */ + +#if 0 +/* + * We did something stupid but got lucky. Namely, we sent a HEARTBEAT + * before the association was all the way up and we did NOT get an + * ABORT. + * + * Log the fact and then process normally. + * + * Section: Not specified + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +lucky(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* sctp_disposition_t lucky(...) */ +#endif /* 0 */ + +#if 0 +/* + * The other end is doing something very stupid. We'll ignore them + * after logging their idiocy. :-) + * + * Section: Not specified + * Verification Tag: 8.5 Verification Tag [Normal verification] + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +other_stupid(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) { + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_disposition_t other_stupid(...) */ +#endif /* 0 */ + + +/* + * The other end is violating protocol. + * + * Section: Not specified + * Verification Tag: Not specified + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * We simply tag the chunk as a violation. The state machine will log + * the violation and continue. + */ +sctp_disposition_t +sctp_sf_violation(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_VIOLATION; + +} /* sctp_sf_violation() */ + + + +/*************************************************************************** + * These are the state functions for handling primitive (Section 10) events. + ***************************************************************************/ +/* + * sctp_sf_do_prm_asoc + * + * Section: 10.1 ULP-to-SCTP + * B) Associate + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) + * -> association id [,destination transport addr list] [,outbound stream + * count] + * + * This primitive allows the upper layer to initiate an association to a + * specific peer endpoint. + * + * The peer endpoint shall be specified by one of the transport addresses + * which defines the endpoint (see Section 1.4). If the local SCTP + * instance has not been initialized, the ASSOCIATE is considered an + * error. + * [This is not relevant for the kernel implementation since we do all + * initialization at boot time. It we hadn't initialized we wouldn't + * get anywhere near this code.] + * + * An association id, which is a local handle to the SCTP association, + * will be returned on successful establishment of the association. If + * SCTP is not able to open an SCTP association with the peer endpoint, + * an error is returned. + * [In the kernel implementation, the sctp_association_t needs to + * be created BEFORE causing this primitive to run.] + * + * Other association parameters may be returned, including the + * complete destination transport addresses of the peer as well as the + * outbound stream count of the local endpoint. One of the transport + * address from the returned destination addresses will be selected by + * the local endpoint as default primary path for sending SCTP packets + * to this peer. The returned "destination transport addr list" can + * be used by the ULP to change the default primary path or to force + * sending a packet to a specific transport address. [All of this + * stuff happens when the INIT ACK arrives. This is a NON-BLOCKING + * function.] + * + * Mandatory attributes: + * + * o local SCTP instance name - obtained from the INITIALIZE operation. + * [This is the argument asoc.] + * o destination transport addr - specified as one of the transport + * addresses of the peer endpoint with which the association is to be + * established. + * [This is asoc->peer.active_path.] + * o outbound stream count - the number of outbound streams the ULP + * would like to open towards this peer endpoint. + * [BUG: This is not currently implemented.] + * Optional attributes: + * + * None. + * + * The return value is a disposition. + */ +sctp_disposition_t +sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *repl; + sctp_bind_addr_t *bp; + sctp_scope_t scope; + int error; + int flags; + + /* The comment below says that we enter COOKIE-WAIT AFTER + * sending the INIT, but that doesn't actually work in our + * implementation... + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_COOKIE_WAIT)); + + /* Build up the bind address list for the association based on + * info from the local endpoint and the remote peer. + */ + bp = sctp_bind_addr_new(GFP_ATOMIC); + if (NULL == bp) { goto nomem; } + + /* Use scoping rules to determine the subset of addresses from + * the endpoint. + */ + scope = sctp_scope(&asoc->peer.active_path->ipaddr); + flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + if (asoc->peer.ipv4_address) { + flags |= SCTP_ADDR4_PEERSUPP; + } + if (asoc->peer.ipv6_address) { + flags |= SCTP_ADDR6_PEERSUPP; + } + error = sctp_bind_addr_copy(bp, &ep->base.bind_addr, scope, + GFP_ATOMIC, flags); + if (0 != error) { goto nomem; } + + /* FIXME: Either move address assignment out of this function + * or else move the association allocation/init into this function. + * The association structure is brand new before calling this + * function, so would not be a sideeffect if the allocation + * moved into this function. --jgrimm + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SET_BIND_ADDR, (sctp_arg_t)bp); + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * A) "A" first sends an INIT chunk to "Z". In the INIT, "A" + * must provide its Verification Tag (Tag_A) in the Initiate + * Tag field. Tag_A SHOULD be a random number in the range of + * 1 to 4294967295 (see 5.3.1 for Tag value selection). ... + */ + + repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + if (NULL == repl) { goto nomem; } + + /* Cast away the const modifier, as we want to just + * rerun it through as a sideffect. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, + SCTP_ASOC((sctp_association_t *)asoc)); + + /* After sending the INIT, "A" starts the T1-init timer and + * enters the COOKIE-WAIT state. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + if (bp) { + sctp_bind_addr_free(bp); + } + + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_prm_asoc() */ + +/* + * Process the SEND primitive. + * + * Section: 10.1 ULP-to-SCTP + * E) Send + * + * Format: SEND(association id, buffer address, byte count [,context] + * [,stream id] [,life time] [,destination transport address] + * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) + * -> result + * + * This is the main method to send user data via SCTP. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * o buffer address - the location where the user message to be + * transmitted is stored; + * + * o byte count - The size of the user data in number of bytes; + * + * Optional attributes: + * + * o context - an optional 32 bit integer that will be carried in the + * sending failure notification to the ULP if the transportation of + * this User Message fails. + * + * o stream id - to indicate which stream to send the data on. If not + * specified, stream 0 will be used. + * + * o life time - specifies the life time of the user data. The user data + * will not be sent by SCTP after the life time expires. This + * parameter can be used to avoid efforts to transmit stale + * user messages. SCTP notifies the ULP if the data cannot be + * initiated to transport (i.e. sent to the destination via SCTP's + * send primitive) within the life time variable. However, the + * user data will be transmitted if SCTP has attempted to transmit a + * chunk before the life time expired. + * + * o destination transport address - specified as one of the destination + * transport addresses of the peer endpoint to which this packet + * should be sent. Whenever possible, SCTP should use this destination + * transport address for sending the packets, instead of the current + * primary path. + * + * o unorder flag - this flag, if present, indicates that the user + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * message). + * + * o no-bundle flag - instructs SCTP not to bundle this user data with + * other outbound DATA chunks. SCTP MAY still bundle even when + * this flag is present, when faced with network congestion. + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data + * being transmitted. This value is passed as opaque data by SCTP. + * + * + * The return value is the disposition. + */ +sctp_disposition_t +sctp_sf_do_prm_send(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_do_prm_send() */ + +/* + * Process the SHUTDOWN primitive. + * + * Section: 10.1: + * C) Shutdown + * + * Format: SHUTDOWN(association id) + * -> result + * + * Gracefully closes an association. Any locally queued user data + * will be delivered to the peer. The association will be terminated only + * after the peer acknowledges all the SCTP packets sent. A success code + * will be returned on successful termination of the association. If + * attempting to terminate the association results in a failure, an error + * code shall be returned. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * Optional attributes: + * + * None. + * + * The return value is the disposition. + */ +sctp_disposition_t +sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); + + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + arg, commands); + } + return disposition; + +} /* sctp_sf_do_9_2_prm_shutdown() */ + +/* We tried an illegal operation on an association which is closed. */ +sctp_disposition_t +sctp_sf_error_closed(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, SCTP_ERROR(-EINVAL)); + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_error_closed() */ + +/* We tried an illegal operation on an association which is shutting + * down. + */ +sctp_disposition_t +sctp_sf_error_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, + SCTP_ERROR(-ESHUTDOWN)); + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_error_shutdown() */ + +/* + * sctp_cookie_wait_prm_shutdown + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explicitly address this issue, but is the route through the + * state table when someone issues a shutdown while in COOKIE_WAIT state. + * + * Outputs + * (timers) + */ +sctp_disposition_t +sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands){ + + + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + +} /* sctp_sf_cookie_wait_prm_shutdown() */ + +/* + * sctp_cookie_echoed_prm_shutdown + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explcitly address this issue, but is the route through the + * state table when someone issues a shutdown while in COOKIE_ECHOED state. + * + * Outputs + * (timers) + */ +sctp_disposition_t +sctp_sf_cookie_echoed_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_prm_shutdown(ep, asoc, type, arg, commands); + +} /* sctp_sf_cookie_echoed_prm_shutdown() */ + +/* + * Ignore the primitive event + * + * The return value is the disposition of the primitive. + */ +sctp_disposition_t +sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); + + return SCTP_DISPOSITION_DISCARD; + +} /* sctp_sf_ignore_primitive() */ + + +/*************************************************************************** + * These are the state functions for the OTHER events. + ***************************************************************************/ + +/* + * Start the shutdown negotiation. + * + * From Section 9.2: + * Once all its outstanding data has been acknowledged, the endpoint + * shall send a SHUTDOWN chunk to its peer including in the Cumulative + * TSN Ack field the last sequential TSN it has received from the peer. + * It shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT + * state. If the timer expires, the endpoint must re-send the SHUTDOWN + * with the updated last sequential TSN received from its peer. + * + * The return value is the disposition. + */ +sctp_disposition_t +sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *reply; + + /* Once all its outstanding data has been acknowledged, the + * endpoint shall send a SHUTDOWN chunk to its peer including + * in the Cumulative TSN Ack field the last sequential TSN it + * has received from the peer. + */ + reply = sctp_make_shutdown(asoc); + if (NULL == reply) { goto nomem; } + + /* Set the transport for the SHUTDOWN chunk and the timeout for the + * T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* It shall then start the T2-shutdown timer */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + /* and enter the SHUTDOWN-SENT state. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_SENT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_9_2_start_shutdown() */ + + +/* + * Generate a SHUTDOWN ACK now that everything is SACK'd. + * + * From Section 9.2: + * + * If it has no more outstanding DATA chunks, the SHUTDOWN receiver + * shall send a SHUTDOWN ACK and start a T2-shutdown timer of its own, + * entering the SHUTDOWN-ACK-SENT state. If the timer expires, the + * endpoint must re-send the SHUTDOWN ACK. + * + * The return value is the disposition. */ +sctp_disposition_t +sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = (sctp_chunk_t *) arg; + sctp_chunk_t *reply; + + /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver + * shall send a SHUTDOWN ACK ... + */ + reply = sctp_make_shutdown_ack(asoc, chunk); + if (NULL == reply) { goto nomem; } + + /* Set the transport for the SHUTDOWN ACK chunk and the timeout for + * the T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* and start/restart a T2-shutdown timer of its own, */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + if (asoc->autoclose) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); + } + + /* Enter the SHUTDOWN-ACK-SENT state. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_ACK_SENT)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_do_9_2_shutdown_ack() */ + +/* + * Ignore the event defined as other + * + * The return value is the disposition of the event. + */ +sctp_disposition_t +sctp_sf_ignore_other(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", + type.other); + return SCTP_DISPOSITION_DISCARD; + +} /* sctp_sf_ignore_primitive() */ + +/************************************************************ + * These are the state functions for handling timeout events. + ************************************************************/ + +/* + * RTX Timeout + * + * Section: 6.3.3 Handle T3-rtx Expiration + * + * Whenever the retransmission timer T3-rtx expires for a destination + * address, do the following: + * [See below] + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = arg; + + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + /* E1) For the destination address for which the timer + * expires, adjust its ssthresh with rules defined in Section + * 7.2.3 and set the cwnd <- MTU. + */ + + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ + + /* E3) Determine how many of the earliest (i.e., lowest TSN) + * outstanding DATA chunks for the address for which the + * T3-rtx has expired will fit into a single packet, subject + * to the MTU constraint for the path corresponding to the + * destination transport address to which the retransmission + * is being sent (this may be different from the address for + * which the timer expires [see Section 6.4]). Call this + * value K. Bundle and retransmit those K DATA chunks in a + * single packet to the destination endpoint. + * + * Note: Any DATA chunks that were sent to the address for + * which the T3-rtx timer expired but did not fit in one MTU + * (rule E3 above), should be marked for retransmission and + * sent as soon as cwnd allows (normally when a SACK arrives). + */ + + /* NB: Rules E4 and F1 are implicit in R1. */ + + sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport)); + + /* Do some failure management (Section 8.2). */ + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_do_6_3_3_rtx() */ + +/* + * Generate delayed SACK on timeout + * + * Section: 6.2 Acknowledgement on Reception of DATA Chunks + * + * The guidelines on delayed acknowledgement algorithm specified in + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, an + * acknowledgement SHOULD be generated for at least every second packet + * (not every second DATA chunk) received, and SHOULD be generated + * within 200 ms of the arrival of any unacknowledged DATA chunk. In + * some situations it may be beneficial for an SCTP transmitter to be + * more conservative than the algorithms detailed in this document + * allow. However, an SCTP transmitter MUST NOT be more aggressive than + * the following algorithms allow. + */ +sctp_disposition_t +sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_do_6_2_sack() */ + +/* + * sctp_sf_t1_timer_expire + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * RFC 2960 Section 4 Notes + * 2) If the T1-init timer expires, the endpoint MUST retransmit INIT + * and re-start the T1-init timer without changing state. This MUST + * be repeated up to 'Max.Init.Retransmits' times. After that, the + * endpoint MUST abort the initialization process and report the + * error to SCTP user. + * + * 3) If the T1-cookie timer expires, the endpoint MUST retransmit + * COOKIE ECHO and re-start the T1-cookie timer without changing + * state. This MUST be repeated up to 'Max.Init.Retransmits' times. + * After that, the endpoint MUST abort the initialization process and + * report the error to SCTP user. + * + * + * Outputs + * (timers, events) + * + */ +sctp_disposition_t +sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *repl; + sctp_bind_addr_t *bp; + sctp_event_timeout_t timer = (sctp_event_timeout_t)arg; + int timeout; + int attempts; + + timeout = asoc->timeouts[timer]; + attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; + repl = NULL; + + SCTP_DEBUG_PRINTK("Timer T1 expired.\n"); + + if ((timeout < asoc->max_init_timeo) + && (attempts < asoc->max_init_attempts)) { + + switch (timer) { + case SCTP_EVENT_TIMEOUT_T1_INIT: + bp = (sctp_bind_addr_t *)&asoc->base.bind_addr; + repl = sctp_make_init(asoc, bp, GFP_ATOMIC); + break; + case SCTP_EVENT_TIMEOUT_T1_COOKIE: + repl = sctp_make_cookie_echo(asoc, NULL); + break; + default: + BUG(); + break; + } + + if (!repl) { goto nomem; } + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + + /* Issue a sideeffect to do the needed accounting. */ + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, + SCTP_TO(timer)); + + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); + + return SCTP_DISPOSITION_DELETE_TCB; + } + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_t1_timer_expire() */ + +/* RFC2960 9.2 If the timer expires, the endpoint must re-send the SHUTDOWN + * with the updated last sequential TSN received from its peer. + * + * An endpoint should limit the number of retransmissions of the + * SHUTDOWN chunk to the protocol parameter 'Association.Max.Retrans'. + * If this threshold is exceeded the endpoint should destroy the TCB and + * MUST report the peer endpoint unreachable to the upper layer (and + * thus the association enters the CLOSED state). The reception of any + * packet from its peer (i.e. as the peer sends all of its queued DATA + * chunks) should clear the endpoint's retransmission count and restart + * the T2-Shutdown timer, giving its peer ample opportunity to transmit + * all of its queued DATA chunks that have not yet been sent. + */ +sctp_disposition_t +sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *reply = NULL; + + SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); + + if (asoc->overall_error_count >= asoc->overall_error_threshold) { + + /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ + + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); + return SCTP_DISPOSITION_DELETE_TCB; + } + + switch (asoc->state) { + case SCTP_STATE_SHUTDOWN_SENT: + reply = sctp_make_shutdown(asoc); + break; + case SCTP_STATE_SHUTDOWN_ACK_SENT: + reply = sctp_make_shutdown_ack(asoc, NULL); + break; + default: + BUG(); + break; + } + if (!reply) { goto nomem; } + + /* Do some failure management (Section 8.2). */ + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); + + /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for + * the T2-shutdown timer. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); + + /* Restart the T2-shutdown timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + + return SCTP_DISPOSITION_CONSUME; +nomem: + return SCTP_DISPOSITION_NOMEM; + +} /* sctp_sf_t2_timer_expire() */ + +/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires, + * the association is automatically closed by starting the shutdown process. + * The work that needs to be done is same as when SHUTDOWN is initiated by + * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). + */ +sctp_disposition_t +sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); + + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + arg, commands); + } + return disposition; + +} /* sctp_sf_autoclose_timer_expire() */ + +/***************************************************************************** + * These are sa state functions which could apply to all types of events. + ****************************************************************************/ + +/* + * This table entry is not implemented. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_not_impl(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_NOT_IMPL; + +} /* sctp_sf_not_impl() */ + +/* + * This table entry represents a bug. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_bug(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + return SCTP_DISPOSITION_BUG; + +} /* sctp_sf_bug() */ + +/* + * This table entry represents the firing of a timer in the wrong state. + * Since timer deletion cannot be guaranteed a timer 'may' end up firing + * when the association is in the wrong state. This event should + * be ignored, so as to prevent any rearming of the timer. + * + * Inputs + * (endpoint, asoc, chunk) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_timer_ignore(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Timer %d ignored.\n", type.chunk); + + return SCTP_DISPOSITION_CONSUME; + +} /* sctp_sf_timer_ignore() */ + + +/* + * Discard the chunk. + * + * Section: 0.2, 5.2.3, 5.2.5, 5.2.6, 6.0, 8.4.6, 8.5.1c, 9.2 + * [Too numerous to mention...] + * Verification Tag: No verification needed. + * Inputs + * (endpoint, asoc, chunk) + * + * Outputs + * (asoc, reply_msg, msg_up, timers, counters) + * + * The return value is the disposition of the chunk. + */ +sctp_disposition_t +sctp_sf_discard_chunk(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); + return SCTP_DISPOSITION_DISCARD; + +} /* sctp_sf_discard_chunk() */ + + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* Pull the SACK chunk based on the SACK header. */ +sctp_sackhdr_t * +sctp_sm_pull_sack(sctp_chunk_t *chunk) +{ + sctp_sackhdr_t *sack; + uint16_t num_blocks; + uint16_t num_dup_tsns; + + sack = (sctp_sackhdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_sackhdr_t)); + + num_blocks = ntohs(sack->num_gap_ack_blocks); + num_dup_tsns = ntohs(sack->num_dup_tsns); + + skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(uint32_t)); + + return sack; + +} /* sctp_sm_pull_sack() */ diff --git a/net/sctp/sctp_sm_statetable.c b/net/sctp/sctp_sm_statetable.c new file mode 100644 index 000000000000..8edf022dff70 --- /dev/null +++ b/net/sctp/sctp_sm_statetable.c @@ -0,0 +1,1527 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statetable.c,v 1.19 2002/08/16 19:30:50 jgrimm Exp $ + * + * These are the state tables for the SCTP state machine. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Hui Huang + * Daisy Chang + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.19 2002/08/16 19:30:50 jgrimm Exp $"; + +#include +#include +#include + +sctp_sm_table_entry_t nop = {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk"}; +sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; + +#define DO_LOOKUP(_max, _type, _table) \ + if ((event_subtype._type > (_max))) { \ + printk(KERN_WARNING \ + "sctp table %p possible attack:" \ + " event %d exceeds max %d\n", \ + _table, event_subtype._type, _max); \ + return(&bug); \ + } \ + return(&_table[event_subtype._type][(int)state]); + +sctp_sm_table_entry_t * +sctp_sm_lookup_event(sctp_event_t event_type, sctp_state_t state, + sctp_subtype_t event_subtype) +{ + switch (event_type) { + case SCTP_EVENT_T_CHUNK : + return sctp_chunk_event_lookup(event_subtype.chunk, state); + break; + case SCTP_EVENT_T_TIMEOUT : + DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, + timeout_event_table); + break; + case SCTP_EVENT_T_OTHER : + DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table); + break; + case SCTP_EVENT_T_PRIMITIVE: + DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive, + primitive_event_table); + break; + default: + /* Yikes! We got an illegal event type. */ + return(&bug); + } + +} /* sctp_sm_lookup_event() */ + + +#define TYPE_SCTP_DATA { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_eat_data_fast_4_4, name: "sctp_sf_eat_data_fast_4_4"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ +} /* TYPE_SCTP_DATA */ + + + +#define TYPE_SCTP_INIT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1B_init, name: "sctp_sf_do_5_1B_init"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_INIT */ + +#define TYPE_SCTP_INIT_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_1C_ack, name: "sctp_sf_do_5_1C_ack"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ +} /* TYPE_SCTP_INIT_ACK */ + +#define TYPE_SCTP_SACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ +} /* TYPE_SCTP_SACK */ + +#define TYPE_SCTP_HEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + /* This should not happen, but we are nice. */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ +\ +} /* TYPE_SCTP_HEARTBEAT */ + +#define TYPE_SCTP_HEARTBEAT_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_HEARTBEAT_ACK */ + +#define TYPE_SCTP_ABORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_pdiscard, name: "sctp_sf_pdiscard"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_cookie_wait_abort, name: "sctp_sf_cookie_wait_abort"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_abort, \ + name: "sctp_sf_cookie_echoed_abort"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ +\ +} /* TYPE_SCTP_ABORT */ + +#define TYPE_SCTP_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_shutdown, name: "sctp_sf_do_9_2_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ + name: "sctp_sf_do_9_2_shutdown_ack"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ +} /* TYPE_SCTP_SHUTDOWN */ + +#define TYPE_SCTP_SHUTDOWN_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ +\ +} /* TYPE_SCTP_SHUTDOWN_ACK */ + +#define TYPE_SCTP_ERROR { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_operr_notify, name: "sctp_sf_operr_notify"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_ERROR */ + +#define TYPE_SCTP_COOKIE_ECHO { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1D_ce, name: "sctp_sf_do_5_1D_ce"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ +\ +} /* TYPE_SCTP_COOKIE_ECHO */ + +#define TYPE_SCTP_COOKIE_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_1E_ca, name: "sctp_sf_do_5_1E_ca"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ +} /* TYPE_SCTP_COOKIE_ACK */ + +#define TYPE_SCTP_ECN_ECNE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ +} /* TYPE_SCTP_ECN_ECNE */ + +#define TYPE_SCTP_ECN_CWR { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ +} /* TYPE_SCTP_ECN_CWR */ + +#define TYPE_SCTP_SHUTDOWN_COMPLETE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_4_C, name: "sctp_sf_do_4_C"}, \ +\ +} /* TYPE_SCTP_SHUTDOWN_COMPLETE */ + +/* The primary index for this table is the chunk type. + * The secondary index for this table is the state. + * + * For base protocol (RFC 2960). + */ +sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_DATA, + TYPE_SCTP_INIT, + TYPE_SCTP_INIT_ACK, + TYPE_SCTP_SACK, + TYPE_SCTP_HEARTBEAT, + TYPE_SCTP_HEARTBEAT_ACK, + TYPE_SCTP_ABORT, + TYPE_SCTP_SHUTDOWN, + TYPE_SCTP_SHUTDOWN_ACK, + TYPE_SCTP_ERROR, + TYPE_SCTP_COOKIE_ECHO, + TYPE_SCTP_COOKIE_ACK, + TYPE_SCTP_ECN_ECNE, + TYPE_SCTP_ECN_CWR, + TYPE_SCTP_SHUTDOWN_COMPLETE, +}; /* state_fn_t chunk_event_table[][] */ + +static sctp_sm_table_entry_t +chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = { + /* SCTP_STATE_EMPTY */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_CLOSED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_WAIT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_ECHOED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + + /* SCTP_STATE_ESTABLISHED */ + {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"}, + + /* SCTP_STATE_SHUTDOWN_PENDING */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_RECEIVED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, +}; /* chunk asconf */ + +static sctp_sm_table_entry_t +chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { + /* SCTP_STATE_EMPTY */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_CLOSED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_WAIT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_COOKIE_ECHOED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + + /* SCTP_STATE_ESTABLISHED */ + {fn: sctp_sf_discard_chunk, + name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"}, + + /* SCTP_STATE_SHUTDOWN_PENDING */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_RECEIVED */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, +}; /* chunk asconf_ack */ + +#define TYPE_SCTP_PRIMITIVE_INITIALIZE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_INITIALIZE */ + +#define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_prm_asoc, name: "sctp_sf_do_prm_asoc"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ + +#define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_cookie_wait_prm_shutdown, \ + name: "sctp_sf_cookie_wait_prm_shutdown"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_prm_shutdown, \ + name:"sctp_sf_cookie_echoed_prm_shutdown"},\ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_prm_shutdown, \ + name: "sctp_sf_do_9_2_prm_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ + +#define TYPE_SCTP_PRIMITIVE_ABORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_ABORT */ + +#define TYPE_SCTP_PRIMITIVE_SEND { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_SEND */ + +#define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE */ + +#define TYPE_SCTP_PRIMITIVE_STATUS { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_STATUS */ + +#define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */ + +#define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ + +#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */ + +#define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */ + +#define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */ + +#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */ + +#define TYPE_SCTP_PRIMITIVE_DESTROY { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_PRIMITIVE_DESTROY */ + +/* The primary index for this table is the primitive type. + * The secondary index for this table is the state. + */ +sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_PRIMITIVE_INITIALIZE, + TYPE_SCTP_PRIMITIVE_ASSOCIATE, + TYPE_SCTP_PRIMITIVE_SHUTDOWN, + TYPE_SCTP_PRIMITIVE_ABORT, + TYPE_SCTP_PRIMITIVE_SEND, + TYPE_SCTP_PRIMITIVE_SETPRIMARY, + TYPE_SCTP_PRIMITIVE_RECEIVE, + TYPE_SCTP_PRIMITIVE_STATUS, + TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT, + TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT, + TYPE_SCTP_PRIMITIVE_GETSRTTREPORT, + TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD, + TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED, + TYPE_SCTP_PRIMITIVE_DESTROY, +}; /* primitive_event_table[][] */ + +#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_2_start_shutdown, \ + name: "sctp_do_9_2_start_shutdown"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ + name: "sctp_sf_do_9_2_shutdown_ack"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +\ +} /* TYPE_SCTP_OTHER_NO_PENDING_TSN */ + +#define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_OTHER_ICMP_UNREACHFRAG */ + +sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_OTHER_NO_PENDING_TSN, + TYPE_SCTP_OTHER_ICMP_UNREACHFRAG, +}; + +#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_NONE */ + +#define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE */ + +#define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_T1_INIT */ + +#define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN */ + +#define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_T3_RTX */ + +#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_T4_RTO */ + +#define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT */ + +#define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_SACK */ + +#define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_autoclose_timer_expire, \ + name: "sctp_sf_autoclose_timer_expire"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE */ + +#define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +\ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +\ +} /* TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE */ + + +sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_EVENT_TIMEOUT_NONE, + TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, + TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, + TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, + TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, + TYPE_SCTP_EVENT_TIMEOUT_T4_RTO, + TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, + TYPE_SCTP_EVENT_TIMEOUT_SACK, + TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, + TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE, +}; + +sctp_sm_table_entry_t * +sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) +{ + if ( state > SCTP_STATE_MAX ) { BUG(); } + if ( cid < 0 ) { return &nop; } + + if ( cid <= SCTP_CID_BASE_MAX ) { + return &chunk_event_table[cid][state]; + } + + switch ( cid ) { + case SCTP_CID_ASCONF : return &chunk_event_table_asconf[state]; + case SCTP_CID_ASCONF_ACK : return &chunk_event_table_asconf_ack[state]; + default: return &nop; + } + + return &nop; +} diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c new file mode 100644 index 000000000000..1adfc8a66c33 --- /dev/null +++ b/net/sctp/sctp_socket.c @@ -0,0 +1,2923 @@ +/* Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_socket.c,v 1.62 2002/08/16 19:30:50 jgrimm Exp $ + * + * These functions interface with the sockets layer to implement the + * SCTP Extensions for the Sockets API. + * + * Note that the descriptions from the specification are USER level + * functions--this file is the functions which populate the struct proto + * for SCTP which is the BOTTOM of the sockets interface. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Narasimha Budihal + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Daisy Chang + * Sridhar Samudrala + * Inaky Perez-Gonzalez + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_socket.c,v 1.62 2002/08/16 19:30:50 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include /* for sa_family_t */ +#include +#include + +/* Forward declarations for internal helper functions. */ +static void __sctp_write_space(sctp_association_t *asoc); +static int sctp_writeable(struct sock *sk); +static inline int sctp_wspace(sctp_association_t *asoc); +static inline void sctp_set_owner_w(sctp_chunk_t *chunk); +static void sctp_wfree(struct sk_buff *skb); +static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, + int msg_len); +static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); +struct sk_buff * sctp_skb_recv_datagram(struct sock *sk, int flags, + int noblock, int *err); +static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, + int *addr_len, struct sk_buff *skb); +static inline void sctp_sk_addr_set(struct sock *, + const sockaddr_storage_t *newaddr, + sockaddr_storage_t *saveaddr); +static inline void sctp_sk_addr_restore(struct sock *, + const sockaddr_storage_t *); +static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); +static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); +static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); +static int sctp_do_bind(struct sock *, sockaddr_storage_t *, int); +static int sctp_autobind(struct sock *sk); +static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, + unsigned short snum); + +/* API 3.1.2 bind() - UDP Style Syntax + * The syntax of bind() is, + * + * ret = bind(int sd, struct sockaddr *addr, int addrlen); + * + * sd - the socket descriptor returned by socket(). + * addr - the address structure (struct sockaddr_in or struct + * sockaddr_in6 [RFC 2553]), + * addrlen - the size of the address structure. + * + * The caller should use struct sockaddr_storage described in RFC 2553 + * to represent addr for portability reason. + */ +int +sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + int retval = 0; + + sctp_lock_sock(sk); + + SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n", + sk, uaddr, addr_len); + + /* Disallow binding twice. */ + + if (0 == sctp_sk(sk)->ep->base.bind_addr.port) { + retval = sctp_do_bind(sk, (sockaddr_storage_t *)uaddr, + addr_len); + } else { + retval = -EINVAL; + } + + sctp_release_sock(sk); + + return retval; + +} /* sctp_bind() */ + +/* Bind a local address either to an endpoint or to an association. */ +static int +sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + sctp_bind_addr_t *bp = &ep->base.bind_addr; + unsigned short sa_family = newaddr->sa.sa_family; + sockaddr_storage_t tmpaddr, saveaddr; + unsigned short *snum; + int ret = 0; + + SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", + sk, newaddr, addr_len); + + /* FIXME: This function needs to handle v4-mapped-on-v6 + * addresses! + */ + + if (PF_INET == sk->family) { + if (sa_family != AF_INET) { + return -EINVAL; + } + } + + /* Make a local copy of the new address. */ + tmpaddr = *newaddr; + + switch (sa_family) { + case AF_INET: + if (addr_len < sizeof(struct sockaddr_in)) { + return -EINVAL; + } + ret = inet_addr_type(newaddr->v4.sin_addr.s_addr); + + /* FIXME: + * Should we allow apps to bind to non-local addresses by + * checking the IP sysctl parameter "ip_nonlocal_bind"? + */ + if (newaddr->v4.sin_addr.s_addr != INADDR_ANY + && ret != RTN_LOCAL) { + return -EADDRNOTAVAIL; + } + tmpaddr.v4.sin_port = htons(tmpaddr.v4.sin_port); + snum = &tmpaddr.v4.sin_port; + break; + case AF_INET6: + SCTP_V6( + /* FIXME: Hui, please verify this. Looking at + * the ipv6 code I see a SIN6_LEN_RFC2133 check. + * I'm guessing that scope_id is a newer addition. + */ + if (addr_len < sizeof(struct sockaddr_in6)) { + return -EINVAL; + } + /* FIXME - The support for IPv6 multiple types + * of addresses need to be added later. + */ + ret = sctp_ipv6_addr_type(&newaddr->v6.sin6_addr); + tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port); + snum = &tmpaddr.v6.sin6_port; + break; + ) + default: + return -EINVAL; + } /* switch(family) */ + + + SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", + bp->port, *snum); + + /* We must either be unbound, or bind to the same port. */ + if ((0 != bp->port) && (*snum != bp->port)) { + SCTP_DEBUG_PRINTK("sctp_do_bind:" + " New port %d does not match existing port " + "%d.\n", *snum, bp->port); + return -EINVAL; + } + + if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)){ + return -EACCES; + } + + + /* FIXME - Make socket understand that there might be multiple bind + * addresses and there will be multiple source addresses involved in + * routing and failover decisions. + */ + + sctp_sk_addr_set(sk, &tmpaddr, &saveaddr); + + /* Make sure we are allowed to bind here. + * The function sctp_get_port() does duplicate address + * detection. + */ + if (0 != (ret = sctp_get_port(sk, *snum))) { + sctp_sk_addr_restore(sk, &saveaddr); + if (ret == (int)sk) { + /* This endpoint has a conflicting address. */ + return -EINVAL; + } else { + return -EADDRINUSE; + } + } + + /* Refresh ephemeral port. */ + if (0 == *snum) { + *snum = inet_sk(sk)->num; + } + + /* The getsockname() API depends on 'sport' being set. */ + inet_sk(sk)->sport = htons(inet_sk(sk)->num); + + /* Add the address to the bind address list. */ + sctp_local_bh_disable(); + sctp_write_lock(&ep->base.addr_lock); + + /* Use GFP_ATOMIC since BHs are disabled. */ + if (0 != (ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { + sctp_sk_addr_restore(sk, &saveaddr); + } else if (0 == bp->port) { + bp->port = *snum; + } + + sctp_write_unlock(&ep->base.addr_lock); + sctp_local_bh_enable(); + + return ret; + +} /* sctp_do_bind */ + +/* API 8.1 sctp_bindx() + * + * The syntax of sctp_bindx() is, + * + * ret = sctp_bindx(int sd, + * struct sockaddr_storage *addrs, + * int addrcnt, + * int flags); + * + * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. + * If the sd is an IPv6 socket, the addresses passed can either be IPv4 + * or IPv6 addresses. + * + * A single address may be specified as INADDR_ANY or IPV6_ADDR_ANY, see + * section 3.1.2 for this usage. + * + * addrs is a pointer to an array of one or more socket addresses. Each + * address is contained in a struct sockaddr_storage, so each address is + * fixed length. The caller specifies the number of addresses in the + * array with addrcnt. + * + * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns -1, + * and sets errno to the appropriate error code. [ Editor's note: need + * to fill in all error code? ] + * + * For SCTP, the port given in each socket address must be the same, or + * sctp_bindx() will fail, setting errno to EINVAL . + * + * The flags parameter is formed from the bitwise OR of zero or + * more of the following currently defined flags: + * + * SCTP_BINDX_ADD_ADDR + * SCTP_BINDX_REM_ADDR + * + * SCTP_BIND_ADD_ADDR directs SCTP to add the given addresses to the + * association, and SCTP_BIND_REM_ADDR directs SCTP to remove the given + * addresses from the association. The two flags are mutually exclusive; + * if both are given, sctp_bindx() will fail with EINVAL. A caller may not + * remove all addresses from an association; sctp_bindx() will reject such + * an attempt with EINVAL. + * + * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate + * additional addresses with an endpoint after calling bind(). Or use + * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening + * socket is associated with so that no new association accepted will be + * associated with those addresses. + * + * SCTP_BIND_ADD_ADDR is defined as 0, so that it becomes the default + * behavior for sctp_bindx() when no flags are given. + * + * Adding and removing addresses from a connected association is optional + * functionality. Implementations that do not support this functionality + * should return EOPNOTSUPP. + * + * NOTE: This could be integrated into sctp_setsockopt_bindx(), + * but keeping it this way makes it easier if sometime sys_bindx is + * added. + */ + +/* Unprotected by locks. Call only with socket lock sk->lock held! See + * sctp_bindx() for a lock-protected call. + */ + +static int +__sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, + int addrcnt, int flags) +{ + int retval = 0; + + SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " + "flags: %s)\n", sk, addrs, addrcnt, + (BINDX_ADD_ADDR == flags)?"ADD": + ((BINDX_REM_ADDR == flags)?"REM":"BOGUS")); + + switch (flags) { + case BINDX_ADD_ADDR: + retval = sctp_bindx_add(sk, addrs, addrcnt); + break; + case BINDX_REM_ADDR: + retval = sctp_bindx_rem(sk, addrs, addrcnt); + break; + default: + retval = -EINVAL; + break; + } + + return retval; + +} /* __sctp_bindx() */ + +/* BINDX with locks. + * + * NOTE: Currently unused at all ... + */ +int +sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, + int flags) +{ + int retval; + + sctp_lock_sock(sk); + retval = __sctp_bindx(sk, addrs, addrcnt, flags); + sctp_release_sock(sk); + + return retval; + +} /* sctp_bindx() */ + + +/* Add a list of addresses as bind addresses to local endpoint or + * association. + * + * Basically run through each address specified in the addrs/addrcnt + * array/length pair, determine if it is IPv6 or IPv4 and call + * sctp_do_bind() on it. + * + * If any of them fails, then the operation will be reversed and the + * ones that were added will be removed. + * + * Only __sctp_bindx() is supposed to call this function. + */ +int +sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +{ + + int cnt; + int retval = 0; + int addr_len; + + SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n", + sk, addrs, addrcnt); + + for (cnt = 0; cnt < addrcnt; cnt++) { + /* The list may contain either IPv4 or IPv6 address; + * determine the address length for walking thru the list. + */ + switch (((struct sockaddr *)&addrs[cnt])->sa_family) { + case AF_INET: + addr_len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addr_len = sizeof(struct sockaddr_in6); + break; + default: + retval = -EINVAL; + goto err_bindx_add; + } + + retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], + addr_len); +err_bindx_add: + if (retval < 0) { + /* Failed. Cleanup the ones that has been added */ + if (cnt > 0) { + sctp_bindx_rem(sk, addrs, cnt); + } + return retval; + } + + } + + /* Notify the peer(s), assuming we have (an) association(s). + * FIXME: for UDP, we have a 1-1-many mapping amongst sk, ep and asoc, + * so we don't have to do much work on locating associations. + * + * However, when the separation of ep and asoc kicks in, especially + * for TCP style connection, it becomes n-1-n mapping. We will need + * to do more fine work. Until then, hold my peace. + * --xguo + * + * Really, I don't think that will be a problem. The bind() + * call on a socket will either know the endpoint + * (e.g. TCP-style listen()ing socket, or UDP-style socket), + * or exactly one association. The former case is EXACTLY + * what we have now. In the former case we know the + * association already. --piggy + * + * This code will be working on either a UDP style or a TCP style + * socket, or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the + * ADDIP code. + * --daisy + */ + +#if CONFIG_IP_SCTP_ADDIP + /* Add these addresses to all associations on this endpoint. */ + if ( retval >= 0) { + list_t *pos; + sctp_endpoint_t *ep; + sctp_association_t *asoc; + ep = sctp_sk(sk)->ep; + + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + + sctp_addip_addr_config(asoc, + SCTP_PARAM_ADD_IP, + addrs, addrcnt); + + } /* for (each association on the endpoint) */ + } +#endif + + return retval; + +} /* sctp_bindx_add() */ + + +/* Remove a list of addresses from bind addresses list. Do not remove the + * last address. + * + * Basically run through each address specified in the addrs/addrcnt + * array/length pair, determine if it is IPv6 or IPv4 and call + * sctp_del_bind() on it. + * + * If any of them fails, then the operation will be reversed and the + * ones that were removed will be added back. + * + * At least one address has to be left; if only one address is + * available, the operation will return -EBUSY. + * + * Only __sctp_bindx() is supposed to call this function. + */ +int +sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + int cnt; + sctp_bind_addr_t *bp = &ep->base.bind_addr; + int retval = 0; + sockaddr_storage_t saveaddr; + + SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", + sk, addrs, addrcnt); + + for (cnt = 0; cnt < addrcnt; cnt++) { + /* If there is only one bind address, there is nothing more + * to be removed (we need at least one address here). + */ + + if (list_empty(&bp->address_list)) { + retval = -EBUSY; + goto err_bindx_rem; + } + + /* The list may contain either IPv4 or IPv6 address; + * determine the address length for walking thru the list. + */ + switch (((struct sockaddr *)&addrs[cnt])->sa_family) { + case AF_INET: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v4.sin_port = + ntohs(saveaddr.v4.sin_port); + /* verify the port */ + if (saveaddr.v4.sin_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } + break; + case AF_INET6: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v6.sin6_port = + ntohs(saveaddr.v6.sin6_port); + /* verify the port */ + if (saveaddr.v6.sin6_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } + break; + default: + retval = -EINVAL; + goto err_bindx_rem; + } + + /* FIXME - There is probably a need to check if sk->saddr and + * sk->rcv_addr are currently set to one of the addresses to + * be removed. This is something which needs to be looked into + * when we are fixing the outstanding issues with multi-homing + * socket routing and failover schemes. Refer to comments in + * sctp_do_bind(). -daisy + */ + sctp_local_bh_disable(); + sctp_write_lock(&ep->base.addr_lock); + + retval = sctp_del_bind_addr(bp, &saveaddr); + + sctp_write_unlock(&ep->base.addr_lock); + sctp_local_bh_enable(); +err_bindx_rem: + if (retval < 0) { + /* Failed. Add the ones that has been removed back */ + if (cnt > 0) { + sctp_bindx_add(sk, addrs, cnt); + } + return retval; + } + + } + + /* + * This code will be working on either a UDP style or a TCP style + * socket, * or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the + * ADDIP code. + * --daisy + */ +#if CONFIG_IP_SCTP_ADDIP + /* Remove these addresses from all associations on this endpoint. */ + if (retval >= 0) { + list_t *pos; + sctp_endpoint_t *ep; + sctp_association_t *asoc; + ep = sctp_sk(sk)->ep; + + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + + sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, + addrs, addrcnt); + + } /* for (each association on the endpoint) */ + } +#endif + + return retval; + +} /* sctp_bindx_rem() */ + + +/* Helper for tunneling sys_bindx() requests through sctp_setsockopt() + * + * Basically do nothing but copying the addresses from user to kernel + * land and invoking sctp_bindx on the sk. This is used for tunneling + * the sctp_bindx() [sys_bindx()] request through sctp_setsockopt() + * from userspace. + * + * Note I don't use move_addr_to_kernel(): the reason is we would be + * iterating over an array of struct sockaddr_storage passing always + * what we know is a good size (sizeof (struct sock...)), so it is + * pointless. Instead check the whole area for read access and copy + * it. + * + * We don't use copy_from_user() for optimization: we first do the + * sanity checks (buffer size -fast- and access check-healthy + * pointer); if all of those succeed, then we can alloc the memory + * (expensive operation) needed to copy the data to kernel. Then we do + * the copying without checking the user space area + * (__copy_from_user()). + * + * On exit there is no need to do sockfd_put(), sys_setsockopt() does + * it. + * + * sk The sk of the socket + * addrs The pointer to the addresses in user land + * addrssize Size of the addrs buffer + * op Operation to perform (add or remove, see the flags of + * sctp_bindx) + * + * Returns 0 if ok, <0 errno code on error. + */ +static int +sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, + int addrssize, int op) +{ + struct sockaddr_storage *kaddrs; + int err; + size_t addrcnt; + + SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" + " addrssize %d opt %d\n", sk, addrs, + addrssize, op); + + /* Do we have an integer number of structs sockaddr_storage? */ + if (unlikely(addrssize <= 0 + || addrssize % sizeof(struct sockaddr_storage) != 0)) { + return -EINVAL; + } + + /* Check the user passed a healthy pointer. */ + if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize))) { + return -EFAULT; + } + + /* Alloc space for the address array in kernel memory. */ + kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); + if (unlikely(NULL == kaddrs)) { + return -ENOMEM; + } + + __copy_from_user(kaddrs, addrs, addrssize); + addrcnt = addrssize / sizeof(struct sockaddr_storage); + err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */ + kfree(kaddrs); + return err; + +} /* sctp_setsockopt_bindx() */ + + +/* API 3.1.4 close() - UDP Style Syntax + * Applications use close() to perform graceful shutdown (as described in + * Section 10.1 of [SCTP]) on ALL the associations currently represented + * by a UDP-style socket. + * + * The syntax is + * + * ret = close(int sd); + * + * sd - the socket descriptor of the associations to be closed. + * + * To gracefully shutdown a specific association represented by the + * UDP-style socket, an application should use the sendmsg() call, + * passing no user data, but including the appropriate flag in the + * ancillary data (see Section xxxx). + * + * If sd in the close() call is a branched-off socket representing only + * one association, the shutdown is performed on that association only. + */ + +void +sctp_close(struct sock *sk, long timeout) +{ + sctp_endpoint_t *ep; + sctp_association_t *asoc; + list_t *pos, *temp; + + + SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%x...)\n", + (unsigned int)sk); + + sctp_lock_sock(sk); + sk->shutdown = SHUTDOWN_MASK; + + ep = sctp_sk(sk)->ep; + + /* Walk all associations on a socket, not on an endpoint. */ + list_for_each_safe(pos, temp, &ep->asocs) { + asoc = list_entry(pos, sctp_association_t, asocs); + sctp_primitive_SHUTDOWN(asoc, NULL); + } + + + /* Clean up any skbs sitting on the receive queue. + */ + skb_queue_purge(&sk->receive_queue); + + /* This will run the backlog queue. */ + sctp_release_sock(sk); + + /* Supposedly, no process has access to the socket, but + * the net layers still may. + */ + + sctp_local_bh_disable(); + sctp_bh_lock_sock(sk); + + /* Hold the sock, since inet_sock_release() will put sock_put() + * and we have just a little more cleanup. + */ + sock_hold(sk); + inet_sock_release(sk); + + sctp_bh_unlock_sock(sk); + sctp_local_bh_enable(); + + sock_put(sk); + + SCTP_DBG_OBJCNT_DEC(sock); + +} /* sctp_close() */ + +/* API 3.1.3 sendmsg() - UDP Style Syntax + * + * An application uses sendmsg() and recvmsg() calls to transmit data to + * and receive data from its peer. + * + * ssize_t sendmsg(int socket, const struct msghdr *message, + * int flags); + * + * socket - the socket descriptor of the endpoint. + * message - pointer to the msghdr structure which contains a single + * user message and possibly some ancillary data. + * + * See Section 5 for complete description of the data + * structures. + * + * flags - flags sent or received with the user message, see Section + * 5 for complete description of the flags. + * + * NB: The argument 'msg' is a user space address. + */ +/* BUG: We do not implement timeouts. */ +/* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ + +int +sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) +{ + sctp_opt_t *sp; + sctp_endpoint_t *ep; + sctp_association_t *asoc = NULL; + sctp_transport_t *transport; + sctp_chunk_t *chunk = NULL; + sockaddr_storage_t to; + struct sockaddr *msg_name = NULL; + struct sctp_sndrcvinfo default_sinfo = {0}; + struct sctp_sndrcvinfo *sinfo; + struct sctp_initmsg *sinit; + sctp_assoc_t associd = NULL; + sctp_cmsgs_t cmsgs = {0}; + int err; + size_t msg_len; + sctp_scope_t scope; + long timeo; + uint16_t sinfo_flags = 0; + + SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, " + "size: %d)\n", sk, msg, size); + + err = 0; + sp = sctp_sk(sk); + ep = sp->ep; + + SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); + + /* Parse out the SCTP CMSGs. */ + err = sctp_msghdr_parse(msg, &cmsgs); + + if (err) { + SCTP_DEBUG_PRINTK("msghdr parse err = %x\n", err); + goto out_nounlock; + } + + /* Fetch the destination address for this packet. This + * address only selects the association--it is not necessarily + * the address we will send to. + * For a peeled-off socket, msg_name is ignored. + */ + if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { + err = sctp_sendmsg_verify_name(sk, msg); + if (err) { return err; } + + memcpy(&to, msg->msg_name, msg->msg_namelen); + SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is " + "0x%x:%u.\n", + to.v4.sin_addr.s_addr, to.v4.sin_port); + + to.v4.sin_port = ntohs(to.v4.sin_port); + msg_name = msg->msg_name; + } + + msg_len = get_user_iov_size(msg->msg_iov, msg->msg_iovlen); + + sinfo = cmsgs.info; + sinit = cmsgs.init; + + /* Did the user specify SNDRCVINFO? */ + if (sinfo) { + sinfo_flags = sinfo->sinfo_flags; + associd = sinfo->sinfo_assoc_id; + } + + SCTP_DEBUG_PRINTK("msg_len: %d, sinfo_flags: 0x%x\n", + msg_len, sinfo_flags); + + /* FIXME: Support MSG_ABORT. */ + /* If MSG_EOF is set, no data can be sent. Disallow sending 0-length + * messages when MSG_EOF is not set. + */ + if ((sinfo_flags & MSG_ABORT) + || ((sinfo_flags & MSG_EOF) && (msg_len > 0)) + || (!(sinfo_flags & MSG_EOF) && (msg_len == 0))) { + err = -EINVAL; + goto out_nounlock; + } + + sctp_lock_sock(sk); + + transport = NULL; + + SCTP_DEBUG_PRINTK("About to look up association.\n"); + /* If a msg_name has been specified, assume this is to be used. */ + if (msg_name) { + asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); + } else { + /* For a peeled-off socket, ignore any associd specified by + * the user with SNDRCVINFO. + */ + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) { + if (list_empty(&ep->asocs)) { + err = -EINVAL; + goto out_unlock; + } + asoc = list_entry(ep->asocs.next, sctp_association_t, + asocs); + } else if (associd) { + asoc = sctp_id2assoc(sk, associd); + } + if (!asoc) { + err = -EINVAL; + goto out_unlock; + } + } + + + if (asoc) { + SCTP_DEBUG_PRINTK("Just looked up association: " + "%s. \n", asoc->debug_name); + if (sinfo_flags & MSG_EOF) { + SCTP_DEBUG_PRINTK("Shutting down association: %p\n", + asoc); + sctp_primitive_SHUTDOWN(asoc, NULL); + err = 0; + goto out_unlock; + } + } + + + /* Do we need to create the association? */ + if (NULL == asoc) { + + SCTP_DEBUG_PRINTK("There is no association yet.\n"); + + /* Check for invalid stream against the stream counts, + * either the default or the user specified stream counts. + */ + if (sinfo) { + + if ((NULL == sinit) || + (sinit && (0 == sinit->sinit_num_ostreams))) { + /* Check against the defaults. */ + if (sinfo->sinfo_stream >= + sp->initmsg.sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + + } else { + /* Check against the defaults. */ + if (sinfo->sinfo_stream >= + sp->initmsg.sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + /* Check against the requested. */ + if (sinfo->sinfo_stream >= + sinit->sinit_num_ostreams) { + err = -EINVAL; + goto out_unlock; + } + + } + } + + /* + * API 3.1.2 bind() - UDP Style Syntax + * If a bind() or sctp_bindx() is not called prior to a + * sendmsg() call that initiates a new association, the + * system picks an ephemeral port and will choose an address + * set equivalent to binding with a wildcard address. + */ + if (0 == ep->base.bind_addr.port) { + if (sctp_autobind(sk)) { + err = -EAGAIN; + goto out_unlock; + } + } + + scope = sctp_scope(&to); + asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); + if (NULL == asoc) { + err = -ENOMEM; + goto out_unlock; + } + + /* If the SCTP_INIT ancillary data is specified, set all + * the association init values accordingly. + */ + if (NULL != sinit) { + if (0 != sinit->sinit_num_ostreams) { + asoc->c.sinit_num_ostreams = + sinit->sinit_num_ostreams; + } + if (0 != sinit->sinit_max_instreams) { + if (sinit->sinit_max_instreams <= + SCTP_MAX_STREAM) { + asoc->c.sinit_max_instreams = + sinit->sinit_max_instreams; + } else { + asoc->c.sinit_max_instreams = + SCTP_MAX_STREAM; + } + } + if (0 != sinit->sinit_max_attempts) { + asoc->max_init_attempts + = sinit->sinit_max_attempts; + } + if (0 != sinit->sinit_max_init_timeo) { + asoc->max_init_timeo + = sinit->sinit_max_init_timeo * HZ; + + } + } + + /* Prime the peer's transport structures. */ + transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); + + } /* if (we need an association) */ + + /* ASSERT: we have a valid association at this point. */ + SCTP_DEBUG_PRINTK("We have a valid association. \n"); + + /* API 7.1.7, the sndbuf size per association bounds the + * maximum size of data that can be sent in a single send call. + */ + if (msg_len > sk->sndbuf) { + err = -EMSGSIZE; + goto out_free; + } + + /* FIXME: In the current implementation, a single chunk is created + * for the entire message initially, even if it has to be fragmented + * later. As the length field in the chunkhdr is used to set + * the chunk length, the maximum size of the chunk and hence the + * message is limited by its type(uint16_t). + * The real fix is to fragment the message before creating the chunks. + */ + if (msg_len > ((uint16_t)(~(uint16_t)0) - + WORD_ROUND(sizeof(sctp_data_chunk_t)+1))) { + err = -EMSGSIZE; + goto out_free; + } + + /* If fragmentation is disabled and the message length exceeds the + * association fragmentation point, return EMSGSIZE. The I-D + * does not specify what this error is, but this looks like + * a great fit. + */ + if (sctp_sk(sk)->disable_fragments && (msg_len > asoc->frag_point)) { + err = -EMSGSIZE; + goto out_free; + } + + if (sinfo) { + /* Check for invalid stream. */ + if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { + err = -EINVAL; + goto out_free; + } + } else { + /* If the user didn't specify SNDRCVINFO, make up one with + * some defaults. + */ + default_sinfo.sinfo_stream = asoc->defaults.stream; + default_sinfo.sinfo_ppid = asoc->defaults.ppid; + sinfo = &default_sinfo; + } + + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); + + if (!sctp_wspace(asoc)) { + err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); + if (err) { + goto out_free; + } + } + + /* Get enough memory for the whole message. */ + chunk = sctp_make_data_empty(asoc, sinfo, msg_len); + + if (!chunk) { + err = -ENOMEM; + goto out_free; + } + +#if 0 + /* FIXME: This looks wrong so I'll comment out. + * We should be able to use this same technique for + * primary address override! --jgrimm + */ + + /* If the user gave us an address, copy it in. */ + if (NULL != msg->msg_name) { + chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk->transport) { + err = -EINVAL; + goto out_free; + } + } +#endif /* 0 */ + + /* Copy the message from the user. */ + err = sctp_user_addto_chunk(chunk, msg_len, msg->msg_iov); + + if (err < 0) { + goto out_free; + } + + SCTP_DEBUG_PRINTK("Copied message to chunk: %p.\n", chunk); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (uint8_t *)chunk->chunk_hdr + - (uint8_t *)chunk->skb->data); + + /* Do accounting for the write space. */ + sctp_set_owner_w(chunk); + + if (SCTP_STATE_CLOSED == asoc->state) { + err = sctp_primitive_ASSOCIATE(asoc, NULL); + if (err < 0) { + goto out_free; + } + SCTP_DEBUG_PRINTK("We associated primitively.\n"); + } + + + /* Send it to the lower layers. */ + err = sctp_primitive_SEND(asoc, chunk); + + SCTP_DEBUG_PRINTK("We sent primitively.\n"); + + /* BUG: SCTP_CHECK_TIMER(sk); */ + if (0 == err) { + err = msg_len; + goto out_unlock; + } + +out_free: + if (SCTP_STATE_CLOSED == asoc->state) { + sctp_association_free(asoc); + } + if (chunk) { + sctp_free_chunk(chunk); + } +out_unlock: + sctp_release_sock(sk); +out_nounlock: + return err; + +#if 0 +do_sock_err: + if (msg_len) { + err = msg_len; + } else { + err = sock_error(sk); + } + goto out; +do_interrupted: + if (msg_len) { + err = msg_len; + } + goto out; +#endif /* 0 */ + +} /* sctp_sendmsg() */ + +/* API 3.1.3 recvmsg() - UDP Style Syntax + * + * ssize_t recvmsg(int socket, struct msghdr *message, + * int flags); + * + * socket - the socket descriptor of the endpoint. + * message - pointer to the msghdr structure which contains a single + * user message and possibly some ancillary data. + * + * See Section 5 for complete description of the data + * structures. + * + * flags - flags sent or received with the user message, see Section + * 5 for complete description of the flags. + * + */ + +int +sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, + int flags, int *addr_len) +{ + sctp_ulpevent_t *event = NULL; + struct sk_buff *skb; + int copied; + int err = 0; + + SCTP_DEBUG_PRINTK("sctp_recvmsg(" + "%s: %p, %s: %p, %s: %d, %s: %d, %s: " + "0x%x, %s: %p)\n", + "sk", sk, + "msghdr", msg, + "len", len, + "knoblauch", noblock, + "flags", flags, + "addr_len", addr_len); + + sctp_lock_sock(sk); + skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); + if (!skb){ + goto out; + } + + copied = skb->len; + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list; + + for (list = skb_shinfo(skb)->frag_list; list; + list=list->next){ + copied += list->len; + } + } + + if (copied > len) { + copied = len; + msg->msg_flags |= MSG_TRUNC; + } + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + + event = (sctp_ulpevent_t *)skb->cb; + + if (err) { goto out_free; } + + sock_recv_timestamp(msg, sk, skb); + + if (sctp_ulpevent_is_notification(event)) { + msg->msg_flags |= MSG_NOTIFICATION; + } else { + /* Copy the address. */ + if (addr_len && msg->msg_name) { + sctp_sk_memcpy_msgname(sk, msg->msg_name, + addr_len, skb); + } + + } + + /* Check if we allow SCTP_SNDRCVINFO. */ + if (sctp_sk(sk)->subscribe.sctp_data_io_event) { + sctp_ulpevent_read_sndrcvinfo(event, msg); + } + +#if 0 + /* FIXME: we should be calling IP layer too. */ + if (sk->protinfo.af_inet.cmsg_flags) + ip_cmsg_recv(msg, skb); +#endif + + err = copied; + + /* FIXME: We need to support MSG_EOR correctly. */ + msg->msg_flags |= MSG_EOR; + +out_free: + sctp_ulpevent_free(event); /* Free the skb. */ +out: + sctp_release_sock(sk); + return err; + +} /* sctp_recvmsg() */ + +static inline int +sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) { + return -EINVAL; + } + + if (get_user(val, (int *)optval)) { + return -EFAULT; + } + + sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; + + return 0; + +} /* sctp_setsockopt_disable_fragments() */ + +static inline int +sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) +{ + if (optlen != sizeof(struct sctp_event_subscribe)) { + return -EINVAL; + } + + if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) { + return -EFAULT; + } + + return 0; + +} /* sctp_setsockopt_set_events() */ + +static inline int +sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) +{ + sctp_opt_t *sp = sctp_sk(sk); + + if (optlen != sizeof(int)) { + return -EINVAL; + } + + if (copy_from_user(&sp->autoclose, optval, optlen)) { + return -EFAULT; + } + + sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; + + return 0; + +} /* sctp_setsockopt_autoclose() */ + +/* API 6.2 setsockopt(), getsockopt() + * + * Applications use setsockopt() and getsockopt() to set or retrieve + * socket options. Socket options are used to change the default + * behavior of sockets calls. They are described in Section 7. + * + * The syntax is: + * + * ret = getsockopt(int sd, int level, int optname, void *optval, + * int *optlen); + * ret = setsockopt(int sd, int level, int optname, const void *optval, + * int optlen); + * + * sd - the socket descript. + * level - set to IPPROTO_SCTP for all SCTP options. + * optname - the option name. + * optval - the buffer to store the value of the option. + * optlen - the size of the buffer. + * + */ +int +sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, + int optlen) +{ + int retval = 0; + char * tmp; + sctp_protocol_t *proto = sctp_get_protocol(); + list_t *pos; + sctp_func_t *af; + + + SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", + sk, optname); + + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of setsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ + if (level != SOL_SCTP) { + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + + retval = af->setsockopt(sk, level, optname, optval, + optlen); + if (retval < 0) { goto out_nounlock; } + } + } + + sctp_lock_sock(sk); + + switch (optname) { + case SCTP_SOCKOPT_DEBUG_NAME: + + /* BUG! we don't ever seem to free this memory. --jgrimm */ + if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { + retval = -ENOMEM; + goto out_unlock; + } + + if (copy_from_user(tmp, optval, optlen)) { + retval = -EFAULT; + goto out_unlock; + } + tmp[optlen] = '\000'; + sctp_sk(sk)->ep->debug_name = tmp; + break; + case SCTP_SOCKOPT_BINDX_ADD: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + optval, optlen, BINDX_ADD_ADDR); + break; + case SCTP_SOCKOPT_BINDX_REM: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + optval, optlen, BINDX_REM_ADDR); + break; + case SCTP_DISABLE_FRAGMENTS: + retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); + break; + case SCTP_SET_EVENTS: + retval = sctp_setsockopt_set_events(sk, optval, optlen); + break; + case SCTP_AUTOCLOSE: + retval = sctp_setsockopt_autoclose(sk, optval, optlen); + break; + default: + retval = -ENOPROTOOPT; + break; + } /* switch(optname) */ + + out_unlock: + sctp_release_sock(sk); + out_nounlock: + return retval; + +} /* sctp_setsockopt() */ + + +/* FIXME: Write comments. */ +int +sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + return -EOPNOTSUPP; /* STUB */ + +} /* sctp_connect() */ + +/* FIXME: Write comments. */ +int +sctp_disconnect(struct sock *sk, int flags) +{ + return(-EOPNOTSUPP); /* STUB */ + +} /* sctp_disconnect() */ + + +/* FIXME: Write comments. */ +struct sock * +sctp_accept(struct sock *sk, int flags, int *err) +{ + int error = -EOPNOTSUPP; + + *err = error; + return NULL; + +} /* sctp_accept() */ + +/* FIXME: Write Comments. */ +int +sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + return(-EOPNOTSUPP); /* STUB */ + +} /* sctp_ioctl() */ + +/* This is the function which gets called during socket creation to + * initialized the SCTP-specific portion of the sock. + * The sock structure should already be zero-filled memory. + */ +int +sctp_init_sock(struct sock *sk) +{ + sctp_endpoint_t *ep; + sctp_protocol_t *proto; + sctp_opt_t *sp; + + SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); + + proto = sctp_get_protocol(); + + /* Create a per socket endpoint structure. Even if we + * change the data structure relationships, this may still + * be useful for storing pre-connect address information. + */ + ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); + + if (NULL == ep) { return -ENOMEM; } + + sp = sctp_sk(sk); + + /* Initialize the SCTP per socket area. */ + + sp->ep = ep; + sp->type = SCTP_SOCKET_UDP; + + /* FIXME: The next draft (04) of the SCTP Sockets Extensions + * should include a socket option for manipulating these + * message parameters (and a few others). + */ + sp->default_stream = 0; + sp->default_ppid = 0; + + /* Initialize default setup parameters. These parameters + * can be modified with the SCTP_INITMSG socket option or + * overridden by the SCTP_INIT CMSG. + */ + sp->initmsg.sinit_num_ostreams = proto->max_outstreams; + sp->initmsg.sinit_max_instreams = proto->max_instreams; + sp->initmsg.sinit_max_attempts = proto->max_retrans_init; + sp->initmsg.sinit_max_init_timeo = proto->rto_max / HZ; + + /* Initialize default RTO related parameters. These parameters can + * be modified for with the SCTP_RTOINFO socket option. + * FIXME: This are not used yet. + */ + sp->rtoinfo.srto_initial = proto->rto_initial; + sp->rtoinfo.srto_max = proto->rto_max; + sp->rtoinfo.srto_min = proto->rto_min; + + /* Initialize default event subscriptions. + * the struct sock is initialized to zero, so only + * enable the events needed. By default, UDP-style + * sockets enable io and association change notifications. + */ + if (SCTP_SOCKET_UDP == sp->type) { + sp->subscribe.sctp_data_io_event = 1; + sp->subscribe.sctp_association_event = 1; + } + + /* Default Peer Address Parameters. These defaults can + * be modified via SCTP_SET_PEER_ADDR_PARAMS + */ + sp->paddrparam.spp_hbinterval = proto->hb_interval / HZ; + sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; + + + /* If enabled no SCTP message fragmentation will be performed. + * Configure through SCTP_DISABLE_FRAGMENTS socket option. + */ + sp->disable_fragments = 0; + + /* Turn on/off any Nagle-like algorithm. */ + sp->nodelay = 0; + + /* Auto-close idle associations after the configured + * number of seconds. A value of 0 disables this + * feature. Configure through the SCTP_AUTOCLOSE socket option, + * for UDP-style sockets only. + */ + sp->autoclose = 0; + + SCTP_DBG_OBJCNT_INC(sock); + return(0); + +} /* sctp_init_sock() */ + +/* Cleanup any SCTP per socket resources. */ +int +sctp_destroy_sock(struct sock *sk) +{ + + sctp_endpoint_t *ep; + + SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); + + /* Release our hold on the endpoint. */ + ep = sctp_sk(sk)->ep; + sctp_endpoint_free(ep); + + return(0); + +} /* sctp_destroy_sock() */ + + +/* FIXME: Comments needed. */ +void sctp_shutdown(struct sock *sk, int how) +{ + /* UDP-style sockets do not support shutdown. */ + /* STUB */ +} /* sctp_shutdown() */ + +static int +sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, + int *optlen) +{ + struct sctp_status status; + sctp_endpoint_t *ep; + sctp_association_t *assoc = NULL; + sctp_transport_t *transport; + sctp_assoc_t associd; + int retval = 0; + + if (len != sizeof(status)) { + retval = -EINVAL; + goto out_nounlock; + } + + if (copy_from_user(&status, optval, sizeof(status))) { + retval = -EFAULT; + goto out_nounlock; + } + + sctp_lock_sock(sk); + + associd = status.sstat_assoc_id; + if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sctp_sk(sk)->type) && associd) { + assoc = sctp_id2assoc(sk, associd); + if (!assoc) { + retval = -EINVAL; + goto out_unlock; + } + } else { + ep = sctp_sk(sk)->ep; + if (list_empty(&ep->asocs)) { + retval = -EINVAL; + goto out_unlock; + } + + assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); + } + + transport = assoc->peer.primary_path; + + status.sstat_assoc_id = sctp_assoc2id(assoc); + status.sstat_state = assoc->state; + status.sstat_rwnd = assoc->peer.rwnd; + status.sstat_unackdata = assoc->unack_data; + status.sstat_penddata = assoc->peer.tsn_map.pending_data; + status.sstat_instrms = assoc->c.sinit_max_instreams; + status.sstat_outstrms = assoc->c.sinit_num_ostreams; + status.sstat_fragmentation_point = assoc->frag_point; + status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); + memcpy(&status.sstat_primary.spinfo_address, + &(transport->ipaddr), sizeof(sockaddr_storage_t)); + status.sstat_primary.spinfo_state = transport->state.active; + status.sstat_primary.spinfo_cwnd = transport->cwnd; + status.sstat_primary.spinfo_srtt = transport->srtt; + status.sstat_primary.spinfo_rto = transport->rto; + status.sstat_primary.spinfo_mtu = transport->pmtu; + + if (put_user(len, optlen)) { + retval = -EFAULT; + goto out_unlock; + } + + SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", + len, status.sstat_state, status.sstat_rwnd, + status.sstat_assoc_id); + + if (copy_to_user(optval, &status, len)) { + retval = -EFAULT; + goto out_unlock; + } + +out_unlock: + sctp_release_sock(sk); +out_nounlock: + return (retval); + +} /* sctp_getsockopt_sctp_status() */ + +static inline int +sctp_getsockopt_disable_fragments(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + + if (len < sizeof(int)) { + return(-EINVAL); + } + + len = sizeof(int); + + val = (sctp_sk(sk)->disable_fragments == 1); + + if (put_user(len, optlen)) { + return -EFAULT; + } + + if (copy_to_user(optval, &val, len)) { + return -EFAULT; + } + + return (0); + +} /* sctp_getsockopt_disable_fragments() */ + +static inline int +sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +{ + if (len != sizeof(struct sctp_event_subscribe)) { + return -EINVAL; + } + + if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) { + return -EFAULT; + } + + return 0; + +} /* sctp_getsockopt_set_events() */ + +static inline int +sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) +{ + if (len != sizeof(int)) { + return -EINVAL; + } + + if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) { + return -EFAULT; + } + + return 0; + +} /* sctp_getsockopt_autoclose() */ + + +/* Helper routine to branch off an association to a new socket. */ +int +sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +{ + struct sock *oldsk = assoc->base.sk; + struct sock *newsk; + struct socket *tmpsock; + sctp_endpoint_t *newep; + sctp_opt_t *oldsp = sctp_sk(oldsk); + sctp_opt_t *newsp; + int err = 0; + + /* An association cannot be branched off from an already peeled-off + * socket. + */ + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type) { + return -EINVAL; + } + + /* Create a new socket. */ + err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock); + if (err < 0) { + return (err); + } + + newsk = tmpsock->sk; + newsp = sctp_sk(newsk); + newep = newsp->ep; + + /* Migrate socket buffer sizes and all the socket level options to the + * new socket. + */ + newsk->sndbuf = oldsk->sndbuf; + newsk->rcvbuf = oldsk->rcvbuf; + *newsp = *oldsp; + + /* Restore the ep value that was overwritten with the above structure + * copy. + */ + newsp->ep = newep; + + /* Set the type of socket to indicate that it is peeled off from the + * original socket. + */ + newsp->type = SCTP_SOCKET_UDP_HIGH_BANDWIDTH; + + /* Migrate the association to the new socket. */ + sctp_assoc_migrate(assoc, newsk); + + *newsock = tmpsock; + + return (err); + +} /* sctp_do_peeloff() */ + +static inline int +sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) +{ + sctp_peeloff_arg_t peeloff; + struct socket *newsock; + int err, sd; + sctp_association_t *assoc; + + if (len != sizeof(sctp_peeloff_arg_t)) { + return -EINVAL; + } + + if (copy_from_user(&peeloff, optval, len)) { + return -EFAULT; + } + + assoc = sctp_id2assoc(sk, peeloff.associd); + if (NULL == assoc) { + return -EINVAL; + } + + SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); + + err = sctp_do_peeloff(assoc, &newsock); + if (err < 0) { + return (err); + } + + /* Map the socket to an unused fd that can be returned to the user. */ + sd = sock_map_fd(newsock); + if (sd < 0) { + sock_release(newsock); + return (sd); + } + + SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", + __FUNCTION__, sk, assoc, newsock->sk, sd); + + /* Return the fd mapped to the new socket. */ + peeloff.sd = sd; + if (copy_to_user(optval, &peeloff, len)) { + return -EFAULT; + } + + return 0; + +} /* sctp_getsockopt_peeloff() */ + +int +sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, + int *optlen) +{ + int retval = 0; + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *af; + list_t *pos; + int len; + + SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); + + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of getsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ + if (level != SOL_SCTP) { + list_for_each(pos, &proto->address_families) { + af = list_entry(pos, sctp_func_t, list); + + retval = af->getsockopt(sk, level, optname, + optval, optlen); + if (retval < 0) { return retval; } + } + } + + if (get_user(len, optlen)) { return -EFAULT;} + + switch (optname) { + case SCTP_STATUS: + retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); + break; + case SCTP_DISABLE_FRAGMENTS: + retval = sctp_getsockopt_disable_fragments(sk, len, optval, + optlen); + break; + case SCTP_SET_EVENTS: + retval = sctp_getsockopt_set_events(sk, len, optval, optlen); + break; + case SCTP_AUTOCLOSE: + retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); + break; + case SCTP_SOCKOPT_PEELOFF: + retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); + break; + default: + retval = -ENOPROTOOPT; + break; + } + + return retval; + +} /* sctp_getsockopt() */ + +void sctp_hash(struct sock *sk) +{ + /* STUB */ +} /* void sctp_hash(struct sock *sk) */ + +void sctp_unhash(struct sock *sk) +{ + /* STUB */ +} /* void sctp_unhash(struct sock *sk) */ + +/* Check if port is acceptable. Possibly find first available port. + * + * The port hash table (contained in the 'global' SCTP protocol storage + * returned by sctp_protocol_t * sctp_get_protocol()). The hash + * table is an array of 4096 lists (sctp_bind_hashbucket_t). Each + * list (the list number is the port number hashed out, so as you + * would expect from a hash function, all the ports in a given list have + * such a number that hashes out to the same list number; you were + * expecting that, right?); so each list has a set of ports, with a + * link to the socket (struct sock) that uses it, the port number and + * a fastreuse flag (FIXME: NPI ipg). + */ + +int sctp_get_port(struct sock *sk, unsigned short snum) +{ + sctp_bind_hashbucket_t *head; /* hash list */ + sctp_bind_bucket_t *pp; /* hash list port iterator */ + sctp_protocol_t *sctp = sctp_get_protocol(); + int ret; + + SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); + + sctp_local_bh_disable(); + + if (snum == 0) { + + /* Search for an available port. + * + * 'sctp->port_rover' was the last port assigned, so + * we start to search from 'sctp->port_rover + + * 1'. What we do is first check if port 'rover' is + * already in the hash table; if not, we use that; if + * it is, we try next. + */ + + int low = sysctl_local_port_range[0]; + int high = sysctl_local_port_range[1]; + int remaining = (high - low) + 1; + int rover; + int index; + + sctp_spin_lock(&sctp->port_alloc_lock); + rover = sctp->port_rover; + do { + rover++; + if ((rover < low) || (rover > high)) + rover = low; + index = sctp_phashfn(rover); + head = &sctp->port_hashtable[index]; + sctp_spin_lock(&head->lock); + for (pp = head->chain; pp; pp = pp->next) + if (pp->port == rover) + goto next; + break; + next: + sctp_spin_unlock(&head->lock); + } while (--remaining > 0); + sctp->port_rover = rover; + sctp_spin_unlock(&sctp->port_alloc_lock); + + /* Exhausted local port range during search? */ + ret = 1; + if (remaining <= 0) { + goto fail; + } + + /* OK, here is the one we will use. HEAD (the port + * hash table list entry) is non-NULL and we hold it's + * mutex. + */ + snum = rover; + pp = NULL; + + } else { + + /* We are given an specific port number; we verify + * that it is not being used. If it is used, we will + * exahust the search in the hash list corresponding + * to the port number (snum) - we detect that with the + * port iterator, pp being NULL. + */ + head = &sctp->port_hashtable[sctp_phashfn(snum)]; + sctp_spin_lock(&head->lock); + for (pp = head->chain; pp; pp = pp->next) { + if (pp->port == snum) { + break; + } + } + } + + if (pp != NULL && pp->sk != NULL) { + + /* We had a port hash table hit - there is an + * available port (pp != NULL) and it is being + * used by other socket (pp->sk != NULL); that other + * socket is going to be sk2. + */ + + int sk_reuse = sk->reuse; + sockaddr_storage_t tmpaddr; + struct sock *sk2 = pp->sk; + + SCTP_DEBUG_PRINTK("sctp_get_port() found a " + "possible match\n"); + if (pp->fastreuse != 0 && sk->reuse != 0) { + goto success; + } + + /* FIXME - multiple addresses need to be supported + * later. + */ + + switch (sk->family) { + case PF_INET: + tmpaddr.v4.sin_family = AF_INET; + tmpaddr.v4.sin_port = snum; + tmpaddr.v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; + break; + case PF_INET6: + SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; + tmpaddr.v6.sin6_port = snum; + tmpaddr.v6.sin6_addr + = inet6_sk(sk)->rcv_saddr; + ) + break; + default: + break; + } + + /* Run through the list of sockets bound to the port + * (pp->port) [via the pointers bind_next and + * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, + * we get the endpoint they describe and run through + * the endpoint's list of IP (v4 or v6) addresses, + * comparing each of the addresses with the address of + * the socket sk. If we find a match, then that means + * that this port/socket (sk) combination are already + * in an endpoint. + */ + for( ; sk2 != NULL; sk2 = sk2->bind_next) { + sctp_endpoint_t *ep2; + ep2 = sctp_sk(sk2)->ep; + + if (!sk_reuse || !sk2->reuse) { + if (sctp_bind_addr_has_addr( + &ep2->base.bind_addr, &tmpaddr)) { + goto found; + } + + } /* if (neither socket slated for reuse) */ + + } /* for (every socket in this port hash bucket) */ + found: + + /* If we found a conflict, fail. */ + if (sk2 != NULL) { + ret = (int)sk2; + goto fail_unlock; + } + SCTP_DEBUG_PRINTK("sctp_get_port(): Found a match\n"); + } /* if (we had a port hash-table hit) */ + + /* If there was a hash table miss, create a new port. */ + ret = 1; + + if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) { + goto fail_unlock; + } + + /* In either case (hit or miss), make sure fastreuse is 1 only + * if sk->reuse is too (that is, if the caller requested + * SO_REUSEADDR on this socket -sk-). + */ + if (pp->sk == NULL) { + pp->fastreuse = sk->reuse? 1 : 0; + } else if (pp->fastreuse && sk->reuse == 0) { + pp->fastreuse = 0; + } + + /* We are set, so fill up all the data in the hash table + * entry, tie the socket list information with the rest of the + * sockets FIXME: Blurry, NPI (ipg). + */ +success: + inet_sk(sk)->num = snum; + if (sk->prev == NULL) { + if ((sk->bind_next = pp->sk) != NULL) { + pp->sk->bind_pprev = &sk->bind_next; + } + pp->sk = sk; + sk->bind_pprev = &pp->sk; + sk->prev = (struct sock *) pp; + } + ret = 0; + +fail_unlock: + sctp_spin_unlock(&head->lock); +fail: + sctp_local_bh_enable(); + + SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret); + return ret; + +} /* sctp_get_port() */ + + +/* + * 3.1.3 listen() - UDP Style Syntax + * + * By default, new associations are not accepted for UDP style sockets. + * An application uses listen() to mark a socket as being able to + * accept new associations. + * + */ +int sctp_seqpacket_listen(struct sock *sk, int backlog) +{ + sctp_opt_t *sp = sctp_sk(sk); + sctp_endpoint_t *ep = sp->ep; + + /* Only UDP style sockets that are not peeled off are allowed to + * listen(). + */ + if (SCTP_SOCKET_UDP != sp->type) { + return (-EINVAL); + } + + /* + * If a bind() or sctp_bindx() is not called prior to a listen() + * call that allows new associations to be accepted, the system + * picks an ephemeral port and will choose an address set equivalent + * to binding with a wildcard address. + * + * This is not currently spelled out in the SCTP sockets + * extensions draft, but follows the practice as seen in TCP + * sockets. + */ + if (0 == ep->base.bind_addr.port) { + if (sctp_autobind(sk)) { + return (-EAGAIN); + } + } + + + sk->state = SCTP_SS_LISTENING; + sctp_hash_endpoint(ep); + + return 0; + +} /* sctp_seqpacket_listen() */ + +/* + * Move a socket to LISTENING state. + */ +int sctp_inet_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err; + + sctp_lock_sock(sk); + + err = -EINVAL; + if (sock->state != SS_UNCONNECTED) { + goto out; + } + + switch (sock->type) { + case SOCK_SEQPACKET: + err = sctp_seqpacket_listen(sk, backlog); + break; + case SOCK_STREAM: + /* FIXME for TCP-style sockets. */ + err = -EOPNOTSUPP; + default: + goto out; + } + +out: + sctp_release_sock(sk); + return err; + +} /* sctp_inet_listen() */ + +/* + * This function is done by modeling the current datagram_poll() and the + * tcp_poll(). Note that, based on these implementations, we don't + * lock the socket in this function, even though it seems that, + * ideally, locking or some other mechanisms can be used to ensure + * the integrity of the counters (sndbuf and wmem_queued) used + * in this place. We assume that we don't need locks either until proven + * otherwise. + * + * Another thing to note is that we include the Async I/O support + * here, again, by modeling the current TCP/UDP code. We don't have + * a good way to test with it yet. + */ +unsigned int +sctp_poll(struct file *file, struct socket *sock, poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask; + + poll_wait(file, sk->sleep, wait); + mask = 0; + + /* Is there any exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)) { + mask |= POLLERR; + } + if (sk->shutdown == SHUTDOWN_MASK) { + mask |= POLLHUP; + } + + /* Is it readable? Reconsider this code with TCP-style support. */ + if (!skb_queue_empty(&sk->receive_queue) + || (sk->shutdown & RCV_SHUTDOWN)) { + mask |= POLLIN | POLLRDNORM; + } + + /* + * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and + * peeled off sockets. Additionally, TCP-style needs to consider + * other establishment conditions. + */ + if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { + /* The association is going away. */ + if (SCTP_SS_DISCONNECTING == sk->state) { + mask |= POLLHUP; + } + /* The association is either gone or not ready. */ + if (SCTP_SS_CLOSED == sk->state) { + return mask; + } + } + + /* Is it writable? */ + if (sctp_writeable(sk)) { + mask |= POLLOUT | POLLWRNORM; + } else { + set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + /* + * Since the socket is not locked, the buffer + * might be made available after the writeable check and + * before the bit is set. This could cause a lost I/O + * signal. tcp_poll() has a race breaker for this race + * condition. Based on their implementation, we put + * in the following code to cover it as well. + */ + if (sctp_writeable(sk)) { + mask |= POLLOUT | POLLWRNORM; + } + } + + + return mask; +} + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + + +static sctp_bind_bucket_t * +sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) +{ + sctp_bind_bucket_t *pp; + + SCTP_DEBUG_PRINTK( "sctp_bucket_create() begins, snum=%d\n", snum); + pp = kmalloc(sizeof(sctp_bind_bucket_t), GFP_ATOMIC); + if (pp != NULL) { + pp->port = snum; + pp->fastreuse = 0; + pp->sk = NULL; + if ((pp->next = head->chain) != NULL) + pp->next->pprev = &pp->next; + head->chain= pp; + pp->pprev = &head->chain; + } + SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); + return(pp); + +} /* sctp_bucket_create() */ + +/* FIXME: Commments! */ +__inline__ void __sctp_put_port(struct sock *sk) +{ + sctp_protocol_t *sctp_proto = sctp_get_protocol(); + sctp_bind_hashbucket_t *head = + &sctp_proto->port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; + sctp_bind_bucket_t *pp; + + sctp_spin_lock(&head->lock); + pp = (sctp_bind_bucket_t *) sk->prev; + if (sk->bind_next) + sk->bind_next->bind_pprev = sk->bind_pprev; + *(sk->bind_pprev) = sk->bind_next; + sk->prev = NULL; + inet_sk(sk)->num = 0; + if (pp->sk == NULL) { + if (pp->next) + pp->next->pprev = pp->pprev; + *(pp->pprev) = pp->next; + kfree(pp); + } + sctp_spin_unlock(&head->lock); + +} /* __sctp_put_port() */ + +void +sctp_put_port(struct sock *sk) +{ + sctp_local_bh_disable(); + __sctp_put_port(sk); + sctp_local_bh_enable(); + +} /* sctp_put_port() */ + +/* + * The system picks an ephemeral port and choose an address set equivalent + * to binding with a wildcard address. + * One of those addresses will be the primary address for the association. + * This automatically enables the multihoming capability of SCTP. + */ +int +sctp_autobind(struct sock *sk) +{ + sockaddr_storage_t autoaddr; + int addr_len=0; + + memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); + + switch(sk->family){ + case PF_INET: + autoaddr.v4.sin_family = AF_INET; + autoaddr.v4.sin_addr.s_addr = INADDR_ANY; + autoaddr.v4.sin_port = htons(inet_sk(sk)->num); + addr_len = sizeof(struct sockaddr_in); + break; + case PF_INET6: + SCTP_V6( + /* FIXME: Write me for v6! */ + BUG(); + autoaddr.v6.sin6_family = AF_INET6; + autoaddr.v6.sin6_port = htons(inet_sk(sk)->num); + addr_len = sizeof(struct sockaddr_in6); + ); + break; + default: /* This should not happen. */ + break; + } /* switch(family) */ + + return(sctp_do_bind(sk, &autoaddr, addr_len)); + +} /* sctp_autobind() */ + + +/* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. + * + * From RFC 2292 + * 4.2 The cmsghdr Structure * + * + * When ancillary data is sent or received, any number of ancillary data + * objects can be specified by the msg_control and msg_controllen members of + * the msghdr structure, because each object is preceded by + * a cmsghdr structure defining the object's length (the cmsg_len member). + * Historically Berkeley-derived implementations have passed only one object + * at a time, but this API allows multiple objects to be + * passed in a single call to sendmsg() or recvmsg(). The following example + * shows two ancillary data objects in a control buffer. + * + * |<--------------------------- msg_controllen -------------------------->| + * | | + * + * |<----- ancillary data object ----->|<----- ancillary data object ----->| + * + * |<---------- CMSG_SPACE() --------->|<---------- CMSG_SPACE() --------->| + * | | | + * + * |<---------- cmsg_len ---------->| |<--------- cmsg_len ----------->| | + * + * |<--------- CMSG_LEN() --------->| |<-------- CMSG_LEN() ---------->| | + * | | | | | + * + * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ + * |cmsg_|cmsg_|cmsg_|XX| |XX|cmsg_|cmsg_|cmsg_|XX| |XX| + * + * |len |level|type |XX|cmsg_data[]|XX|len |level|type |XX|cmsg_data[]|XX| + * + * +-----+-----+-----+--+-----------+--+-----+-----+-----+--+-----------+--+ + * ^ + * | + * + * msg_control + * points here + * + */ +int +sctp_msghdr_parse(const struct msghdr *msg, + sctp_cmsgs_t *cmsgs) +{ + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { + + /* Check for minimum length. The SCM code has this check. */ + if (cmsg->cmsg_len < sizeof(struct cmsghdr) || + (unsigned long)(((char*)cmsg - (char*)msg->msg_control) + + cmsg->cmsg_len) > msg->msg_controllen) { + return -EINVAL; + } + + /* Should we parse this header or ignore? */ + if (cmsg->cmsg_level != IPPROTO_SCTP) { + continue; + } + + /* Strictly check lengths following example in SCM code. */ + switch (cmsg->cmsg_type) { + case SCTP_INIT: + /* SCTP Socket API Extension (draft 1) + * 5.2.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for + * initializing new SCTP associations with sendmsg(). + * The SCTP_INITMSG socket option uses this same data + * structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + */ + + if (cmsg->cmsg_len + != CMSG_LEN(sizeof(struct sctp_initmsg))) + return -EINVAL; + cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); + + break; + + case SCTP_SNDRCV: + /* SCTP Socket API Extension (draft 1) + * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for + * sendmsg() and describes SCTP header information + * about a received message through recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + */ + if (cmsg->cmsg_len + != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) { + return -EINVAL; + } + + cmsgs->info = (struct sctp_sndrcvinfo*)CMSG_DATA(cmsg); + + /* Minimally, validate the sinfo_flags. */ + if (cmsgs->info->sinfo_flags + & ~(MSG_UNORDERED|MSG_ADDR_OVER + |MSG_ABORT|MSG_EOF)){ + + return -EINVAL; + } + + break; + default: + return -EINVAL; + + } /* switch(cmsg_type) */ + } + return 0; + +} /* sctp_msghdr_parse()*/ + + +/* Setup sk->rcv_saddr before calling get_port(). */ +static inline void +sctp_sk_addr_set(struct sock *sk, + const sockaddr_storage_t *newaddr, + sockaddr_storage_t *saveaddr) +{ + struct inet_opt *inet = inet_sk(sk); + + saveaddr->sa.sa_family = newaddr->sa.sa_family; + + switch(newaddr->sa.sa_family){ + case AF_INET: + saveaddr->v4.sin_addr.s_addr = inet->rcv_saddr; + inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr; + break; + case AF_INET6: + SCTP_V6({ + struct ipv6_pinfo *np = inet6_sk(sk); + + saveaddr->v6.sin6_addr = np->rcv_saddr; + np->rcv_saddr = np->saddr = newaddr->v6.sin6_addr; + break; + }) + default: + break; + } + +} /* sctp_sk_addr_store() */ + + +/* Restore sk->rcv_saddr after failing get_port(). */ +static inline void +sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) +{ + struct inet_opt *inet = inet_sk(sk); + + switch(addr->sa.sa_family){ + case AF_INET: + inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr; + break; + case AF_INET6: + SCTP_V6({ + struct ipv6_pinfo *np = inet6_sk(sk); + + np->rcv_saddr = np->saddr = addr->v6.sin6_addr; + break; + }) + default: + break; + } + +} /* sctp_sk_addr_restore() */ + +/* + * Wait for a packet.. + * Note: This function is the same function as in core/datagram.c + * with a few modifications to make lksctp work. + */ +static int +sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) +{ + int error; + + DECLARE_WAITQUEUE(wait, current); + + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue_exclusive(sk->sleep, &wait); + + /* Socket errors? */ + error = sock_error(sk); + if (error) { + goto out; + } + + if (!skb_queue_empty(&sk->receive_queue)) { + goto ready; + } + + /* Socket shut down? */ + if (sk->shutdown & RCV_SHUTDOWN) { + goto out; + } + + /* Sequenced packets can come disconnected. If so we report the + * problem. + */ + error = -ENOTCONN; + + /* Is there a good reason to think that we may receive some data? */ + if ((list_empty(&sctp_sk(sk)->ep->asocs)) + && (sk->state != SCTP_SS_LISTENING)) { + goto out; + } + + /* Handle signals. */ + if (signal_pending(current)) { + goto interrupted; + } + + /* Let another process have a go. Since we are going to sleep + * anyway. Note: This may cause odd behaviors if the message + * does not fit in the user's buffer, but this seems to be the + * only way to honor MSG_DONTWAIT realistically. + */ + sctp_release_sock(sk); + *timeo_p = schedule_timeout(*timeo_p); + sctp_lock_sock(sk); + +ready: + remove_wait_queue(sk->sleep, &wait); + __set_current_state(TASK_RUNNING); + return 0; + +interrupted: + error = sock_intr_errno(*timeo_p); +out: + remove_wait_queue(sk->sleep, &wait); + __set_current_state(TASK_RUNNING); + *err = error; + return error; + +} /* sctp_wait_for_packet() */ + + +/* Receive a datagram. + * Note: This is pretty much the same routine as in core/datagram.c + * with a few changes to make lksctp work. + */ +struct sk_buff * +sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +{ + int error; + struct sk_buff *skb; + long timeo; + + /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + error = sock_error(sk); + if (error) { + goto no_packet; + } + + timeo = sock_rcvtimeo(sk, noblock); + + SCTP_DEBUG_PRINTK("Timeout: timeo: %ld, MAX: %ld.\n", + timeo, MAX_SCHEDULE_TIMEOUT); + + do { + /* Again only user level code calls this function, + * so nothing interrupt level + * will suddenly eat the receive_queue. + * + * Look at current nfs client by the way... + * However, this function was corrent in any case. 8) + */ + if (flags & MSG_PEEK) { + unsigned long cpu_flags; + + sctp_spin_lock_irqsave(&sk->receive_queue.lock, + cpu_flags); + skb = skb_peek(&sk->receive_queue); + if (skb!=NULL) + atomic_inc(&skb->users); + sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, + cpu_flags); + } else { + skb = skb_dequeue(&sk->receive_queue); + } + + if (skb) { return skb; } + + /* User doesn't want to wait */ + error = -EAGAIN; + if (!timeo) + goto no_packet; + + } while (sctp_wait_for_packet(sk, err, &timeo) == 0); + + return NULL; + +no_packet: + *err = error; + return NULL; + +} /* sctp_skb_recv_datagram() */ + + +/* Copy an approriately formatted address for msg_name. */ +static inline void +sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, int *addr_len, + struct sk_buff *skb) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6 __attribute__ ((unused)); + struct sctphdr *sh; + + /* The sockets layer handles copying this out to user space. */ + + switch (sk->family) { + case PF_INET: + + sin = (struct sockaddr_in *)msgname; + if (addr_len) { + *addr_len = sizeof(struct sockaddr_in); + } + sin->sin_family = AF_INET; + + sh = (struct sctphdr *)skb->h.raw; + sin->sin_port = sh->source; + sin->sin_addr.s_addr = skb->nh.iph->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + break; + case PF_INET6: + SCTP_V6( + + /* FIXME: Need v6 code here. We should convert + * V4 addresses to PF_INET6 format. See ipv6/udp.c + * for an example. --jgrimm + */ + ); + break; + default: /* Should not get here. */ + break; + } + +} /* sctp_sk_memcpy_msgname() */ + + +static inline int +sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) +{ + sockaddr_storage_t *sa; + + if (msg->msg_namelen < sizeof (struct sockaddr) ) { + return (-EINVAL); + } + sa = (sockaddr_storage_t *)(msg->msg_name); + switch (sa->sa.sa_family) { + case AF_INET: + if (msg->msg_namelen < sizeof(struct sockaddr_in)) { + return(-EINVAL); + } + break; + case AF_INET6: + if (PF_INET == sk->family) { + return(-EINVAL); + } + SCTP_V6( + if (msg->msg_namelen < sizeof(struct sockaddr_in6)) { + return(-EINVAL); + } + break; + ); + default: + return (-EINVAL); + } + + /* Disallow any illegal addresses to be used as destinations. */ + if (!sctp_addr_is_valid(sa)) { + return(-EINVAL); + } + + return 0; + +} /* sctp_sendmsg_verify_name() */ + + +/* Get the sndbuf space available at the time on the association. */ +static inline int +sctp_wspace(sctp_association_t *asoc) +{ + struct sock *sk = asoc->base.sk; + int amt = 0; + + amt = sk->sndbuf - asoc->sndbuf_used; + if (amt < 0) { + amt = 0; + } + return amt; + +} /* sctp_wspace() */ + + +/* Increment the used sndbuf space count of the corresponding association by + * the size of the outgoing data chunk. + * Also, set the skb destructor for sndbuf accounting later. + * + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * destructor in the data chunk skb for the purpose of the sndbuf space + * tracking. + */ +static inline void +sctp_set_owner_w(sctp_chunk_t *chunk) +{ + sctp_association_t *asoc = chunk->asoc; + struct sock *sk = asoc->base.sk; + + + /* The sndbuf space is tracked per association. */ + sctp_association_hold(asoc); + + chunk->skb->destructor = sctp_wfree; + /* Save the chunk pointer in skb for sctp_wfree to use later. */ + *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); + sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); + +} /* sctp_set_owner_w() */ + +/* Do accounting for the sndbuf space. + * Decrement the used sndbuf space of the corresponding association by the + * data size which was just transmitted(freed). + */ +static void +sctp_wfree(struct sk_buff *skb) +{ + sctp_association_t *asoc; + sctp_chunk_t *chunk; + struct sock *sk; + + + /* Get the saved chunk pointer. */ + chunk = *((sctp_chunk_t **)(skb->cb)); + asoc = chunk->asoc; + sk = asoc->base.sk; + asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); + sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + __sctp_write_space(asoc); + + sctp_association_put(asoc); + +} /* sctp_wfree() */ + + +/* Helper function to wait for space in the sndbuf. */ +static int +sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len) +{ + struct sock *sk = asoc->base.sk; + int err = 0; + long current_timeo = *timeo_p; + DECLARE_WAITQUEUE(wait, current); + + SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", + asoc, (long)(*timeo_p), msg_len); + + /* Wait on the association specific sndbuf space. */ + add_wait_queue_exclusive(&asoc->wait, &wait); + + /* Increment the association's refcnt. */ + sctp_association_hold(asoc); + + for (;;) { + + set_current_state(TASK_INTERRUPTIBLE); + + if (!*timeo_p) { + goto do_nonblock; + } + + if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + asoc->base.dead) { + goto do_error; + } + + if (signal_pending(current)) { + goto do_interrupted; + } + + if (msg_len <= sctp_wspace(asoc)) { + break; + } + + /* Let another process have a go. Since we are going + * to sleep anyway. + */ + + sctp_release_sock(sk); + + current_timeo = schedule_timeout(current_timeo); + + sctp_lock_sock(sk); + + *timeo_p = current_timeo; + } + +out: + + remove_wait_queue(&asoc->wait, &wait); + + /* Release the association's refcnt. */ + sctp_association_put(asoc); + + __set_current_state(TASK_RUNNING); + return err; + +do_error: + err = -EPIPE; + goto out; + +do_interrupted: + err = sock_intr_errno(*timeo_p); + goto out; + +do_nonblock: + err = -EAGAIN; + goto out; + +} /* sctp_wait_for_sndbuf() */ + + +/* If sndbuf has changed, wake up per association sndbuf waiters. */ +static void +__sctp_write_space(sctp_association_t *asoc) +{ + struct sock *sk = asoc->base.sk; + struct socket *sock = sk->socket; + + if ((sctp_wspace(asoc) > 0) && sock) { + if (waitqueue_active(&asoc->wait)) { + wake_up_interruptible(&asoc->wait); + } + if (sctp_writeable(sk)) { + if (sk->sleep && waitqueue_active(sk->sleep)) { + wake_up_interruptible(sk->sleep); + } + /* Note that we try to include the Async I/O support + * here by modeling from the current TCP/UDP code. + * We have not tested with it yet. + */ + if (sock->fasync_list + && !(sk->shutdown & SEND_SHUTDOWN)) { + sock_wake_async(sock, 2, POLL_OUT); + } + } + } + +} /* __sctp_write_space() */ + + +/* If socket sndbuf has changed, wake up all per association waiters. */ +void +sctp_write_space(struct sock *sk) +{ + sctp_association_t *asoc; + list_t *pos; + + /* Wake up the tasks in each wait queue. */ + list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { + asoc = list_entry(pos, sctp_association_t, asocs); + __sctp_write_space(asoc); + } + +} /* sctp_write_space() */ + +/* Is there any sndbuf space available on the socket? + * + * Note that wmem_queued is the sum of the send buffers on all of the + * associations on the same socket. For a UDP-style socket with + * multiple associations, it is possible for it to be "unwriteable" + * prematurely. I assume that this is acceptable because + * a premature "unwriteable" is better than an accidental "writeable" which + * would cause an unwanted block under certain circumstances. For the 1-1 + * UDP-style sockets or TCP-style sockets, this code should work. + * - Daisy + */ +static int +sctp_writeable(struct sock *sk) +{ + + int amt = 0; + + amt = sk->sndbuf - sk->wmem_queued; + if (amt < 0) { + amt = 0; + } + return amt; + +} /* sctp_writeable() */ + +/* This proto struct describes the ULP interface for SCTP. */ +struct proto sctp_prot = { + .name = "SCTP", + .close = sctp_close, + .connect = sctp_connect, + .disconnect = sctp_disconnect, + .accept = sctp_accept, + .ioctl = sctp_ioctl, + .init = sctp_init_sock, + .destroy = sctp_destroy_sock, + .shutdown = sctp_shutdown, + .setsockopt = sctp_setsockopt, + .getsockopt = sctp_getsockopt, + .sendmsg = sctp_sendmsg, + .recvmsg = sctp_recvmsg, + .bind = sctp_bind, + .backlog_rcv = sctp_backlog_rcv, + .hash = sctp_hash, + .unhash = sctp_unhash, + .get_port = sctp_get_port, +}; diff --git a/net/sctp/sctp_sysctl.c b/net/sctp/sctp_sysctl.c new file mode 100644 index 000000000000..fb9f8ffaff30 --- /dev/null +++ b/net/sctp/sctp_sysctl.c @@ -0,0 +1,110 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2002 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sysctl.c,v 1.2 2002/07/12 14:50:25 jgrimm Exp $ + * + * Sysctl related interfaces for SCTP. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Mingqin Liu + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sysctl.c,v 1.2 2002/07/12 14:50:25 jgrimm Exp $"; + +#include +#include + +extern sctp_protocol_t sctp_proto; + +static ctl_table sctp_table[] = { + {NET_SCTP_RTO_INITIAL, "rto_initial", + &sctp_proto.rto_initial, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_SCTP_RTO_MIN, "rto_min", + &sctp_proto.rto_min, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_SCTP_RTO_MAX, "rto_max", + &sctp_proto.rto_max, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_SCTP_VALID_COOKIE_LIFE, "valid_cookie_life", + &sctp_proto.valid_cookie_life, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_SCTP_MAX_BURST, "max_burst", + &sctp_proto.max_burst, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_SCTP_ASSOCIATION_MAX_RETRANS, "association_max_retrans", + &sctp_proto.max_retrans_association, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_SCTP_PATH_MAX_RETRANS, "path_max_retrans", + &sctp_proto.max_retrans_path, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_SCTP_MAX_INIT_RETRANSMITS, "max_init_retransmits", + &sctp_proto.max_retrans_init, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_SCTP_HB_INTERVAL, "hb_interval", + &sctp_proto.hb_interval, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor", + &sctp_proto.rto_alpha, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_SCTP_RTO_BETA, "rto_beta_exp_divisor", + &sctp_proto.rto_beta, sizeof(int), 0644, NULL, + &proc_dointvec}, + {0} +}; + +static ctl_table sctp_net_table[] = { + {NET_SCTP, "sctp", NULL, 0, 0555, sctp_table}, + {0} +}; + +static ctl_table sctp_root_table[] = { + {CTL_NET, "net", NULL, 0, 0555, sctp_net_table}, + {0} +}; + +static struct ctl_table_header * sctp_sysctl_header; + +/* Sysctl registration. */ +void sctp_sysctl_register(void) +{ + sctp_sysctl_header = register_sysctl_table(sctp_root_table, 0); + +} /* sctp_sysctl_register() */ + +/* Sysctl deregistration. */ +void sctp_sysctl_unregister(void) +{ + unregister_sysctl_table(sctp_sysctl_header); + +} /* sctp_sysctl_unregister() */ + diff --git a/net/sctp/sctp_transport.c b/net/sctp/sctp_transport.c new file mode 100644 index 000000000000..407c9aa71b07 --- /dev/null +++ b/net/sctp/sctp_transport.c @@ -0,0 +1,476 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_transport.c,v 1.11 2002/06/20 05:57:01 samudrala Exp $ + * + * This module provides the abstraction for an SCTP tranport representing + * a remote transport address. For local transport addresses, we just use + * sockaddr_storage_t. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_transport.c,v 1.11 2002/06/20 05:57:01 samudrala Exp $"; + +#include +#include +#include + +/* 1st Level Abstractions. */ + +/* Allocate and initialize a new transport. */ +sctp_transport_t * +sctp_transport_new(const sockaddr_storage_t *addr, int priority) +{ + sctp_transport_t *transport; + + transport = t_new(sctp_transport_t, priority); + if (NULL == transport) { + goto fail; + } + + if (NULL == sctp_transport_init(transport, addr, priority)) { + goto fail_init; + } + + transport->malloced = 1; + SCTP_DBG_OBJCNT_INC(transport); + + return transport; + +fail_init: + kfree(transport); +fail: + return NULL; + +} /* sctp_transport_new() */ + + +/* Intialize a new transport from provided memory. */ +sctp_transport_t * +sctp_transport_init(sctp_transport_t *peer, + const sockaddr_storage_t *addr, + int priority) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + + /* Copy in the address. */ + peer->ipaddr = *addr; + peer->af_specific = sctp_get_af_specific(addr); + peer->asoc = NULL; + peer->pmtu = peer->af_specific->get_dst_mtu(addr); + + /* From 6.3.1 RTO Calculation: + * + * C1) Until an RTT measurement has been made for a packet sent to the + * given destination transport address, set RTO to the protocol + * parameter 'RTO.Initial'. + */ + peer->rtt = 0; + peer->rto = proto->rto_initial; + peer->rttvar = 0; + peer->srtt = 0; + peer->rto_pending = 0; + + peer->last_time_heard = jiffies; + peer->last_time_used = jiffies; + peer->last_time_ecne_reduced = jiffies; + + peer->state.active = 1; + peer->state.hb_allowed = 0; + + /* Initialize the default path max_retrans. */ + peer->max_retrans = proto->max_retrans_path; + peer->error_threshold = 0; + peer->error_count = 0; + + peer->debug_name = "unnamedtransport"; + + INIT_LIST_HEAD(&peer->transmitted); + INIT_LIST_HEAD(&peer->send_ready); + INIT_LIST_HEAD(&peer->transports); + + /* Set up the retransmission timer. */ + init_timer(&peer->T3_rtx_timer); + peer->T3_rtx_timer.function = sctp_generate_t3_rtx_event; + peer->T3_rtx_timer.data = (unsigned long)peer; + + /* Set up the heartbeat timer. */ + init_timer(&peer->hb_timer); + peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + peer->hb_timer.function = sctp_generate_heartbeat_event; + peer->hb_timer.data = (unsigned long)peer; + + atomic_set(&peer->refcnt, 1); + peer->dead = 0; + + peer->malloced = 0; + return peer; + +} /* sctp_transport_init() */ + +/* This transport is no longer needed. Free up if possible, or + * delay until it last reference count. + */ +void +sctp_transport_free(sctp_transport_t *transport) +{ + transport->dead = 1; + + /* Try to delete the heartbeat timer. */ + if (del_timer(&transport->hb_timer)) { + sctp_transport_put(transport); + } + + sctp_transport_put(transport); + +} /* sctp_transport_free() */ + + +/* Destroy the transport data structure. + * Assumes there are no more users of this structure. +*/ +void +sctp_transport_destroy(sctp_transport_t *transport) +{ + SCTP_ASSERT(transport->dead, "Transport is not dead", return); + + if (transport->asoc) { + sctp_association_put(transport->asoc); + } + + kfree(transport); + SCTP_DBG_OBJCNT_DEC(transport); + +} /* sctp_transport_destroy() */ + + +/* Start T3_rtx timer if it is not already running and update the heartbeat + * timer. This routine is called everytime a DATA chunk is sent. + */ +void +sctp_transport_reset_timers(sctp_transport_t *transport) +{ + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R1) Every time a DATA chunk is sent to any address(including a + * retransmission), if the T3-rtx timer of that address is not running + * start it running so that it will expire after the RTO of that + * address. + */ + if (!timer_pending(&transport->T3_rtx_timer)) { + if (!mod_timer(&transport->T3_rtx_timer, + jiffies + transport->rto)) { + sctp_transport_hold(transport); + } + } + + /* When a data chunk is sent, reset the heartbeat interval. */ + if (!mod_timer(&transport->hb_timer, + transport->hb_interval + transport->rto + jiffies)) { + sctp_transport_hold(transport); + } + +} /* sctp_transport_reset_timers() */ + +/* This transport has been assigned to an association. + * Initialize fields from the association or from the sock itself. + * Register the reference count in the association. + */ +void sctp_transport_set_owner(sctp_transport_t *transport, + sctp_association_t *asoc) +{ + transport->asoc = asoc; + sctp_association_hold(asoc); + +} /* sctp_transport_set_owner() */ + +/* Hold a reference to a transport. */ +void sctp_transport_hold(sctp_transport_t *transport) +{ + atomic_inc(&transport->refcnt); + +} /* sctp_transport_hold() */ + +/* Release a reference to a transport and clean up + * if there are no more references. + */ +void sctp_transport_put(sctp_transport_t *transport) +{ + if (atomic_dec_and_test(&transport->refcnt)) { + sctp_transport_destroy(transport); + } + +} /* sctp_transport_put() */ + +/* Update transport's RTO based on the newly calculated RTT. */ +void +sctp_transport_update_rto(sctp_transport_t *tp, uint32_t rtt) +{ + sctp_protocol_t *proto = sctp_get_protocol(); + + /* Check for valid transport. */ + SCTP_ASSERT(tp, "NULL transport", return); + + /* We should not be doing any RTO updates unless rto_pending is set. */ + SCTP_ASSERT(tp->rto_pending, "rto_pending not set", return); + + if (tp->rttvar || tp->srtt) { + /* 6.3.1 C3) When a new RTT measurement R' is made, set + * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| + * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' + */ + + /* Note: The above algorithm has been rewritten to + * express rto_beta and rto_alpha as inverse powers + * of two. + * For example, assuming the default value of RTO.Alpha of + * 1/8, rto_alpha would be expressed as 3. + */ + tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) + + ((abs(tp->srtt - rtt)) >> proto->rto_beta); + tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) + + (rtt >> proto->rto_alpha); + + } else { + /* 6.3.1 C2) When the first RTT measurement R is made, set + * SRTT <- R, RTTVAR <- R/2. + */ + tp->srtt = rtt; + tp->rttvar = rtt >> 1; + } + + /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then + * adjust RTTVAR <- G, where G is the CLOCK GRANULARITY. + */ + if (tp->rttvar == 0) { + tp->rttvar = SCTP_CLOCK_GRANULARITY; + } + + /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ + tp->rto = tp->srtt + (tp->rttvar << 2); + + /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min + * seconds then it is rounded up to RTO.Min seconds. + */ + if (tp->rto < tp->asoc->rto_min) { + tp->rto = tp->asoc->rto_min; + } + + /* 6.3.1 C7) A maximum value may be placed on RTO provided it is + * at least RTO.max seconds. + */ + if (tp->rto > tp->asoc->rto_max) { + tp->rto = tp->asoc->rto_max; + } + + tp->rtt = rtt; + + /* Reset rto_pending so that a new RTT measurement is started when a + * new data chunk is sent. + */ + tp->rto_pending = 0; + + SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p, rtt: %d, srtt: %d " + "rttvar: %d, rto: %d\n", + tp, rtt, tp->srtt, tp->rttvar, tp->rto); + +} /* sctp_transport_update_rto() */ + +/* This routine updates the transport's cwnd and partial_bytes_acked + * parameters based on the bytes acked in the received SACK. + */ +void +sctp_transport_raise_cwnd(sctp_transport_t *transport, uint32_t sack_ctsn, + uint32_t bytes_acked) +{ + uint32_t cwnd, ssthresh, flight_size, pba, pmtu; + + cwnd = transport->cwnd; + flight_size = transport->flight_size; + + /* The appropriate cwnd increase algorithm is performed if, and only + * if the cumulative TSN has advanced and the congestion window is + * being fully utilized. + */ + if ((transport->asoc->ctsn_ack_point >= sack_ctsn) + || (flight_size < cwnd)) { + return; + } + + ssthresh = transport->ssthresh; + pba = transport->partial_bytes_acked; + pmtu = transport->asoc->pmtu; + + if (cwnd <= ssthresh) { + /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less + * than or equal to ssthresh an SCTP endpoint MUST use the + * slow start algorithm to increase cwnd only if the current + * congestion window is being fully utilized and an incoming + * SACK advances the Cumulative TSN Ack Point. Only when these + * two conditions are met can the cwnd be increased otherwise + * the cwnd MUST not be increased. If these conditions are met + * then cwnd MUST be increased by at most the lesser of + * 1) the total size of the previously outstanding DATA chunk(s) + * acknowledged, and 2) the destination's path MTU. + */ + if (bytes_acked > pmtu) { + cwnd += pmtu; + } else { + cwnd += bytes_acked; + } + SCTP_DEBUG_PRINTK(__FUNCTION__ ": SLOW START: transport: %p, " + "bytes_acked: %d, cwnd: %d, ssthresh: %d, " + "flight_size: %d, pba: %d\n", + transport, bytes_acked, cwnd, + ssthresh, flight_size, pba); + } else { + /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, upon + * each SACK arrival that advances the Cumulative TSN Ack Point, + * increase partial_bytes_acked by the total number of bytes of + * all new chunks acknowledged in that SACK including chunks + * acknowledged by the new Cumulative TSN Ack and by Gap Ack + * Blocks. + * + * When partial_bytes_acked is equal to or greater than cwnd and + * before the arrival of the SACK the sender had cwnd or more + * bytes of data outstanding (i.e., before arrival of the SACK, + * flightsize was greater than or equal to cwnd), increase cwnd + * by MTU, and reset partial_bytes_acked to + * (partial_bytes_acked - cwnd). + */ + pba += bytes_acked; + if (pba >= cwnd) { + cwnd += pmtu; + pba = ((cwnd < pba) ? (pba - cwnd) : 0); + } + SCTP_DEBUG_PRINTK(__FUNCTION__ ": CONGESTION AVOIDANCE: " + "transport: %p, bytes_acked: %d, cwnd: %d, " + "ssthresh: %d, flight_size: %d, pba: %d\n", + transport, bytes_acked, cwnd, + ssthresh, flight_size, pba); + } + + transport->cwnd = cwnd; + transport->partial_bytes_acked = pba; + +} /* sctp_transport_raise_cwnd() */ + +/* This routine is used to lower the transport's cwnd when congestion is + * detected. + */ +void +sctp_transport_lower_cwnd(sctp_transport_t *transport, + sctp_lower_cwnd_t reason) +{ + switch(reason) { + case SCTP_LOWER_CWND_T3_RTX: + /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 + * When the T3-rtx timer expires on an address, SCTP should + * perform slow start by: + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = 1*MTU + * partial_bytes_acked = 0 + */ + transport->ssthresh = max(transport->cwnd/2, + 2*transport->asoc->pmtu); + transport->cwnd = transport->asoc->pmtu; + break; + case SCTP_LOWER_CWND_FAST_RTX: + /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the + * destination address(es) to which the missing DATA chunks + * were last sent, according to the formula described in + * Section 7.2.3. + * + * RFC 2960 7.2.3, sctpimpguide-05 2.9.2 Upon detection of + * packet losses from SACK (see Section 7.2.4), An endpoint + * should do the following: + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = ssthresh + * partial_bytes_acked = 0 + */ + transport->ssthresh = max(transport->cwnd/2, + 2*transport->asoc->pmtu); + transport->cwnd = transport->ssthresh; + break; + case SCTP_LOWER_CWND_ECNE: + /* RFC 2481 Section 6.1.2. + * If the sender receives an ECN-Echo ACK packet + * then the sender knows that congestion was encountered in the + * network on the path from the sender to the receiver. The + * indication of congestion should be treated just as a + * congestion loss in non-ECN Capable TCP. That is, the TCP + * source halves the congestion window "cwnd" and reduces the + * slow start threshold "ssthresh". + * A critical condition is that TCP does not react to + * congestion indications more than once every window of + * data (or more loosely more than once every round-trip time). + */ + if ((jiffies - transport->last_time_ecne_reduced) + > transport->rtt) { + transport->ssthresh = max(transport->cwnd/2, + 2*transport->asoc->pmtu); + transport->cwnd = transport->ssthresh; + transport->last_time_ecne_reduced = jiffies; + } + break; + case SCTP_LOWER_CWND_INACTIVE: + /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2 + * When the association does not transmit data on a given + * transport address within an RTO, the cwnd of the transport + * address should be adjusted to 2*MTU. + * NOTE: Although the draft recommends that this check needs + * to be done every RTO interval, we do it every hearbeat + * interval. + */ + if ((jiffies - transport->last_time_used) > transport->rto) { + transport->cwnd = 2*transport->asoc->pmtu; + } + break; + } + + transport->partial_bytes_acked = 0; + + SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p reason: %d cwnd: " + "%d ssthresh: %d\n", transport, reason, + transport->cwnd, transport->ssthresh); + +} /* sctp_transport_lower_cwnd() */ diff --git a/net/sctp/sctp_tsnmap.c b/net/sctp/sctp_tsnmap.c new file mode 100644 index 000000000000..70a38e9934c3 --- /dev/null +++ b/net/sctp/sctp_tsnmap.c @@ -0,0 +1,443 @@ +/* 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 Intel Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_tsnmap.c,v 1.8 2002/07/26 22:52:32 jgrimm Exp $ + * + * These functions manipulate sctp tsn mapping array. + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Jon Grimm + * Karl Knutson + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_tsnmap.c,v 1.8 2002/07/26 22:52:32 jgrimm Exp $"; + +#include +#include +#include +#include + +static inline void _sctp_tsnmap_update(sctp_tsnmap_t *map); +static inline void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map); +static inline void _sctp_tsnmap_find_gap_ack(uint8_t *map, uint16_t off, + uint16_t len, uint16_t base, + int *started, uint16_t *start, + int *ended, uint16_t *end); + + +/* Create a new sctp_tsnmap. + * Allocate room to store at least 'len' contiguous TSNs. + */ +sctp_tsnmap_t * +sctp_tsnmap_new(uint16_t len, uint32_t initial_tsn, int priority) +{ + sctp_tsnmap_t *retval; + + retval = kmalloc(sizeof(sctp_tsnmap_t) + + sctp_tsnmap_storage_size(len), + priority); + if (NULL == retval) { + goto fail; + } + + if (NULL == sctp_tsnmap_init(retval, len, initial_tsn)) { + goto fail_map; + } + retval->malloced = 1; + return(retval); + + fail_map: + kfree(retval); + fail: + return NULL; + +} /* sctp_tsnmap_new() */ + +/* Initialize a block of memory as a tsnmap. */ +sctp_tsnmap_t * +sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, uint32_t initial_tsn) +{ + map->tsn_map = map->raw_map; + map->overflow_map = map->tsn_map + len; + + map->len = len; + + /* Clear out a TSN ack status. */ + memset(map->tsn_map, 0x00, map->len + map->len); + + /* Keep track of TSNs represented by tsn_map. */ + map->base_tsn = initial_tsn; + map->overflow_tsn = initial_tsn + map->len; + + map->cumulative_tsn_ack_point = initial_tsn - 1; + map->max_tsn_seen = map->cumulative_tsn_ack_point; + + map->malloced = 0; + + map->pending_data = 0; + + return map; + +} /* sctp_tsnmap_init() */ + + +/* Test the tracking state of this TSN. + * Returns: + * 0 if the TSN has not yet been seen + * >0 if the TSN has been seen (duplicate) + * <0 if the TSN is invalid (too large to track) + */ +int +sctp_tsnmap_check(const sctp_tsnmap_t *map, uint32_t tsn) +{ + int32_t gap; + int dup; + /* Calculate the index into the mapping arrays. */ + gap = tsn - map->base_tsn; + + /* Verify that we can hold this TSN. */ + if (gap >= (/* base */ map->len + /* overflow */ map->len)) { + dup = -1; + goto out; + } + + /* Honk if we've already seen this TSN. + * We have three cases: + * 1. The TSN is ancient or belongs to a previous tsn_map. + * 2. The TSN is already marked in the tsn_map. + * 3. The TSN is already marked in the tsn_map_overflow. + */ + + if ( gap < 0 + || (gap < map->len && map->tsn_map[gap]) + || (gap >= map->len && map->overflow_map[gap - map->len])) { + dup = 1; + } else { + dup = 0; + } + + out: + return(dup); + +} /* sctp_tsnmap_check() */ + + +/* Is there a gap in the TSN map? */ +int +sctp_tsnmap_has_gap(const sctp_tsnmap_t *map) +{ + int has_gap; + + has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen); + return has_gap; + +} /* sctp_tsnmap_has_gap() */ + + +/* Mark this TSN as seen. */ +void +sctp_tsnmap_mark(sctp_tsnmap_t *map, uint32_t tsn) +{ + int32_t gap; + + /* Vacuously mark any TSN which precedes the map base or + * exceeds the end of the map. + */ + if (TSN_lt(tsn, map->base_tsn)) { + return; + } + + if (!TSN_lt(tsn, map->base_tsn + map->len + map->len)) { + return; + } + + /* Bump the max. */ + if (TSN_lt(map->max_tsn_seen, tsn)) { + map->max_tsn_seen = tsn; + } + + /* Assert: TSN is in range. */ + gap = tsn - map->base_tsn; + + /* Mark the TSN as received. */ + if (gap < map->len) { + map->tsn_map[gap]++; + } else { + map->overflow_map[gap - map->len]++; + } + + /* Go fixup any internal TSN mapping variables including + * cumulative_tsn_ack_point. + */ + _sctp_tsnmap_update(map); + +} /* sctp_tsnmap_mark() */ + +/* Retrieve the Cumulative TSN Ack Point. */ +uint32_t +sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map) +{ + return(map->cumulative_tsn_ack_point); + +} /* sctp_tsnmap_get_ctsn() */ + +/* Retrieve the highest TSN we've seen. */ +uint32_t +sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map) +{ + return(map->max_tsn_seen); + +} /* sctp_tsnmap_get_max_tsn_seen() */ + + +/* Dispose of a tsnmap. */ +void +sctp_tsnmap_free(sctp_tsnmap_t *map) +{ + if (map->malloced) { + kfree(map); + } +} /* sctp_tsnmap_free() */ + + +/* Initialize a Gap Ack Block iterator from memory being provided. */ +void +sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter) +{ + /* Only start looking one past the Cumulative TSN Ack Point. */ + iter->start = map->cumulative_tsn_ack_point + 1; + +} /* sctp_tsnmap_iter_init() */ + + + + + +/* Get the next Gap Ack Blocks. Returns 0 if there was not + * another block to get. + */ +int +sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + uint16_t *start, uint16_t *end) +{ + int started, ended; + uint16_t _start, _end, offset; + + + /* We haven't found a gap yet. */ + started = ended = 0; + + + /* Search the first mapping array. */ + if (iter->start - map->base_tsn < map->len) { + offset = iter->start - map->base_tsn; + _sctp_tsnmap_find_gap_ack(map->tsn_map, + offset, + map->len, 0, + &started, &_start, + &ended, &_end); + } + + + /* Do we need to check the overflow map? */ + + if (!ended) { + + /* Fix up where we'd like to start searching in the + * overflow map. + */ + if (iter->start - map->base_tsn < map->len) { + offset = 0; + } else { + offset = iter->start - map->base_tsn - map->len; + } + + + /* Search the overflow map. */ + _sctp_tsnmap_find_gap_ack(map->overflow_map, + offset, + map->len, + map->len, + &started, &_start, + &ended, &_end); + } + + /* The Gap Ack Block happens to end at the end of the + * overflow map. + */ + if (started & !ended) { + ended++; + _end = map->len + map->len - 1; + } + + /* If we found a Gap Ack Block, return the start and end and + * bump the iterator forward. + */ + if (ended) { + /* Fix up the start and end based on the + * Cumulative TSN Ack offset into the map. + */ + int gap = map->cumulative_tsn_ack_point + - map->base_tsn; + + *start = _start - gap; + *end = _end - gap; + + /* Move the iterator forward. */ + iter->start = map->cumulative_tsn_ack_point + *end + 1; + } + + return(ended); + +} /* sctp_tsnmap_next_gap_ack() */ + +/******************************************************************** + * 2nd Level Abstractions + ********************************************************************/ + +/* This private helper function updates the tsnmap buffers and + * the Cumulative TSN Ack Point. + */ +static inline void +_sctp_tsnmap_update(sctp_tsnmap_t *map) +{ + uint32_t ctsn; + + ctsn = map->cumulative_tsn_ack_point; + do { + ctsn++; + if ( ctsn == map->overflow_tsn ) { + + /* Now tsn_map must have been all '1's, + * so we swap the map and check the overflow table + */ + + uint8_t *tmp = map->tsn_map; + memset(tmp, 0, map->len); + map->tsn_map = map->overflow_map; + map->overflow_map = tmp; + + /* Update the tsn_map boundaries. */ + map->base_tsn += map->len; + map->overflow_tsn += map->len; + } + } while ( map->tsn_map[ctsn - map->base_tsn] ); + + map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ + + _sctp_tsnmap_update_pending_data(map); + +} /* _sctp_tsnmap_update() */ + +static inline void +_sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) +{ + uint32_t cum_tsn = map->cumulative_tsn_ack_point; + uint32_t max_tsn = map->max_tsn_seen; + uint32_t base_tsn = map->base_tsn; + uint16_t pending_data; + int32_t gap, start, end, i; + + pending_data = max_tsn - cum_tsn; + gap = max_tsn - base_tsn; + + if (gap <= 0 || gap >= (map->len + map->len)) { + goto out; + } + + start = ((cum_tsn >= base_tsn) ? (cum_tsn - base_tsn + 1) : 0); + end = ((gap > map->len ) ? map->len : gap + 1); + + for (i = start; i < end; i++) { + if (map->tsn_map[i]) { pending_data--; } + } + + if (gap >= map->len) { + start = 0; + end = gap - map->len + 1; + for (i = start; i < end; i++) { + if (map->overflow_map[i]) { pending_data--; } + } + } +out: + map->pending_data = pending_data; +} + +/* This is a private helper for finding Gap Ack Blocks. It searches a + * single array for the start and end of a Gap Ack Block. + * + * The flags "started" and "ended" tell is if we found the beginning + * or (respectively) the end of a Gap Ack Block. + * + */ + +static inline void +_sctp_tsnmap_find_gap_ack(uint8_t *map, uint16_t off, + uint16_t len, uint16_t base, + int *started, uint16_t *start, + int *ended, uint16_t *end) +{ + int i = off; + + /* Let's look through the entire array, but break out + * early if we have found the end of the Gap Ack Block. + */ + + /* Look for the start. */ + if (!(*started)) { + for (; i < len; i++) { + if (map[i]) { + (*started)++; + *start = base + i; + break; + } + } + } + /* Look for the end. */ + if (*started) { + /* We have found the start, let's find the + * end. If we find the end, break out. + */ + for (; i < len; i++) { + + if (!map[i]){ + (*ended)++; + *end = base + i - 1; + break; + } + } + } + +} /* _sctp_tsnmap_next_gap_ack() */ diff --git a/net/sctp/sctp_ulpevent.c b/net/sctp/sctp_ulpevent.c new file mode 100644 index 000000000000..71ae3e37fe02 --- /dev/null +++ b/net/sctp/sctp_ulpevent.c @@ -0,0 +1,927 @@ +/* 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 Intel Corp. + * Copyright (c) 2001 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpevent.c,v 1.15 2002/07/12 14:50:26 jgrimm Exp $ + * + * These functions manipulate an sctp event. The sctp_ulpevent_t is used + * to carry notifications and data to the ULP (sockets). + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpevent.c,v 1.15 2002/07/12 14:50:26 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include + + +static void +sctp_rcvmsg_rfree(struct sk_buff *skb); +static inline void +sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc); + + +/* Create a new sctp_ulpevent. + */ +sctp_ulpevent_t * +sctp_ulpevent_new(int size, int msg_flags, int priority) +{ + sctp_ulpevent_t *event; + struct sk_buff *skb; + + skb = alloc_skb(size, priority); + + if (NULL == skb) { + goto fail; + } + + event = (sctp_ulpevent_t *)skb->cb; + event = sctp_ulpevent_init(event, skb, msg_flags); + + if (NULL == event) { + goto fail_init; + } + + event->malloced = 1; + return(event); + + fail_init: + kfree_skb(event->parent); + fail: + return NULL; + +} /* sctp_ulpevent_new() */ + +/* Initialize an ULP event from an given skb. */ +sctp_ulpevent_t * +sctp_ulpevent_init(sctp_ulpevent_t *event, + struct sk_buff *parent, + int msg_flags) +{ + memset(event, sizeof(sctp_ulpevent_t), 0x00); + + event->msg_flags = msg_flags; + event->parent = parent; + event->malloced = 0; + return(event); + +} /* sctp_ulpevent_init() */ + + + +/* Dispose of an event. */ +void +sctp_ulpevent_free(sctp_ulpevent_t *event) +{ + if (event->malloced) { + kfree_skb(event->parent); + } + +} /* sctp_ulpevent_free() */ + +/* Is this a MSG_NOTIFICATION? */ +int +sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) +{ + return(event->msg_flags & MSG_NOTIFICATION); + +} /* sctp_ulpevent_is_notification() */ + + +/* Create and initialize an SCTP_ASSOC_CHANGE event. + * + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notification. + * + * Note: There is no field checking here. If a field is unused it will be + * zero'd out. + */ +sctp_ulpevent_t * +sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, + uint16_t flags, + uint16_t state, + uint16_t error, + uint16_t outbound, + uint16_t inbound, + int priority) +{ + + sctp_ulpevent_t *event; + struct sctp_assoc_change *sac; + + event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + MSG_NOTIFICATION, + priority); + + if (NULL == event) { + goto fail; + } + + sac = (struct sctp_assoc_change *) + skb_put(event->parent, + sizeof(struct sctp_assoc_change)); + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_type: + * It should be SCTP_ASSOC_CHANGE. + */ + + sac->sac_type = SCTP_ASSOC_CHANGE; + + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_state: 32 bits (signed integer) + * This field holds one of a number of values that communicate the + * event that happened to the association. + */ + + sac->sac_state = state; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_flags: 16 bits (unsigned integer) + * Currently unused. + * + */ + sac->sac_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_length: sizeof (uint32_t) + * This field is the total length of the notification data, including + * the notification header. + */ + + sac->sac_length = sizeof(struct sctp_assoc_change); + + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_error: 32 bits (signed integer) + * + * If the state was reached due to a error condition (e.g. + * COMMUNICATION_LOST) any relevant error information is available in + * this field. This corresponds to the protocol error codes defined in + * [SCTP]. + */ + + sac->sac_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_outbound_streams: 16 bits (unsigned integer) + * sac_inbound_streams: 16 bits (unsigned integer) + * + * The maximum number of streams allowed in each direction are + * available in sac_outbound_streams and sac_inbound streams. + */ + sac->sac_outbound_streams = outbound; + sac->sac_inbound_streams = inbound; + + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_assoc_id: sizeof (sctp_assoc_t) + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + sac->sac_assoc_id = sctp_assoc2id(asoc); + + return(event); +fail: + return(NULL); + +} /* sctp_ulpevent_make_assoc_change() */ + + +/* Create and initialize an SCTP_PEER_ADDR_CHANGE event. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. + * + */ +sctp_ulpevent_t * +sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_paddr_change *spc; + + event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), + MSG_NOTIFICATION, + priority); + + if (NULL == event) { + goto fail; + } + + spc = (struct sctp_paddr_change *) + skb_put(event->parent, + sizeof(struct sctp_paddr_change)); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_type: + * + * It should be SCTP_PEER_ADDR_CHANGE. + */ + spc->spc_type = SCTP_PEER_ADDR_CHANGE; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_length: sizeof (uint32_t) + * + * This field is the total length of the notification data, including + * the notification header. + */ + spc->spc_length = sizeof(struct sctp_paddr_change); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_flags: 16 bits (unsigned integer) + * Currently unused. + */ + spc->spc_flags = 0; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. + */ + spc->spc_state = state; + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_error: 32 bits (signed integer) + * + * If the state was reached due to any error condition (e.g. + * ADDRESS_UNREACHABLE) any relevant error information is available in + * this field. + */ + spc->spc_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * sac_assoc_id: sizeof (sctp_assoc_t) + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + spc->spc_assoc_id = sctp_assoc2id(asoc); + + /* Sockets API Extensions for SCTP + * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * spc_aaddr: sizeof (struct sockaddr_storage) + * + * The affected address field, holds the remote peer's address that is + * encountering the change of state. + */ + memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); + + + return(event); +fail: + return(NULL); + +} /* sctp_ulpevent_make_peer_addr_change() */ + +/* Create and initialize an SCTP_REMOTE_ERROR notification. + * + * Note: This assumes that the chunk->skb->data already points to the + * operation error payload. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. + * + */ +sctp_ulpevent_t * +sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + uint16_t flags, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_remote_error *sre; + struct sk_buff *skb; + sctp_errhdr_t *ch; + uint16_t cause; + int elen; + + ch = (sctp_errhdr_t *)(chunk->skb->data); + cause = ch->cause; + elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); + + /* Pull off the ERROR header. */ + skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); + + /* Copy the skb to a new skb with room for us to prepend + * notification with. */ + skb = skb_copy_expand(chunk->skb, + sizeof(struct sctp_remote_error), /* headroom */ + 0, /* tailroom */ + priority); + + /* Pull off the rest of the cause TLV from the chunk. */ + skb_pull(chunk->skb, elen); + + if (NULL == skb) { + goto fail; + } + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *)skb->cb; + event = sctp_ulpevent_init(event, + skb, + MSG_NOTIFICATION); + if (NULL == event) { + goto fail; + } + + event->malloced = 1; + + sre = (struct sctp_remote_error *) + skb_push(skb, sizeof(struct sctp_remote_error)); + + /* Trim the buffer to the right length. */ + skb_trim(skb, sizeof(struct sctp_remote_error) + elen); + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_type: + * It should be SCTP_REMOTE_ERROR. + */ + sre->sre_type = SCTP_REMOTE_ERROR; + + /* + * Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_flags: 16 bits (unsigned integer) + * Currently unused. + */ + sre->sre_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_length: sizeof (uint32_t) + * + * This field is the total length of the notification data, + * including the notification header. + */ + sre->sre_length = skb->len; + + /* + * Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_error: 16 bits (unsigned integer) + * This value represents one of the Operational Error causes defined in + * the SCTP specification, in network byte order. + */ + sre->sre_error = cause; + + + /* + * Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_assoc_id: sizeof (sctp_assoc_t) + * + * + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + + sre->sre_assoc_id = sctp_assoc2id(asoc); + + + return(event); +fail: + return(NULL); + +} /* sctp_ulpevent_make_remote_error () */ + +/* Create and initialize a SCTP_SEND_FAILED notification. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.4 SCTP_SEND_FAILED + */ +sctp_ulpevent_t * +sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + uint16_t flags, + uint32_t error, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_send_failed *ssf; + struct sk_buff *skb; + + /* Make skb with more room so we can prepend notification. */ + skb = skb_copy_expand(chunk->skb, + sizeof(struct sctp_send_failed), /* headroom */ + 0, /* tailroom */ + priority); + + if (NULL == skb) { + goto fail; + } + + /* Pull off the common chunk header and DATA header. */ + skb_pull(skb, sizeof(sctp_data_chunk_t)); + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *)skb->cb; + event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); + if (NULL == event) { goto fail; } + + /* Mark as malloced, even though the constructor was not + * called. + */ + event->malloced = 1; + + ssf = (struct sctp_send_failed *) + skb_push(skb, sizeof(struct sctp_send_failed)); + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_type: + * It should be SCTP_SEND_FAILED. + */ + ssf->ssf_type = SCTP_SEND_FAILED; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_flags: 16 bits (unsigned integer) + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ + ssf->ssf_flags = flags; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_length: sizeof (uint32_t) + * This field is the total length of the notification data, including + * the notification header. + */ + ssf->ssf_length = skb->len; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_error: 16 bits (unsigned integer) + * This value represents the reason why the send failed, and if set, + * will be a SCTP protocol error code as defined in [SCTP] section + * 3.3.10. + */ + ssf->ssf_error = error; + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_info: sizeof (struct sctp_sndrcvinfo) + * The original send information associated with the undelivered + * message. + */ + memcpy(&ssf->ssf_info, + &chunk->sinfo, + sizeof(struct sctp_sndrcvinfo)); + + /* Socket Extensions for SCTP + * 5.3.1.4 SCTP_SEND_FAILED + * + * ssf_assoc_id: sizeof (sctp_assoc_t) + * The association id field, sf_assoc_id, holds the identifier for the + * association. All notifications for a given association have the + * same association identifier. For TCP style socket, this field is + * ignored. + */ + ssf->ssf_assoc_id = sctp_assoc2id(asoc); + + + return(event); +fail: + return(NULL); + +} /* sctp_ulpevent_make_send_failed () */ + +/* Create and initialize a SCTP_SHUTDOWN_EVENT notification. + * + * Socket Extensions for SCTP - draft-01 + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + */ +sctp_ulpevent_t * +sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, + uint16_t flags, + int priority) +{ + sctp_ulpevent_t *event; + struct sctp_shutdown_event *sse; + + event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), + MSG_NOTIFICATION, + priority); + + if (NULL == event) { + goto fail; + } + + sse = (struct sctp_shutdown_event *) + skb_put(event->parent, + sizeof(struct sctp_shutdown_event)); + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_type + * It should be SCTP_SHUTDOWN_EVENT + */ + sse->sse_type = SCTP_SHUTDOWN_EVENT; + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_flags: 16 bits (unsigned integer) + * Currently unused. + */ + sse->sse_flags = 0; + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_length: sizeof (uint32_t) + * This field is the total length of the notification data, including + * the notification header. + */ + sse->sse_length = sizeof(struct sctp_shutdown_event); + + /* Socket Extensions for SCTP + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * sse_assoc_id: sizeof (sctp_assoc_t) + * The association id field, holds the identifier for the association. + * All notifications for a given association have the same association + * identifier. For TCP style socket, this field is ignored. + */ + sse->sse_assoc_id = sctp_assoc2id(asoc); + + return(event); +fail: + return(NULL); + +} /* sctp_ulpevent_make_shutdown_event () */ + + +/* A message has been received. Package this message as a notification + * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo + * even if filtered out later. + * + * Socket Extensions for SCTP - draft-01 + * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + */ +sctp_ulpevent_t * +sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, + sctp_chunk_t *chunk, + int priority) +{ + + sctp_ulpevent_t *event; + struct sctp_sndrcvinfo *info; + struct sk_buff *skb; + size_t padding, len; + + /* Clone the original skb, sharing the data. */ + skb = skb_clone(chunk->skb, priority); + if (NULL == skb) { + goto fail; + } + + + /* First calculate the padding, so we don't inadvertently + * pass up the wrong length to the user. + * + * RFC 2960 - Section 3.2 Chunk Field Descriptions + * + * The total length of a chunk(including Type, Length and Value fields) + * MUST be a multiple of 4 bytes. If the length of the chunk is not a + * multiple of 4 bytes, the sender MUST pad the chunk with all zero + * bytes and this padding is not included in the chunk length field. + * The sender should never pad with more than 3 bytes. The receiver + * MUST ignore the padding bytes. + * + */ + len = ntohs(chunk->chunk_hdr->length); + padding = WORD_ROUND(len) - len; + + /* Fixup cloned skb with just this chunks data. */ + skb_trim(skb, chunk->chunk_end - padding - skb->data); + + /* Set up a destructor to do rwnd accounting. */ + sctp_ulpevent_set_owner_r(skb, asoc); + + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *)skb->cb; + /* Initialize event with flags 0. */ + event = sctp_ulpevent_init(event, skb, 0); + + if (NULL == event) { + goto fail_init; + } + + event->malloced = 1; + + info = (struct sctp_sndrcvinfo *)&event->sndrcvinfo; + + /* + * Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_stream: 16 bits (unsigned integer) + * + * For recvmsg() the SCTP stack places the message's stream number in + * this value. + */ + + info->sinfo_stream = ntohs(chunk->subh.data_hdr->stream); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_ssn: 16 bits (unsigned integer) + * + * For recvmsg() this value contains the stream sequence number that + * the remote endpoint placed in the DATA chunk. For fragmented + * messages this is the same number for all deliveries of the message + * (if more than one recvmsg() is needed to read the message). + */ + + info->sinfo_ssn = ntohs(chunk->subh.data_hdr->ssn); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_ppid:32 bits (unsigned integer) + * + * In recvmsg() this value is + * the same information that was passed by the upper layer in the peer + * application. Please note that byte order issues are NOT accounted + * for and this information is passed opaquely by the SCTP stack from + * one end to the other. + */ + info->sinfo_ppid = ntohl(chunk->subh.data_hdr->ppid); + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + * + * recvmsg() flags: + * + * MSG_UNORDERED - This flag is present when the message was sent + * non-ordered. + */ + + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { + info->sinfo_flags |= MSG_UNORDERED; + } + + /* FIXME: For reassembly, we need to have the fragmentation bits. + * This really does not belong in the event structure, but + * its difficult to fix everything at the same time. Eventually, + * we should create and skb based chunk structure. This structure + * storage can be converted to an event. --jgrimm + */ + event->chunk_flags = chunk->chunk_hdr->flags; + + /* With -04 draft, tsn moves into sndrcvinfo. */ + info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn); + + /* Context is not used on receive. */ + info->sinfo_context = 0; + + /* Sockets API Extensions for SCTP + * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * sinfo_assoc_id: sizeof (sctp_assoc_t) + * + * The association handle field, sinfo_assoc_id, holds the identifier + * for the association announced in the COMMUNICATION_UP notification. + * All notifications for a given association have the same identifier. + * Ignored for TCP-style sockets. + */ + + info->sinfo_assoc_id = sctp_assoc2id(asoc); + + return(event); + +fail_init: + kfree_skb(skb); +fail: + return(NULL); + +} /* sctp_ulpevent_make_rcvmsg() */ + +/* Return the notification type, assuming this is a notification + * event. + */ +uint16_t +sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) +{ + union sctp_notification *notification; + + notification = (union sctp_notification *)event->parent->data; + + return(notification->h.sn_type); + +} /* sctp_ulpevent_get_notification_type() */ + +/* Copy out the sndrcvinfo into a msghdr. */ +void +sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr) +{ + + if (!sctp_ulpevent_is_notification(event)) { + put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, + sizeof(struct sctp_sndrcvinfo), + (void *)&event->sndrcvinfo); + } + +} /* sctp_ulpevent_read_sndrcvinfo() */ + +/* Do accounting for bytes just read by user. */ +static void +sctp_rcvmsg_rfree(struct sk_buff *skb) +{ + sctp_association_t *asoc; + sctp_ulpevent_t *event; + + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * Use the local private area of the skb to track the owning + * association. + */ + + event = (sctp_ulpevent_t *)skb->cb; + asoc = event->asoc; + + if (asoc->rwnd_over) { + 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)\n", + skb->len, asoc->rwnd, asoc->rwnd_over); + + sctp_association_put(asoc); + +} /* sctp_rcvmsg_rfree() */ + + +/* Charge receive window for bytes recieved. */ +static inline void +sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) +{ + sctp_ulpevent_t *event; + + /* The current stack structures assume that the rcv buffer is + * per socket. For UDP-style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * We use the local private area of the skb to track the owning + * association. + */ + sctp_association_hold(asoc); + skb->sk = asoc->base.sk; + event = (sctp_ulpevent_t *)skb->cb; + event->asoc = asoc; + + skb->destructor = sctp_rcvmsg_rfree; + + SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); + 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); + +} /* sctp_ulpevent_set_owner_r() */ + + + + + + + + + + + + + + + + + + diff --git a/net/sctp/sctp_ulpqueue.c b/net/sctp/sctp_ulpqueue.c new file mode 100644 index 000000000000..c6a6149e2c80 --- /dev/null +++ b/net/sctp/sctp_ulpqueue.c @@ -0,0 +1,542 @@ +/* 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 Nokia, Inc. + * Copyright (c) 2001 La Monte H.P. Yarroll + * + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpqueue.c,v 1.13 2002/07/12 14:50:26 jgrimm Exp $ + * + * This abstraction carries sctp events to the ULP (sockets). + * + * 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 + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * Sridhar Samudrala + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpqueue.c,v 1.13 2002/07/12 14:50:26 jgrimm Exp $"; + +#include +#include +#include +#include +#include +#include +#include + +/* Forward declarations for internal helpers. */ +static inline sctp_ulpevent_t * +sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event); +static inline sctp_ulpevent_t * +sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event); + + +/* 1st Level Abstractions */ + +/* Create a new ULP queue. + */ +sctp_ulpqueue_t * +sctp_ulpqueue_new(sctp_association_t *asoc, uint16_t inbound, int priority) +{ + sctp_ulpqueue_t *ulpq; + size_t size; + + /* Today, there is only a fixed size of storage needed for + * stream support, but make the interfaces acceptable for + * the future. + */ + size = sizeof(sctp_ulpqueue_t)+sctp_ulpqueue_storage_size(inbound); + ulpq = kmalloc(size, priority); + + if (NULL == ulpq) { + goto fail; + } + + if (NULL == sctp_ulpqueue_init(ulpq, asoc, inbound)) { + goto fail_init; + } + + ulpq->malloced = 1; + return(ulpq); + +fail_init: + kfree(ulpq); +fail: + return NULL; + +} /* sctp_ulpqueue_new() */ + +/* Initialize a ULP queue from a block of memory. */ +sctp_ulpqueue_t * +sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, sctp_association_t *asoc, + uint16_t inbound) +{ + memset(ulpq, + sizeof(sctp_ulpqueue_t) + sctp_ulpqueue_storage_size(inbound), + 0x00); + + ulpq->asoc = asoc; + spin_lock_init(&ulpq->lock); + skb_queue_head_init(&ulpq->reasm); + skb_queue_head_init(&ulpq->lobby); + ulpq->malloced = 0; + + return(ulpq); + +} /* sctp_ulpqueue_init() */ + +/* Flush the reassembly and ordering queues. */ +void +sctp_ulpqueue_flush(sctp_ulpqueue_t *ulpq) +{ + struct sk_buff *skb; + sctp_ulpevent_t *event; + + while((skb = skb_dequeue(&ulpq->lobby))) { + event = (sctp_ulpevent_t *)skb->cb; + sctp_ulpevent_free(event); + } + + while((skb = skb_dequeue(&ulpq->reasm))) { + event = (sctp_ulpevent_t *)skb->cb; + sctp_ulpevent_free(event); + } + +} /* sctp_ulpqueue_flush() */ + + +/* Dispose of a ulpqueue. */ +void +sctp_ulpqueue_free(sctp_ulpqueue_t *ulpq) +{ + + sctp_ulpqueue_flush(ulpq); + if (ulpq->malloced) { + kfree(ulpq); + } + +} /* sctp_ulpqueue_free() */ + + +/* Process an incoming DATA chunk. */ +int +sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk, + int priority) +{ + struct sk_buff_head temp; + sctp_data_chunk_t *hdr; + sctp_ulpevent_t *event; + + hdr = (sctp_data_chunk_t *)chunk->chunk_hdr; + + /* FIXME: Instead of event being the skb clone, we really should + * have a new skb based chunk structure that we can convert to + * an event. Temporarily, I'm carrying a few chunk fields in + * the event to allow reassembly. Its too painful to change + * everything at once. --jgrimm + */ + + event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); + + if (!event) { + return -ENOMEM; + } + + /* Do reassembly if needed. */ + event = sctp_ulpqueue_reasm(ulpq, event); + + /* Do ordering if needed. */ + if (NULL != event) { + /* Create a temporary list to collect chunks on. */ + skb_queue_head_init(&temp); + skb_queue_tail(&temp, event->parent); + + event = sctp_ulpqueue_order(ulpq, event); + } + + /* Send event to the ULP. */ + if (NULL != event) { + sctp_ulpqueue_tail_event(ulpq, event); + } + + return(0); + +} /* sctp_ulpqueue_tail_data() */ + + +/* Add a new event for propogation to the ULP. */ +int +sctp_ulpqueue_tail_event(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + struct sock *sk; + sk = ulpq->asoc->base.sk; + + /* If the socket is just going to throw this away, do not + * even try to deliver it. + */ + if (sk->dead || (sk->shutdown & RCV_SHUTDOWN)) { + goto out_free; + } + + /* Check if the user wishes to receive this event. */ + if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) { + goto out_free; + } + + /* If we are harvesting multiple skbs they will be + * collected on a list. + */ + if (event->parent->list) { + sctp_skb_list_tail(event->parent->list, &sk->receive_queue); + } else { + skb_queue_tail(&sk->receive_queue, event->parent); + } + + wake_up_interruptible(sk->sleep); + + return 1; + +out_free: + if (event->parent->list) { + skb_queue_purge(event->parent->list); + } else { + kfree_skb(event->parent); + } + + return 0; + +} /* sctp_ulpqueue_tail_event() */ + + + +/* 2nd Level Abstractions */ + +/* Helper function to store chunks that need to be reassembled. */ +static inline void +sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + uint32_t tsn, ctsn; + int flags __attribute ((unused)); + + tsn = event->sndrcvinfo.sinfo_tsn; + + sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); + + /* Find the right place in this list. We store them by TSN. */ + sctp_skb_for_each(pos, &ulpq->reasm, tmp) { + cevent = (sctp_ulpevent_t *)pos->cb; + ctsn = cevent->sndrcvinfo.sinfo_tsn; + + if (TSN_lt(tsn, ctsn)) { break; } + } + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->reasm)) { + __skb_insert(event->parent, pos->prev, pos, &ulpq->reasm); + } + else { + __skb_queue_tail(&ulpq->reasm, event->parent); + } + + sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); + +} /* sctp_ulpqueue_store_reasm() */ + +/* Helper function to return an event corresponding to the reassembled + * datagram. + */ +static inline sctp_ulpevent_t * +sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) +{ + struct sk_buff *pos; + sctp_ulpevent_t *event; + struct sk_buff *pnext; + + pos = f_frag->next; + + /* Set the first fragment's frag_list to point to the 2nd fragment. */ + skb_shinfo(f_frag)->frag_list = pos; + + /* Remove the first fragment from the reassembly queue. */ + __skb_unlink(f_frag, f_frag->list); + + do { + pnext = pos->next; + + /* Remove the fragment from the reassembly queue. */ + __skb_unlink(pos, pos->list); + + /* Break if we have reached the last fragment. */ + if (pos == l_frag) { break; } + + pos->next = pnext; + pos = pnext; + } while (1); + + event = (sctp_ulpevent_t *)f_frag->cb; + + return (event); + +} /* sctp_make_reassembled_event() */ + +/* Helper function to check if an incoming chunk has filled up the last + * missing fragment in a SCTP datagram and return the corresponding event. + */ +static inline sctp_ulpevent_t * +sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_t *ulpq) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + struct sk_buff *first_frag = NULL; + uint32_t ctsn, next_tsn; + int flags __attribute ((unused)); + sctp_ulpevent_t *retval = NULL; + + /* Initialized to 0 just to avoid compiler warning message. Will + * never be used with this value. It is referenced only after it + * is set when we find the first fragment of a message. + */ + next_tsn = 0; + + sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); + /* The chunks are held in the reasm queue sorted by TSN. + * Walk through the queue sequentially and look for a sequence of + * fragmented chunks that complete a datagram. + * 'first_frag' and next_tsn are reset when we find a chunk which + * is the first fragment of a datagram. Once these 2 fields are set + * we expect to find the remaining middle fragments and the last + * fragment in order. If not, first_frag is reset to NULL and we + * start the next pass when we find another first fragment. + */ + sctp_skb_for_each(pos, &ulpq->reasm, tmp) { + cevent = (sctp_ulpevent_t *)pos->cb; + ctsn = cevent->sndrcvinfo.sinfo_tsn; + + switch (cevent->chunk_flags & SCTP_DATA_FRAG_MASK) { + case SCTP_DATA_FIRST_FRAG: + first_frag = pos; + next_tsn = ctsn+1; + break; + case SCTP_DATA_MIDDLE_FRAG: + if ((first_frag) && (ctsn == next_tsn)) { + next_tsn++; + } else { + first_frag = NULL; + } + break; + case SCTP_DATA_LAST_FRAG: + if ((first_frag) && (ctsn == next_tsn)) { + retval = sctp_make_reassembled_event( + first_frag, pos); + } else { + first_frag = NULL; + } + break; + } + + /* We have the reassembled event. There is no need to look + * further. + */ + if (retval) { break; } + } + sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); + + return (retval); + +} /* sctp_ulpqueue_retrieve_reassembled() */ + +/* Helper function to reassemble chunks. Hold chunks on the reasm queue that + * need reassembling. + */ +static inline sctp_ulpevent_t * +sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + sctp_ulpevent_t *retval = NULL; + + /* FIXME: We should be using some new chunk structure here + * instead of carrying chunk fields in the event structure. + * This is temporary as it is too painful to change everything + * at once. + */ + + /* Check if this is part of a fragmented message. */ + if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) { + return(event); + } + + sctp_ulpqueue_store_reasm(ulpq, event); + retval = sctp_ulpqueue_retrieve_reassembled(ulpq); + + return(retval); + +} /* sctp_ulpqueue_reasm() */ + + +/* Helper function to gather skbs that have possibly become + * ordered by an an incoming chunk. + */ +static inline void +sctp_ulpqueue_retrieve_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + uint16_t sid, csid; + uint16_t ssn, cssn; + int flags __attribute ((unused)); + + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + /* We are holding the chunks by stream, by SSN. */ + sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); + sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + cevent = (sctp_ulpevent_t *)pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + + /* Have we gone too far? */ + if (csid > sid) { break; } + + /* Have we not gone far enough? */ + if (csid < sid) { continue; } + + if (cssn != ulpq->ssn[sid]) { break; } + + ulpq->ssn[sid]++; + __skb_unlink(pos, pos->list); + + /* Attach all gathered skbs to the event. */ + __skb_queue_tail(event->parent->list, pos); + + } + sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); + +} /* sctp_ulpqueue_retrieve_ordered() */ + + +/* Helper function to store chunks needing ordering. */ +static inline void +sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) +{ + struct sk_buff *pos, *tmp; + sctp_ulpevent_t *cevent; + uint16_t sid, csid; + uint16_t ssn, cssn; + int flags __attribute ((unused)); + + + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); + + /* Find the right place in this list. We store them by + * stream ID and then by SSN. + */ + sctp_skb_for_each(pos, &ulpq->lobby, tmp) { + cevent = (sctp_ulpevent_t *)pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + + if (csid > sid) { break; } + if (csid == sid && SSN_lt(ssn, cssn)) { break;} + + } + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->lobby)) { + __skb_insert(event->parent, pos->prev, pos, &ulpq->lobby); + } + else { + __skb_queue_tail(&ulpq->lobby, event->parent); + } + + + sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); + +} /* sctp_ulpqueue_store_ordered() */ + +static inline sctp_ulpevent_t * +sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +{ + uint16_t sid; + uint16_t ssn; + + + /* FIXME: We should be using some new chunk structure here + * instead of carrying chunk fields in the event structure. + * This is temporary as it is too painful to change everything + * at once. + */ + + + /* Check if this message needs ordering. */ + if (SCTP_DATA_UNORDERED & event->chunk_flags) { + return(event); + } + + /* Note: The stream ID must be verified before this routine. */ + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + + /* Is this the expected SSN for this stream ID? */ + + if (ssn != ulpq->ssn[sid]) { + + /* We've received something out of order, so find where it + * needs to be placed. We order by stream and then by SSN. + */ + + sctp_ulpqueue_store_ordered(ulpq, event); + + return(NULL); + } + + /* Mark that the next chunk has been found. */ + ulpq->ssn[sid]++; + + /* Go find any other chunks that were waiting for + * ordering. + */ + + sctp_ulpqueue_retrieve_ordered(ulpq, event); + + return(event); + +} /* sctp_ulpqueue_order() */ + + + + diff --git a/net/socket.c b/net/socket.c index 53dcf8bf9c83..c9be97e26a5e 100644 --- a/net/socket.c +++ b/net/socket.c @@ -355,7 +355,7 @@ static struct dentry_operations sockfs_dentry_operations = { * but we take care of internal coherence yet. */ -static int sock_map_fd(struct socket *sock) +int sock_map_fd(struct socket *sock) { int fd; struct qstr this; -- cgit v1.2.3 From 5d326e99ec250180892cef40a57938f327f21aab Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Wed, 21 Aug 2002 04:35:39 -0500 Subject: Support MSG_ABORT (the abort primitive) to do a non-graceful shutdown of an association. --- include/net/sctp/sctp.h | 3 +- include/net/sctp/sctp_sm.h | 5 +- net/sctp/sctp_primitive.c | 24 ++++++-- net/sctp/sctp_sm_statefuns.c | 139 ++++++++++++++++++++++++++++++++++++++++-- net/sctp/sctp_sm_statetable.c | 25 +++++--- net/sctp/sctp_socket.c | 47 +++++++------- net/sctp/sctp_ulpevent.c | 36 +++++------ net/sctp/sctp_ulpqueue.c | 20 +++--- 8 files changed, 231 insertions(+), 68 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 5875cc068e1b..29bd3ccf8e0d 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -6,7 +6,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Id: sctp.h,v 1.39 2002/08/16 19:30:49 jgrimm Exp $ + * $Id: sctp.h,v 1.40 2002/08/21 18:34:03 jgrimm Exp $ * * The base lksctp header. * @@ -133,6 +133,7 @@ extern unsigned int sctp_poll(struct file *file, struct socket *sock, */ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); +extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); extern int sctp_primitive_SEND(sctp_association_t *, void *arg); diff --git a/include/net/sctp/sctp_sm.h b/include/net/sctp/sctp_sm.h index f3eb7657701d..037147e03c2a 100644 --- a/include/net/sctp/sctp_sm.h +++ b/include/net/sctp/sctp_sm.h @@ -10,7 +10,7 @@ * based on June 29, 2001, * for the SCTP kernel reference Implementation. * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_sm.h,v 1.33 2002/08/16 19:30:49 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/include/net/sctp/sctp_sm.h,v 1.34 2002/08/21 18:34:04 jgrimm Exp $ * * These are definitions needed by the state machine. * @@ -144,6 +144,9 @@ sctp_state_fn_t sctp_sf_do_prm_send; sctp_state_fn_t sctp_sf_do_9_2_prm_shutdown; sctp_state_fn_t sctp_sf_cookie_wait_prm_shutdown; sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; +sctp_state_fn_t sctp_sf_do_9_1_prm_abort; +sctp_state_fn_t sctp_sf_cookie_wait_prm_abort; +sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort; sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_ignore_primitive; diff --git a/net/sctp/sctp_primitive.c b/net/sctp/sctp_primitive.c index bed944950a3e..f5d3168ad54c 100644 --- a/net/sctp/sctp_primitive.c +++ b/net/sctp/sctp_primitive.c @@ -4,7 +4,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_primitive.c,v 1.5 2002/04/24 16:33:39 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_primitive.c,v 1.6 2002/08/21 18:34:04 jgrimm Exp $ * * These functions implement the SCTP primitive functions from Section 10. * @@ -44,7 +44,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_primitive.c,v 1.5 2002/04/24 16:33:39 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_primitive.c,v 1.6 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -73,7 +73,7 @@ sctp_primitive_ ## name(sctp_association_t *asoc, \ ep = asoc ? asoc->ep : NULL; \ \ error = sctp_do_sm(event_type, subtype, state, ep, asoc, arg, GFP_KERNEL); \ - return(error); \ + return error; \ } /* sctp_primitive_ ## name() */ /* 10.1 ULP-to-SCTP @@ -112,6 +112,21 @@ DECLARE_PRIMITIVE(ASSOCIATE) DECLARE_PRIMITIVE(SHUTDOWN); +/* 10.1 ULP-to-SCTP + * C) Abort + * + * Format: Abort(association id [, cause code]) + * -> result + * + * Ungracefully closes an association. Any locally queued user data + * will be discarded and an ABORT chunk is sent to the peer. A success + * code will be returned on successful abortion of the association. If + * attempting to abort the association results in a failure, an error + * code shall be returned. + */ + +DECLARE_PRIMITIVE(ABORT); + /* 10.1 ULP-to-SCTP * E) Send * @@ -190,6 +205,7 @@ sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) error = sctp_do_sm(event_type, subtype, state, ep, asoc, arg, GFP_ATOMIC); - return(error); + return error; + } /* sctp_other_icmp_unreachfrag() */ diff --git a/net/sctp/sctp_sm_statefuns.c b/net/sctp/sctp_sm_statefuns.c index 54b7b19fd39f..49162bd91b65 100644 --- a/net/sctp/sctp_sm_statefuns.c +++ b/net/sctp/sctp_sm_statefuns.c @@ -6,7 +6,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statefuns.c,v 1.48 2002/08/16 19:30:50 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statefuns.c,v 1.49 2002/08/21 18:34:04 jgrimm Exp $ * * This is part of the SCTP Linux Kernel Reference Implementation. * @@ -49,7 +49,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.48 2002/08/16 19:30:50 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.49 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -213,7 +213,7 @@ sctp_sf_pdiscard(const sctp_endpoint_t *ep, * We are the side that is being asked for an association. * * Section: 5.1 Normal Establishment of an Association, B - * B) "Z" shall respond immediately with an INIT ACK chunk. The + * B) "Z" shall respond immediately with an INIT ACK chunk. The * destination IP address of the INIT ACK MUST be set to the source * IP address of the INIT to which this INIT ACK is responding. In * the response, besides filling in other parameters, "Z" must set the @@ -3182,7 +3182,80 @@ sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, return disposition; } /* sctp_sf_do_9_2_prm_shutdown() */ - + +/* + * Process the ABORT primitive. + * + * Section: 10.1: + * C) Abort + * + * Format: Abort(association id [, cause code]) + * -> result + * + * Ungracefully closes an association. Any locally queued user data + * will be discarded and an ABORT chunk is sent to the peer. A success code + * will be returned on successful abortion of the association. If + * attempting to abort the association results in a failure, an error + * code shall be returned. + * + * Mandatory attributes: + * + * o association id - local handle to the SCTP association + * + * Optional attributes: + * + * o cause code - reason of the abort to be passed to the peer + * + * None. + * + * The return value is the disposition. + */ +sctp_disposition_t +sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + /* From 9.1 Abort of an Association + * Upon receipt of the ABORT primitive from its upper + * layer, the endpoint enters CLOSED state and + * discard all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + + sctp_chunk_t *abort; + sctp_disposition_t retval; + + retval = SCTP_DISPOSITION_CONSUME; + + /* Generate ABORT chunk to send the peer */ + abort = sctp_make_abort(asoc, NULL, 0); + if (!abort) { + retval = SCTP_DISPOSITION_NOMEM; + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); + } + + /* Even if we can't send the ABORT due to low memory delete the + * TCB. This is a departure from our typical NOMEM handling. + */ + + /* Change to CLOSED state */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + + /* Delete the established association */ + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + + return retval; + +} /* sctp_sf_do_9_1_prm_abort() */ + + /* We tried an illegal operation on an association which is closed. */ sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, @@ -3277,6 +3350,64 @@ sctp_sf_cookie_echoed_prm_shutdown(const sctp_endpoint_t *ep, } /* sctp_sf_cookie_echoed_prm_shutdown() */ +/* + * sctp_cookie_wait_prm_abort + * + * Section: 4 Note: 2 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explicitly address this issue, but is the route through the + * state table when someone issues an abort while in COOKIE_WAIT state. + * + * Outputs + * (timers) + */ +sctp_disposition_t +sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands){ + + /* Stop T1-init timer */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); + + return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands); + +} /* sctp_sf_cookie_wait_prm_abort() */ + +/* + * sctp_cookie_echoed_prm_abort + * + * Section: 4 Note: 3 + * Verification Tag: + * Inputs + * (endpoint, asoc) + * + * The RFC does not explcitly address this issue, but is the route through the + * state table when someone issues an abort while in COOKIE_ECHOED state. + * + * Outputs + * (timers) + */ +sctp_disposition_t +sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + + /* There is a single T1 timer, so we should be able to use + * common function with the COOKIE-WAIT state. + */ + return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands); + +} /* sctp_sf_cookie_echoed_prm_abort() */ + /* * Ignore the primitive event * diff --git a/net/sctp/sctp_sm_statetable.c b/net/sctp/sctp_sm_statetable.c index 8edf022dff70..af233f365d6a 100644 --- a/net/sctp/sctp_sm_statetable.c +++ b/net/sctp/sctp_sm_statetable.c @@ -7,7 +7,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statetable.c,v 1.19 2002/08/16 19:30:50 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statetable.c,v 1.20 2002/08/21 18:34:04 jgrimm Exp $ * * These are the state tables for the SCTP state machine. * @@ -45,7 +45,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.19 2002/08/16 19:30:50 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.20 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -721,25 +721,32 @@ chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ \ /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_cookie_wait_prm_abort, \ + name: "sctp_sf_cookie_wait_prm_abort"}, \ \ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_cookie_echoed_prm_abort, \ + name: "sctp_sf_cookie_echoed_prm_abort"}, \ \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ \ } /* TYPE_SCTP_PRIMITIVE_ABORT */ diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index 1adfc8a66c33..f27aea1a7cf9 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -7,7 +7,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_socket.c,v 1.62 2002/08/16 19:30:50 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_socket.c,v 1.63 2002/08/21 18:34:04 jgrimm Exp $ * * These functions interface with the sockets layer to implement the * SCTP Extensions for the Sockets API. @@ -53,7 +53,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_socket.c,v 1.62 2002/08/16 19:30:50 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_socket.c,v 1.63 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -838,12 +838,11 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) msg_len, sinfo_flags); /* FIXME: Support MSG_ABORT. */ - /* If MSG_EOF is set, no data can be sent. Disallow sending 0-length - * messages when MSG_EOF is not set. + /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow sending 0-length + * messages when MSG_EOF|MSG_ABORT is not set. */ - if ((sinfo_flags & MSG_ABORT) - || ((sinfo_flags & MSG_EOF) && (msg_len > 0)) - || (!(sinfo_flags & MSG_EOF) && (msg_len == 0))) { + if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) + || (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { err = -EINVAL; goto out_nounlock; } @@ -886,7 +885,13 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) sctp_primitive_SHUTDOWN(asoc, NULL); err = 0; goto out_unlock; - } + } + if (sinfo_flags & MSG_ABORT) { + SCTP_DEBUG_PRINTK("Aborting association: %p\n",asoc); + sctp_primitive_ABORT(asoc, NULL); + err = 0; + goto out_unlock; + } } @@ -1394,7 +1399,7 @@ sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) int sctp_disconnect(struct sock *sk, int flags) { - return(-EOPNOTSUPP); /* STUB */ + return -EOPNOTSUPP; /* STUB */ } /* sctp_disconnect() */ @@ -1414,7 +1419,7 @@ sctp_accept(struct sock *sk, int flags, int *err) int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - return(-EOPNOTSUPP); /* STUB */ + return -EOPNOTSUPP; /* STUB */ } /* sctp_ioctl() */ @@ -1505,7 +1510,7 @@ sctp_init_sock(struct sock *sk) sp->autoclose = 0; SCTP_DBG_OBJCNT_INC(sock); - return(0); + return 0; } /* sctp_init_sock() */ @@ -1522,7 +1527,7 @@ sctp_destroy_sock(struct sock *sk) ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); - return(0); + return 0; } /* sctp_destroy_sock() */ @@ -1621,7 +1626,7 @@ sctp_getsockopt_disable_fragments(struct sock *sk, int len, int val; if (len < sizeof(int)) { - return(-EINVAL); + return -EINVAL; } len = sizeof(int); @@ -2218,7 +2223,7 @@ sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) pp->pprev = &head->chain; } SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); - return(pp); + return pp; } /* sctp_bucket_create() */ @@ -2290,7 +2295,7 @@ sctp_autobind(struct sock *sk) break; } /* switch(family) */ - return(sctp_do_bind(sk, &autoaddr, addr_len)); + return sctp_do_bind(sk, &autoaddr, addr_len); } /* sctp_autobind() */ @@ -2652,32 +2657,32 @@ sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) sockaddr_storage_t *sa; if (msg->msg_namelen < sizeof (struct sockaddr) ) { - return (-EINVAL); + return -EINVAL; } sa = (sockaddr_storage_t *)(msg->msg_name); switch (sa->sa.sa_family) { case AF_INET: if (msg->msg_namelen < sizeof(struct sockaddr_in)) { - return(-EINVAL); + return -EINVAL; } break; case AF_INET6: if (PF_INET == sk->family) { - return(-EINVAL); + return -EINVAL; } SCTP_V6( if (msg->msg_namelen < sizeof(struct sockaddr_in6)) { - return(-EINVAL); + return -EINVAL; } break; ); default: - return (-EINVAL); + return -EINVAL; } /* Disallow any illegal addresses to be used as destinations. */ if (!sctp_addr_is_valid(sa)) { - return(-EINVAL); + return -EINVAL; } return 0; diff --git a/net/sctp/sctp_ulpevent.c b/net/sctp/sctp_ulpevent.c index 71ae3e37fe02..9b1bd47d7f8f 100644 --- a/net/sctp/sctp_ulpevent.c +++ b/net/sctp/sctp_ulpevent.c @@ -6,7 +6,7 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpevent.c,v 1.15 2002/07/12 14:50:26 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpevent.c,v 1.16 2002/08/21 18:34:04 jgrimm Exp $ * * These functions manipulate an sctp event. The sctp_ulpevent_t is used * to carry notifications and data to the ULP (sockets). @@ -41,7 +41,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpevent.c,v 1.15 2002/07/12 14:50:26 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpevent.c,v 1.16 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -79,7 +79,7 @@ sctp_ulpevent_new(int size, int msg_flags, int priority) } event->malloced = 1; - return(event); + return event; fail_init: kfree_skb(event->parent); @@ -99,7 +99,7 @@ sctp_ulpevent_init(sctp_ulpevent_t *event, event->msg_flags = msg_flags; event->parent = parent; event->malloced = 0; - return(event); + return event; } /* sctp_ulpevent_init() */ @@ -119,7 +119,7 @@ sctp_ulpevent_free(sctp_ulpevent_t *event) int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) { - return(event->msg_flags & MSG_NOTIFICATION); + return event->msg_flags & MSG_NOTIFICATION; } /* sctp_ulpevent_is_notification() */ @@ -237,9 +237,9 @@ sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, */ sac->sac_assoc_id = sctp_assoc2id(asoc); - return(event); + return event; fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_assoc_change() */ @@ -346,9 +346,9 @@ sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); - return(event); + return event; fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_peer_addr_change() */ @@ -472,9 +472,9 @@ sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, sre->sre_assoc_id = sctp_assoc2id(asoc); - return(event); + return event; fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_remote_error () */ @@ -585,9 +585,9 @@ sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ssf->ssf_assoc_id = sctp_assoc2id(asoc); - return(event); + return event; fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_send_failed () */ @@ -651,9 +651,9 @@ sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, */ sse->sse_assoc_id = sctp_assoc2id(asoc); - return(event); + return event; fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_shutdown_event () */ @@ -802,12 +802,12 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, info->sinfo_assoc_id = sctp_assoc2id(asoc); - return(event); + return event; fail_init: kfree_skb(skb); fail: - return(NULL); + return NULL; } /* sctp_ulpevent_make_rcvmsg() */ @@ -821,7 +821,7 @@ sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) notification = (union sctp_notification *)event->parent->data; - return(notification->h.sn_type); + return notification->h.sn_type; } /* sctp_ulpevent_get_notification_type() */ diff --git a/net/sctp/sctp_ulpqueue.c b/net/sctp/sctp_ulpqueue.c index c6a6149e2c80..3d7b86f45ed4 100644 --- a/net/sctp/sctp_ulpqueue.c +++ b/net/sctp/sctp_ulpqueue.c @@ -6,7 +6,7 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpqueue.c,v 1.13 2002/07/12 14:50:26 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_ulpqueue.c,v 1.14 2002/08/21 18:34:04 jgrimm Exp $ * * This abstraction carries sctp events to the ULP (sockets). * @@ -42,7 +42,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpqueue.c,v 1.13 2002/07/12 14:50:26 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpqueue.c,v 1.14 2002/08/21 18:34:04 jgrimm Exp $"; #include #include @@ -85,7 +85,7 @@ sctp_ulpqueue_new(sctp_association_t *asoc, uint16_t inbound, int priority) } ulpq->malloced = 1; - return(ulpq); + return ulpq; fail_init: kfree(ulpq); @@ -109,7 +109,7 @@ sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, sctp_association_t *asoc, skb_queue_head_init(&ulpq->lobby); ulpq->malloced = 0; - return(ulpq); + return ulpq; } /* sctp_ulpqueue_init() */ @@ -187,7 +187,7 @@ sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk, sctp_ulpqueue_tail_event(ulpq, event); } - return(0); + return 0; } /* sctp_ulpqueue_tail_data() */ @@ -391,13 +391,13 @@ sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) /* Check if this is part of a fragmented message. */ if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) { - return(event); + return event; } sctp_ulpqueue_store_reasm(ulpq, event); retval = sctp_ulpqueue_retrieve_reassembled(ulpq); - return(retval); + return retval; } /* sctp_ulpqueue_reasm() */ @@ -504,7 +504,7 @@ sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) /* Check if this message needs ordering. */ if (SCTP_DATA_UNORDERED & event->chunk_flags) { - return(event); + return event; } /* Note: The stream ID must be verified before this routine. */ @@ -521,7 +521,7 @@ sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) sctp_ulpqueue_store_ordered(ulpq, event); - return(NULL); + return NULL; } /* Mark that the next chunk has been found. */ @@ -533,7 +533,7 @@ sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) sctp_ulpqueue_retrieve_ordered(ulpq, event); - return(event); + return event; } /* sctp_ulpqueue_order() */ -- cgit v1.2.3 From 990d1889842757d4f64a50127fbc938a27283f5e Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Wed, 21 Aug 2002 11:43:01 -0500 Subject: Update statetable for prm ABORT and prm SHUTDOWN in the closed state (this should turn into an error just like we do in prm SEND). --- net/sctp/sctp_sm_statetable.c | 8 ++++---- net/sctp/sctp_socket.c | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/net/sctp/sctp_sm_statetable.c b/net/sctp/sctp_sm_statetable.c index af233f365d6a..adf5ceec3853 100644 --- a/net/sctp/sctp_sm_statetable.c +++ b/net/sctp/sctp_sm_statetable.c @@ -7,7 +7,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statetable.c,v 1.20 2002/08/21 18:34:04 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_sm_statetable.c,v 1.21 2002/08/22 02:25:33 jgrimm Exp $ * * These are the state tables for the SCTP state machine. * @@ -45,7 +45,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.20 2002/08/21 18:34:04 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.21 2002/08/22 02:25:33 jgrimm Exp $"; #include #include @@ -685,7 +685,7 @@ chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_cookie_wait_prm_shutdown, \ @@ -718,7 +718,7 @@ chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_cookie_wait_prm_abort, \ diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index f27aea1a7cf9..dfc05cd885e8 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -7,7 +7,7 @@ * * This file is part of the SCTP kernel reference Implementation * - * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_socket.c,v 1.63 2002/08/21 18:34:04 jgrimm Exp $ + * $Header: /cvsroot/lksctp/lksctp/sctp_cvs/net/sctp/sctp_socket.c,v 1.64 2002/08/21 23:06:28 jgrimm Exp $ * * These functions interface with the sockets layer to implement the * SCTP Extensions for the Sockets API. @@ -53,7 +53,7 @@ * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_socket.c,v 1.63 2002/08/21 18:34:04 jgrimm Exp $"; +static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_socket.c,v 1.64 2002/08/21 23:06:28 jgrimm Exp $"; #include #include @@ -837,9 +837,8 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) SCTP_DEBUG_PRINTK("msg_len: %d, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); - /* FIXME: Support MSG_ABORT. */ - /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow sending 0-length - * messages when MSG_EOF|MSG_ABORT is not set. + /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow + * sending 0-length messages when MSG_EOF|MSG_ABORT is not set. */ if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) || (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { -- cgit v1.2.3 From f82c185fc9172fe7b6c27a6a9ef4b2ef284dda03 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 27 Aug 2002 08:02:54 -0700 Subject: include/linux/sctp.h: Use __u{8,16,32} instead of uint{8,16,32}_t --- include/linux/sctp.h | 84 ++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/include/linux/sctp.h b/include/linux/sctp.h index bca0f0f0682b..b070fc1220e5 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -57,17 +57,17 @@ /* Section 3.1. SCTP Common Header Format */ typedef struct sctphdr { - uint16_t source; - uint16_t dest; - uint32_t vtag; - uint32_t checksum; + __u16 source; + __u16 dest; + __u32 vtag; + __u32 checksum; } sctp_sctphdr_t __attribute__((packed)); /* Section 3.2. Chunk Field Descriptions. */ typedef struct sctp_chunkhdr { - uint8_t type; - uint8_t flags; - uint16_t length; + __u8 type; + __u8 flags; + __u16 length; } sctp_chunkhdr_t __attribute__((packed)); @@ -150,8 +150,8 @@ enum { SCTP_CHUNK_FLAG_T = 0x01 }; */ typedef struct sctp_paramhdr { - uint16_t type; - uint16_t length; + __u16 type; + __u16 length; } sctp_paramhdr_t __attribute((packed)); typedef enum { @@ -196,11 +196,11 @@ typedef enum { /* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ typedef struct sctp_datahdr { - uint32_t tsn; - uint16_t stream; - uint16_t ssn; - uint32_t ppid; - uint8_t payload[0]; + __u32 tsn; + __u16 stream; + __u16 ssn; + __u32 ppid; + __u8 payload[0]; } sctp_datahdr_t __attribute__((packed)); typedef struct sctp_data_chunk { @@ -225,12 +225,12 @@ enum { SCTP_DATA_FRAG_MASK = 0x03, }; * endpoints. */ typedef struct sctp_inithdr { - uint32_t init_tag; - uint32_t a_rwnd; - uint16_t num_outbound_streams; - uint16_t num_inbound_streams; - uint32_t initial_tsn; - uint8_t params[0]; + __u32 init_tag; + __u32 a_rwnd; + __u16 num_outbound_streams; + __u16 num_inbound_streams; + __u32 initial_tsn; + __u8 params[0]; } sctp_inithdr_t __attribute__((packed)); typedef struct sctp_init_chunk { @@ -285,7 +285,7 @@ typedef sctp_init_chunk_t sctp_initack_chunk_t; /* Section 3.3.3.1 State Cookie (7) */ typedef struct sctp_cookie_param { sctp_paramhdr_t p; - uint8_t body[0]; + __u8 body[0]; } sctp_cookie_param_t __attribute__((packed)); /* Section 3.3.3.1 Unrecognized Parameters (8) */ @@ -305,8 +305,8 @@ typedef struct sctp_unrecognized_param { */ typedef struct sctp_gap_ack_block { - uint16_t start; - uint16_t end; + __u16 start; + __u16 end; } sctp_gap_ack_block_t __attribute__((packed)); typedef uint32_t sctp_dup_tsn_t; @@ -317,10 +317,10 @@ typedef union { } sctp_sack_variable_t; typedef struct sctp_sackhdr { - uint32_t cum_tsn_ack; - uint32_t a_rwnd; - uint16_t num_gap_ack_blocks; - uint16_t num_dup_tsns; + __u32 cum_tsn_ack; + __u32 a_rwnd; + __u16 num_gap_ack_blocks; + __u16 num_dup_tsns; sctp_sack_variable_t variable[0]; } sctp_sackhdr_t __attribute__((packed)); @@ -360,7 +360,7 @@ typedef struct sctp_abort_chunk { * and the highest consecutive acking value. */ typedef struct sctp_shutdownhdr { - uint32_t cum_tsn_ack; + __u32 cum_tsn_ack; } sctp_shutdownhdr_t __attribute__((packed)); struct sctp_shutdown_chunk_t { @@ -373,9 +373,9 @@ struct sctp_shutdown_chunk_t { /* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ typedef struct sctp_errhdr { - uint16_t cause; - uint16_t length; - uint8_t variable[0]; + __u16 cause; + __u16 length; + __u8 variable[0]; } sctp_errhdr_t __attribute__((packed)); typedef struct sctp_operr_chunk { @@ -450,7 +450,7 @@ typedef enum { * Explicit Congestion Notification Echo (ECNE) (12) */ typedef struct sctp_ecnehdr { - uint32_t lowest_tsn; + __u32 lowest_tsn; } sctp_ecnehdr_t; typedef struct sctp_ecne_chunk { @@ -462,7 +462,7 @@ typedef struct sctp_ecne_chunk { * Congestion Window Reduced (CWR) (13) */ typedef struct sctp_cwrhdr { - uint32_t lowest_tsn; + __u32 lowest_tsn; } sctp_cwrhdr_t; typedef struct sctp_cwr_chunk { @@ -496,9 +496,9 @@ typedef struct sctp_cwr_chunk { * an ASCONF Chunk. */ typedef struct { - uint32_t correlation; + __u32 correlation; sctp_paramhdr_t p; - uint8_t payload[0]; + __u8 payload[0]; } sctpAsconfReq_t; /* ADDIP @@ -512,10 +512,10 @@ typedef struct { * variable parameters. */ typedef struct { - uint32_t serial; - uint8_t reserved[3]; - uint8_t addr_type; - uint32_t addr[4]; + __u32 serial; + __u8 reserved[3]; + __u8 addr_type; + __u32 addr[4]; sctpAsconfReq_t requests[0]; } sctpAsconf_t; @@ -539,11 +539,11 @@ typedef struct { */ typedef union { struct { - uint32_t correlation; + __u32 correlation; sctp_paramhdr_t header; /* success report */ } success; struct { - uint32_t correlation; + __u32 correlation; sctp_paramhdr_t header; /* error cause indication */ sctp_paramhdr_t errcause; uint8_t request[0]; /* original request from ASCONF */ @@ -562,7 +562,7 @@ typedef union { * ASCONF Parameters that were processed by the receiver. */ typedef struct { - uint32_t serial; + __u32 serial; sctpAsconfAckRsp_t responses[0]; } sctpAsconfAck_t; -- cgit v1.2.3 From 13f5f8af450deb72384458cfca7bc2e919382c29 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 10:35:15 -0700 Subject: [SCTP]: Whitespace/codingstyle fixups, plus a bug fix or two. --- include/net/sctp/sctp.h | 210 +-- include/net/sctp/sctp_command.h | 57 +- include/net/sctp/sctp_constants.h | 115 +- include/net/sctp/sctp_sla1.h | 47 +- include/net/sctp/sctp_sm.h | 93 +- include/net/sctp/sctp_structs.h | 1055 ++++++------ include/net/sctp/sctp_tsnmap.h | 56 +- include/net/sctp/sctp_ulpevent.h | 102 +- include/net/sctp/sctp_ulpqueue.h | 43 +- include/net/sctp/sctp_user.h | 314 ++-- net/sctp/Config.help | 5 + net/sctp/Makefile | 26 +- net/sctp/sctp_adler32.c | 133 +- net/sctp/sctp_associola.c | 770 ++++----- net/sctp/sctp_bind_addr.c | 368 ++--- net/sctp/sctp_command.c | 51 +- net/sctp/sctp_crc32c.c | 217 ++- net/sctp/sctp_debug.c | 79 +- net/sctp/sctp_endpointola.c | 297 ++-- net/sctp/sctp_hashdriver.c | 142 +- net/sctp/sctp_input.c | 438 +++-- net/sctp/sctp_inqueue.c | 187 +-- net/sctp/sctp_ipv6.c | 125 +- net/sctp/sctp_objcnt.c | 50 +- net/sctp/sctp_output.c | 499 +++--- net/sctp/sctp_outqueue.c | 1262 +++++++------- net/sctp/sctp_primitive.c | 130 +- net/sctp/sctp_protocol.c | 404 ++--- net/sctp/sctp_sla1.c | 415 +++-- net/sctp/sctp_sm_make_chunk.c | 1669 +++++++++---------- net/sctp/sctp_sm_sideeffect.c | 897 +++++----- net/sctp/sctp_sm_statefuns.c | 3297 +++++++++++++++++-------------------- net/sctp/sctp_sm_statetable.c | 2025 +++++++++-------------- net/sctp/sctp_socket.c | 1957 ++++++++++------------ net/sctp/sctp_sysctl.c | 87 +- net/sctp/sctp_transport.c | 364 ++-- net/sctp/sctp_tsnmap.c | 291 ++-- net/sctp/sctp_ulpevent.c | 620 +++---- net/sctp/sctp_ulpqueue.c | 463 +++--- 39 files changed, 8724 insertions(+), 10636 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 29bd3ccf8e0d..8c8abb0251a5 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -118,18 +118,18 @@ extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, sctp_scope_t, int priority, int flags); -/* - * sctp_socket.c +/* + * sctp_socket.c */ extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); extern int sctp_inet_listen(struct socket *sock, int backlog); extern int sctp_get_port(struct sock *sk, unsigned short snum); extern void sctp_write_space(struct sock *sk); -extern unsigned int sctp_poll(struct file *file, struct socket *sock, +extern unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); -/* - * sctp_primitive.c +/* + * sctp_primitive.c */ extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); @@ -137,13 +137,13 @@ extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); extern int sctp_primitive_SEND(sctp_association_t *, void *arg); -/* +/* * sctp_crc32c.c */ -extern uint32_t count_crc(uint8_t *ptr, uint16_t count); +extern __u32 count_crc(__u8 *ptr, __u16 count); -/* - * sctp_input.c +/* + * sctp_input.c */ extern int sctp_rcv(struct sk_buff *skb); extern void sctp_v4_err(struct sk_buff *skb, u32 info); @@ -156,12 +156,12 @@ extern void __sctp_hash_endpoint(sctp_endpoint_t *); extern void sctp_unhash_endpoint(sctp_endpoint_t *); extern void __sctp_unhash_endpoint(sctp_endpoint_t *); -/* +/* * sctp_hashdriver.c */ extern void sctp_hash_digest(const char *secret, const int secret_len, const char *text, const int text_len, - uint8_t *digest); + __u8 *digest); /* * Section: Macros, externs, and inlines @@ -197,29 +197,23 @@ extern void sctp_hash_digest(const char *secret, const int secret_len, #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk) -/* Determine if this is a valid kernel address. - */ -static inline int -sctp_is_valid_kaddr(unsigned long addr) +/* Determine if this is a valid kernel address. */ +static inline int sctp_is_valid_kaddr(unsigned long addr) { struct page *page; /* Make sure the address is not in the user address space. */ - if (addr < PAGE_OFFSET) { + if (addr < PAGE_OFFSET) return 0; - } page = virt_to_page(addr); /* Is this page valid? */ - if (!virt_addr_valid(addr) || PageReserved(page)) { + if (!virt_addr_valid(addr) || PageReserved(page)) return 0; - } return 1; - -} /* sctp_is_valid_kaddr() */ - +} #endif /* !TEST_FRAME */ @@ -249,8 +243,8 @@ extern int sctp_debug_flag; #endif /* SCTP_DEBUG */ -/* - * Macros for keeping a global reference of object allocations. +/* + * Macros for keeping a global reference of object allocations. */ #ifdef CONFIG_SCTP_DBG_OBJCNT @@ -262,8 +256,7 @@ extern atomic_t sctp_dbg_objcnt_chunk; extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_addr; -/* Macros to atomically increment/decrement objcnt counters. -*/ +/* Macros to atomically increment/decrement objcnt counters. */ #define SCTP_DBG_OBJCNT_INC(name) \ atomic_inc(&sctp_dbg_objcnt_## name) #define SCTP_DBG_OBJCNT_DEC(name) \ @@ -272,8 +265,8 @@ atomic_dec(&sctp_dbg_objcnt_## name) atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0) /* Macro to help create new entries in in the global array of - * objcnt counters. - */ + * objcnt counters. + */ #define SCTP_DBG_OBJCNT_ENTRY(name) \ {.label= #name, .counter= &sctp_dbg_objcnt_## name} @@ -285,14 +278,14 @@ extern void sctp_dbg_objcnt_exit(void); #define SCTP_DBG_OBJCNT_INC(name) #define SCTP_DBG_OBJCNT_DEC(name) -static inline void sctp_dbg_objcnt_init(void) { return; } +static inline void sctp_dbg_objcnt_init(void) { return; } static inline void sctp_dbg_objcnt_exit(void) { return; } #endif /* CONFIG_SCTP_DBG_OBJCOUNT */ #if defined CONFIG_SYSCTL extern void sctp_sysctl_register(void); -extern void sctp_sysctl_unregister(void); +extern void sctp_sysctl_unregister(void); #else static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_unregister(void) { return; } @@ -304,65 +297,56 @@ static inline void sctp_sysctl_unregister(void) { return; } extern int sctp_v6_init(void); extern void sctp_v6_exit(void); -static inline int -sctp_ipv6_addr_type(const struct in6_addr* addr) +static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) { - return(ipv6_addr_type((struct in6_addr*)addr)); + return ipv6_addr_type((struct in6_addr*) addr); } -#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(uint16_t)) +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16)) /* Note: These V6 macros are obsolescent. */ /* Use this macro to enclose code fragments which are V6-dependent. */ #define SCTP_V6(m...) m -#define SCTP_V6_SUPPORT 1 +#define SCTP_V6_SUPPORT 1 #else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #define sctp_ipv6_addr_type(a) 0 -#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(uint16_t)) -#define SCTP_V6(m...) /* Do nothing. */ -#undef SCTP_V6_SUPPORT +#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16)) +#define SCTP_V6(m...) /* Do nothing. */ +#undef SCTP_V6_SUPPORT static inline int sctp_v6_init(void) { return 0; } -static inline void sctp_v6_exit(void) {return; } +static inline void sctp_v6_exit(void) { return; } #endif /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ /* Map an association to an assoc_id. */ -static inline sctp_assoc_t -sctp_assoc2id(const sctp_association_t *asoc) +static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) { - return ((sctp_assoc_t)asoc); - -} /* sctp_assoc2id() */ + return (sctp_assoc_t) asoc; +} +/* Look up the association by its id. */ +static inline sctp_association_t *sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) +{ + sctp_association_t *asoc = NULL; -/* Look up the association by its id. - */ -static inline sctp_association_t * -sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) -{ - sctp_association_t *asoc = NULL; - /* First, verify that this is a kernel address. */ - if (sctp_is_valid_kaddr((unsigned long)id)) { - sctp_association_t *temp; - temp = (sctp_association_t *)id; - + if (sctp_is_valid_kaddr((unsigned long) id)) { + sctp_association_t *temp = (sctp_association_t *) id; + /* Verify that this _is_ an sctp_association_t * data structure and if so, that the socket matches. */ - if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) - && (temp->base.sk == sk)) { + if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && + (temp->base.sk == sk)) asoc = temp; - } } - - return(asoc); -} /* sctp_id2assoc() */ + return asoc; +} /* A macro to walk a list of skbs. */ #define sctp_skb_for_each(pos, head, tmp) \ @@ -372,24 +356,22 @@ for (pos = (head)->next;\ /* A helper to append an entire skb list (list) to another (head). */ -static inline void -sctp_skb_list_tail(struct sk_buff_head *list, - struct sk_buff_head *head) +static inline void sctp_skb_list_tail(struct sk_buff_head *list, + struct sk_buff_head *head) { int flags __attribute__ ((unused)); - sctp_spin_lock_irqsave(&head->lock, flags); + sctp_spin_lock_irqsave(&head->lock, flags); sctp_spin_lock(&list->lock); list_splice((struct list_head *)list, (struct list_head *)head->prev); - + head->qlen += list->qlen; list->qlen = 0; sctp_spin_unlock(&list->lock); sctp_spin_unlock_irqrestore(&head->lock, flags); - -} /* sctp_skb_list_tail() */ +} /** * sctp_list_dequeue - remove from the head of the queue @@ -399,38 +381,31 @@ sctp_skb_list_tail(struct sk_buff_head *list, * returned or %NULL if the list is empty. */ -static inline struct list_head * -sctp_list_dequeue(struct list_head *list) -{ - struct list_head *result; - - result = (void *) 0; - if ( list->next != list ) { - result = list->next; - list->next = result->next; - list->next->prev = list; - INIT_LIST_HEAD(result); - } - return result; - -} /* sctp_list_dequeue() */ +static inline struct list_head *sctp_list_dequeue(struct list_head *list) +{ + struct list_head *result = NULL; + if (list->next != list) { + result = list->next; + list->next = result->next; + list->next->prev = list; + INIT_LIST_HEAD(result); + } + return result; +} /* Calculate the size (in bytes) occupied by the data of an iovec. */ -static inline size_t -get_user_iov_size(struct iovec *iov, int iovlen) { - size_t retval; - - retval = 0; - - for (; iovlen > 0; --iovlen) { - retval += iov->iov_len; - iov++; - } +static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) +{ + size_t retval = 0; - return(retval); + for (; iovlen > 0; --iovlen) { + retval += iov->iov_len; + iov++; + } -} /* get_user_iov_size() */ + return retval; +} /* Round an int up to the next multiple of 4. */ @@ -446,8 +421,7 @@ get_user_iov_size(struct iovec *iov, int iovlen) { /* Stolen from net/profile.h. Using it from there is more grief than * it is worth. */ -static inline void -tv_add(const struct timeval *entered, struct timeval *leaved) +static inline void tv_add(const struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec + entered->tv_usec; time_t secs = leaved->tv_sec + entered->tv_sec; @@ -458,8 +432,7 @@ tv_add(const struct timeval *entered, struct timeval *leaved) } leaved->tv_sec = secs; leaved->tv_usec = usecs; - -} /* tv_add() */ +} /* External references. */ @@ -473,51 +446,44 @@ extern void sctp_put_port(struct sock *sk); /* Return the SCTP protocol structure. */ static inline sctp_protocol_t *sctp_get_protocol(void) { - return(&sctp_proto); - -} /* sctp_get_protocol() */ - + return &sctp_proto; +} /* Warning: The following hash functions assume a power of two 'size'. */ /* This is the hash function for the SCTP port hash table. */ -static inline int sctp_phashfn(uint16_t lport) +static inline int sctp_phashfn(__u16 lport) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); - return (lport & (sctp_proto->port_hashsize - 1)); - -} /* sctp_phashfn() */ + return (lport & (sctp_proto->port_hashsize - 1)); +} /* This is the hash function for the endpoint hash table. */ -static inline int sctp_ep_hashfn(uint16_t lport) +static inline int sctp_ep_hashfn(__u16 lport) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); - return (lport & (sctp_proto->ep_hashsize - 1)); - -} /* sctp_ep_hashfn() */ + return (lport & (sctp_proto->ep_hashsize - 1)); +} /* This is the hash function for the association hash table. */ -static inline int sctp_assoc_hashfn(uint16_t lport, uint16_t rport) +static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= h>>8; - return (h & (sctp_proto->assoc_hashsize-1)); - -} /* sctp_ep_hashfn() */ + return (h & (sctp_proto->assoc_hashsize - 1)); +} -/* This is the hash function for the association hash table. This is +/* This is the hash function for the association hash table. This is * not used yet, but could be used as a better hash function when - * we have a vtag. -*/ -static inline int sctp_vtag_hashfn(uint16_t lport, uint16_t rport, - uint32_t vtag) + * we have a vtag. + */ +static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= vtag; return (h & (sctp_proto->assoc_hashsize-1)); - -} /* sctp_vtag_hashfn() */ +} /* WARNING: Do not change the layout of the members in sctp_sock! */ struct sctp_sock { diff --git a/include/net/sctp/sctp_command.h b/include/net/sctp/sctp_command.h index 86f23e7dca00..4fd50d56fefb 100644 --- a/include/net/sctp/sctp_command.h +++ b/include/net/sctp/sctp_command.h @@ -73,21 +73,21 @@ typedef enum { 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_START, /* Start the heartbeat timers. */ 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_BAD_TAG, /* Verification tags didn't match. */ SCTP_CMD_PROCESS_CTSN, /* Sideeffect from shutdown. */ - SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ + SCTP_CMD_ASSOC_FAILED, /* Handle association failure. */ SCTP_CMD_DISCARD_PACKET, /* Discard the whole packet. */ - SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ + SCTP_CMD_GEN_SHUTDOWN, /* Generate a SHUTDOWN chunk. */ SCTP_CMD_UPDATE_ASSOC, /* Update association information. */ SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ SCTP_CMD_LAST -} sctp_verb_t; /* enum */ +} sctp_verb_t; #define SCTP_CMD_MAX (SCTP_CMD_LAST - 1) #define SCTP_CMD_NUM_VERBS (SCTP_CMD_MAX + 1) @@ -100,10 +100,10 @@ typedef enum { #define SCTP_MAX_NUM_COMMANDS 14 typedef union { - int32_t i32; - uint32_t u32; - uint16_t u16; - uint8_t u8; + __s32 i32; + __u32 u32; + __u16 u16; + __u8 u8; int error; sctp_state_t state; sctp_event_timeout_t to; @@ -120,41 +120,38 @@ typedef union { } sctp_arg_t; /* We are simulating ML type constructors here. - * + * * SCTP_ARG_CONSTRUCTOR(NAME, TYPE, ELT) builds a function called * SCTP_NAME() which takes an argument of type TYPE and returns an * sctp_arg_t. It does this by inserting the sole argument into the * ELT union element of a local sctp_arg_t. * - * E.g., SCTP_ARG_CONSTRUCTOR(I32, int32_t, i32) builds SCTP_I32(arg), - * which takes an int32_t and returns a sctp_arg_t containing the - * int32_t. So, after foo = SCTP_I32(arg), foo.i32 == arg. + * E.g., SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) builds SCTP_I32(arg), + * which takes an __s32 and returns a sctp_arg_t containing the + * __s32. So, after foo = SCTP_I32(arg), foo.i32 == arg. */ -static inline sctp_arg_t -SCTP_NULL(void) +static inline sctp_arg_t SCTP_NULL(void) { - sctp_arg_t retval; retval.ptr = NULL; return(retval); + sctp_arg_t retval; retval.ptr = NULL; return retval; } -static inline sctp_arg_t -SCTP_NOFORCE(void) +static inline sctp_arg_t SCTP_NOFORCE(void) { - sctp_arg_t retval; retval.i32 = 0; return(retval); + sctp_arg_t retval; retval.i32 = 0; return retval; } -static inline sctp_arg_t -SCTP_FORCE(void) +static inline sctp_arg_t SCTP_FORCE(void) { - sctp_arg_t retval; retval.i32 = 1; return(retval); + sctp_arg_t retval; retval.i32 = 1; return retval; } #define SCTP_ARG_CONSTRUCTOR(name, type, elt) \ static inline sctp_arg_t \ SCTP_## name (type arg) \ -{ sctp_arg_t retval; retval.elt = arg; return(retval); } +{ sctp_arg_t retval; retval.elt = arg; return retval; } -SCTP_ARG_CONSTRUCTOR(I32, int32_t, i32) -SCTP_ARG_CONSTRUCTOR(U32, int32_t, u32) -SCTP_ARG_CONSTRUCTOR(U16, int32_t, u16) -SCTP_ARG_CONSTRUCTOR(U8, int32_t, u8) +SCTP_ARG_CONSTRUCTOR(I32, __s32, i32) +SCTP_ARG_CONSTRUCTOR(U32, __u32, u32) +SCTP_ARG_CONSTRUCTOR(U16, __u16, u16) +SCTP_ARG_CONSTRUCTOR(U8, __u8, u8) SCTP_ARG_CONSTRUCTOR(ERROR, int, error) SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) @@ -176,12 +173,12 @@ typedef struct { typedef struct { sctp_cmd_t cmds[SCTP_MAX_NUM_COMMANDS]; - uint8_t next_free_slot; - uint8_t next_cmd; + __u8 next_free_slot; + __u8 next_cmd; } sctp_cmd_seq_t; -/* Create a new sctp_command_sequence. +/* Create a new sctp_command_sequence. * Return NULL if creating a new sequence fails. */ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); diff --git a/include/net/sctp/sctp_constants.h b/include/net/sctp/sctp_constants.h index 03675a7f6b6a..58e910dd87da 100644 --- a/include/net/sctp/sctp_constants.h +++ b/include/net/sctp/sctp_constants.h @@ -62,8 +62,8 @@ /* 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 +/* 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. */ @@ -71,8 +71,8 @@ enum { SCTP_MAX_STREAM = 10 }; + sizeof(struct ipv6hdr)\ + MAX_HEADER)) -/* Define the amount of space to reserve for SCTP, IP, LL. - * There is a little bit of waste that we are always allocating +/* 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. */ @@ -93,10 +93,10 @@ enum { SCTP_MAX_STREAM = 10 }; /* These are the different flavours of event. */ typedef enum { - SCTP_EVENT_T_CHUNK = 1, - SCTP_EVENT_T_TIMEOUT, - SCTP_EVENT_T_OTHER, - SCTP_EVENT_T_PRIMITIVE + SCTP_EVENT_T_CHUNK = 1, + SCTP_EVENT_T_TIMEOUT, + SCTP_EVENT_T_OTHER, + SCTP_EVENT_T_PRIMITIVE } sctp_event_t; @@ -127,8 +127,8 @@ typedef enum { typedef enum { - SCTP_EVENT_NO_PENDING_TSN = 0, - SCTP_EVENT_ICMP_UNREACHFRAG, + SCTP_EVENT_NO_PENDING_TSN = 0, + SCTP_EVENT_ICMP_UNREACHFRAG, } sctp_event_other_t; @@ -138,22 +138,22 @@ typedef enum { /* These are primitive requests from the ULP. */ typedef enum { - SCTP_PRIMITIVE_INITIALIZE = 0, - SCTP_PRIMITIVE_ASSOCIATE, - 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_PRIMITIVE_INITIALIZE = 0, + SCTP_PRIMITIVE_ASSOCIATE, + 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; @@ -167,7 +167,7 @@ typedef enum { */ typedef union { - + sctp_cid_t chunk; sctp_event_timeout_t timeout; sctp_event_other_t other; @@ -178,7 +178,7 @@ typedef union { #define SCTP_SUBTYPE_CONSTRUCTOR(_name, _type, _elt) \ static inline sctp_subtype_t \ SCTP_ST_## _name (_type _arg) \ -{ sctp_subtype_t _retval; _retval._elt = _arg; return(_retval); } +{ sctp_subtype_t _retval; _retval._elt = _arg; return _retval; } SCTP_SUBTYPE_CONSTRUCTOR(CHUNK, sctp_cid_t, chunk) SCTP_SUBTYPE_CONSTRUCTOR(TIMEOUT, sctp_event_timeout_t, timeout) @@ -204,18 +204,18 @@ extern const char *sctp_param_tbl[]; /* Internal error codes */ typedef enum { - SCTP_IERROR_NO_ERROR = 0, - SCTP_IERROR_BASE = 1000, - SCTP_IERROR_NO_COOKIE, - SCTP_IERROR_BAD_SIG, - SCTP_IERROR_STALE_COOKIE, - SCTP_IERROR_NOMEM, - SCTP_IERROR_MALFORMED, - SCTP_IERROR_BAD_TAG, - SCTP_IERROR_BIG_GAP, - SCTP_IERROR_DUP_TSN, + SCTP_IERROR_NO_ERROR = 0, + SCTP_IERROR_BASE = 1000, + SCTP_IERROR_NO_COOKIE, + SCTP_IERROR_BAD_SIG, + SCTP_IERROR_STALE_COOKIE, + SCTP_IERROR_NOMEM, + SCTP_IERROR_MALFORMED, + SCTP_IERROR_BAD_TAG, + SCTP_IERROR_BIG_GAP, + SCTP_IERROR_DUP_TSN, -} sctp_ierror_t; /* enum */ +} sctp_ierror_t; @@ -232,7 +232,7 @@ typedef enum { SCTP_STATE_SHUTDOWN_RECEIVED = 7, SCTP_STATE_SHUTDOWN_ACK_SENT = 8, -} sctp_state_t; /* enum */ +} sctp_state_t; #define SCTP_STATE_MAX SCTP_STATE_SHUTDOWN_ACK_SENT #define SCTP_STATE_NUM_STATES (SCTP_STATE_MAX + 1) @@ -262,7 +262,7 @@ const char *sctp_oname(const sctp_subtype_t); /* other events */ const char *sctp_tname(const sctp_subtype_t); /* timeouts */ const char *sctp_pname(const sctp_subtype_t); /* primitives */ -/* This is a table of printable names of sctp_state_t's. */ +/* This is a table of printable names of sctp_state_t's. */ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; /* SCTP reachability state for each address */ @@ -281,7 +281,7 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; * NEVER make this more than 32767 (2^15-1). The Gap Ack Blocks in a * SACK (see section 3.3.4) are only 16 bits, so 2*SCTP_TSN_MAP_SIZE * must be less than 65535 (2^16 - 1), or we will have overflow - * problems creating SACK's. + * problems creating SACK's. */ #define SCTP_TSN_MAP_SIZE 2048 #define SCTP_TSN_MAX_GAP 65535 @@ -289,20 +289,19 @@ extern const char *sctp_state_tbl[], *sctp_evttype_tbl[], *sctp_status_tbl[]; /* We will not record more than this many duplicate TSNs between two * SACKs. The minimum PMTU is 576. Remove all the headers and there * 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 typedef enum { SCTP_COUNTER_INIT_ERROR, -} sctp_counter_t; +} sctp_counter_t; /* How many counters does an association need? */ #define SCTP_NUMBER_COUNTERS 5 -/* Here we define the default timers. - */ +/* Here we define the default timers. */ /* cookie timer def = ? seconds */ #define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ) @@ -355,7 +354,7 @@ typedef enum { */ #define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */ #define SCTP_HOW_MANY_SECRETS 2 /* How many secrets I keep */ -#define SCTP_HOW_LONG_COOKIE_LIVE 3600 /* How many seconds the current +#define SCTP_HOW_LONG_COOKIE_LIVE 3600 /* How many seconds the current * secret will live? */ #define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */ @@ -370,10 +369,10 @@ typedef enum { * routines which form the lower interface to SCTP_outqueue. */ typedef enum { - SCTP_XMIT_OK, - SCTP_XMIT_PMTU_FULL, - SCTP_XMIT_RWND_FULL, - SCTP_XMIT_MUST_FRAG, + SCTP_XMIT_OK, + SCTP_XMIT_PMTU_FULL, + SCTP_XMIT_RWND_FULL, + SCTP_XMIT_MUST_FRAG, } sctp_xmit_t; /* These are the commands for manipulating transports. */ @@ -383,9 +382,9 @@ typedef enum { } sctp_transport_cmd_t; /* These are the address scopes defined mainly for IPv4 addresses - * based on draft of SCTP IPv4 scoping . - * These scopes are hopefully generic enough to be used on scoping both - * IPv4 and IPv6 addresses in SCTP. + * based on draft of SCTP IPv4 scoping . + * These scopes are hopefully generic enough to be used on scoping both + * IPv4 and IPv6 addresses in SCTP. * At this point, the IPv6 scopes will be mapped to these internal scopes * as much as possible. */ @@ -397,10 +396,10 @@ typedef enum { SCTP_SCOPE_UNUSABLE, /* IPv4 unusable addresses */ } sctp_scope_t; -/* Based on IPv4 scoping , - * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, +/* Based on IPv4 scoping , + * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, * 192.88.99.0/24. - * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP + * Also, RFC 8.4, non-unicast addresses are not considered valid SCTP * addresses. */ #define IS_IPV4_UNUSABLE_ADDRESS(a) \ @@ -436,7 +435,7 @@ typedef enum { /* Flags used for the bind address copy functions. */ #define SCTP_ADDR6_ALLOWED 0x00000001 /* IPv6 address is allowed by - local sock family */ + local sock family */ #define SCTP_ADDR4_PEERSUPP 0x00000002 /* IPv4 address is supported by peer */ #define SCTP_ADDR6_PEERSUPP 0x00000004 /* IPv6 address is supported by diff --git a/include/net/sctp/sctp_sla1.h b/include/net/sctp/sctp_sla1.h index 964da227c796..9e88f6748334 100644 --- a/include/net/sctp/sctp_sla1.h +++ b/include/net/sctp/sctp_sla1.h @@ -31,28 +31,26 @@ #ifndef __SLA1_h__ #define __SLA1_h__ -#ifdef __cplusplus -extern "C" { -#endif +struct SLA_1_Context { + unsigned int A; + unsigned int B; + unsigned int C; + unsigned int D; + unsigned int E; + unsigned int H0; + unsigned int H1; + unsigned int H2; + unsigned int H3; + unsigned int H4; + unsigned int words[80]; + unsigned int TEMP; + + /* block I am collecting to process */ + char SLAblock[64]; -struct SLA_1_Context{ - unsigned int A; - unsigned int B; - unsigned int C; - unsigned int D; - unsigned int E; - unsigned int H0; - unsigned int H1; - unsigned int H2; - unsigned int H3; - unsigned int H4; - unsigned int words[80]; - unsigned int TEMP; - /* block I am collecting to process */ - char SLAblock[64]; - /* collected so far */ - int howManyInBlock; - unsigned int runningTotal; + /* collected so far */ + int howManyInBlock; + unsigned int runningTotal; }; @@ -61,7 +59,7 @@ struct SLA_1_Context{ #define F3(B,C,D) ((B & C) | (B & D) | (C & D)) /* 40 <= t <= 59 */ #define F4(B,C,D) (B ^ C ^ D) /*600 <= t <= 79 */ /* circular shift */ - + #define CSHIFT(A,B) ((B << A) | (B >> (32-A))) #define K1 0x5a827999 /* 0 <= t <= 19 */ @@ -79,9 +77,4 @@ extern void SLA1_Init(struct SLA_1_Context *); extern void SLA1_Process(struct SLA_1_Context *, const unsigned char *, int); extern void SLA1_Final(struct SLA_1_Context *, unsigned char *); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/include/net/sctp/sctp_sm.h b/include/net/sctp/sctp_sm.h index 037147e03c2a..2d1ac5826c89 100644 --- a/include/net/sctp/sctp_sm.h +++ b/include/net/sctp/sctp_sm.h @@ -52,7 +52,6 @@ */ -#include #include #include #include @@ -91,11 +90,11 @@ typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, sctp_cmd_seq_t *); typedef void (sctp_timer_event_t) (unsigned long); typedef struct { - sctp_state_fn_t *fn; - char *name; + sctp_state_fn_t *fn; + char *name; } sctp_sm_table_entry_t; -/* A naming convention of "sctp_sf_xxx" applies to all the state functions +/* A naming convention of "sctp_sf_xxx" applies to all the state functions * currently in use. */ @@ -113,7 +112,7 @@ sctp_state_fn_t sctp_sf_cookie_echoed_abort; sctp_state_fn_t sctp_sf_do_5_1B_init; sctp_state_fn_t sctp_sf_do_5_1C_ack; sctp_state_fn_t sctp_sf_do_5_1D_ce; -sctp_state_fn_t sctp_sf_do_5_1E_ca ; +sctp_state_fn_t sctp_sf_do_5_1E_ca; sctp_state_fn_t sctp_sf_do_4_C; sctp_state_fn_t sctp_sf_eat_data_6_2; sctp_state_fn_t sctp_sf_eat_data_fast_4_4; @@ -162,10 +161,10 @@ sctp_state_fn_t sctp_sf_do_6_2_sack; sctp_state_fn_t sctp_sf_autoclose_timer_expire; -/* These are state functions which are either obsolete or not in use yet. +/* These are state functions which are either obsolete or not in use yet. * If any of these functions needs to be revived, it should be renamed with * the "sctp_sf_xxx" prefix, and be moved to the above prototype groups. - */ + */ /* Prototypes for chunk state functions. Not in use. */ sctp_state_fn_t sctp_sf_do_5_2_6_stale; @@ -189,7 +188,7 @@ sctp_state_fn_t sctp_addip_do_asconf; sctp_state_fn_t sctp_addip_do_asconf_ack; /* Prototypes for utility support functions. */ -uint8_t sctp_get_chunk_type(sctp_chunk_t *chunk); +__u8 sctp_get_chunk_type(sctp_chunk_t *chunk); sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, sctp_state_t state, sctp_subtype_t event_subtype); @@ -198,13 +197,11 @@ time_t timeval_sub(struct timeval *, struct timeval *); sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *, sctp_chunk_t *, const int priority); -uint32_t sctp_generate_verification_tag(void); +__u32 sctp_generate_verification_tag(void); sctpParam_t sctp_get_my_addrs_raw(const sctp_association_t *, const int priority, int *addrs_len); -void sctp_populate_tie_tags(uint8_t *cookie, uint32_t curTag, uint32_t hisTag); - - +void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ sctp_chunk_t *sctp_make_init(const sctp_association_t *, @@ -218,36 +215,36 @@ sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, const sctp_chunk_t *); sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, - const uint32_t lowest_tsn, + const __u32 lowest_tsn, const sctp_chunk_t *); sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, const struct sctp_sndrcvinfo *sinfo, - int len, const uint8_t *data, - uint8_t flags, uint16_t ssn); + int len, const __u8 *data, + __u8 flags, __u16 ssn); sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, const struct sctp_sndrcvinfo *sinfo, - int len, const uint8_t flags, - uint16_t ssn); + int len, const __u8 flags, + __u16 ssn); sctp_chunk_t *sctp_make_data(sctp_association_t *, const struct sctp_sndrcvinfo *sinfo, - int len, const uint8_t *data); + int len, const __u8 *data); sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, const struct sctp_sndrcvinfo *, int len); sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, - const uint32_t); + const __u32); sctp_chunk_t *sctp_make_sack(const sctp_association_t *); sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, const sctp_chunk_t *); sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, const sctp_chunk_t *); -void sctp_init_cause(sctp_chunk_t *, uint16_t cause, const void *, size_t); +void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); sctp_chunk_t *sctp_make_abort(const sctp_association_t *, const sctp_chunk_t *, const size_t hint); sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, const sctp_chunk_t *, - uint32_t tsn); + __u32 tsn); sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, const sctp_transport_t *, const void *payload, @@ -258,7 +255,7 @@ sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, const size_t paylen); sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, const sctp_chunk_t *chunk, - uint16_t cause_code, + __u16 cause_code, const void *payload, size_t paylen); void sctp_chunk_assign_tsn(sctp_chunk_t *); @@ -305,20 +302,20 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); sctp_cookie_param_t * sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, const sctp_chunk_t *, int *cookie_len, - const uint8_t *, int addrs_len); -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, + const __u8 *, int addrs_len); +sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, const sctp_association_t *, sctp_chunk_t *, int priority, int *err); int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, struct sockaddr_storage*, int); /* 3rd level prototypes */ -uint32_t sctp_generate_tag(const sctp_endpoint_t *); -uint32_t sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const sctp_endpoint_t *); +__u32 sctp_generate_tsn(const sctp_endpoint_t *); /* 4th level prototypes */ void sctp_param2sockaddr(sockaddr_storage_t *addr, const sctpParam_t param, - uint16_t port); + __u16 port); int sctp_addr2sockaddr(const sctpParam_t, sockaddr_storage_t *); int sockaddr2sctp_addr(const sockaddr_storage_t *, sctpParam_t); @@ -336,17 +333,15 @@ extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; /* Get the size of a DATA chunk payload. */ -static inline uint16_t -sctp_data_size(sctp_chunk_t *chunk) +static inline __u16 sctp_data_size(sctp_chunk_t *chunk) { - uint16_t size; + __u16 size; size = ntohs(chunk->chunk_hdr->length); size -= sizeof(sctp_data_chunk_t); - return(size); - -} /* sctp_data_size( ) */ + return size; +} /* Compare two TSNs */ @@ -366,12 +361,12 @@ sctp_data_size(sctp_chunk_t *chunk) * s2, and * * (i1 < i2 and i2 - i1 > 2^(SERIAL_BITS - 1)) or - * (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1)) + * (i1 > i2 and i1 - i2 < 2^(SERIAL_BITS - 1)) */ /* * RFC 2960 - * 1.6 Serial Number Arithmetic + * 1.6 Serial Number Arithmetic * * Comparisons and arithmetic on TSNs in this document SHOULD use Serial * Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32. @@ -381,14 +376,12 @@ enum { TSN_SIGN_BIT = (1<<31) }; -static inline int -TSN_lt(__u32 s, __u32 t) +static inline int TSN_lt(__u32 s, __u32 t) { return (((s) - (t)) & TSN_SIGN_BIT); } -static inline int -TSN_lte(__u32 s, __u32 t) +static inline int TSN_lte(__u32 s, __u32 t) { return (((s) == (t)) || (((s) - (t)) & TSN_SIGN_BIT)); } @@ -397,37 +390,31 @@ TSN_lte(__u32 s, __u32 t) /* * RFC 2960 - * 1.6 Serial Number Arithmetic + * 1.6 Serial Number Arithmetic * - * Comparisons and arithmetic on Stream Sequence Numbers in this document - * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where + * Comparisons and arithmetic on Stream Sequence Numbers in this document + * SHOULD use Serial Number Arithmetic as defined in [RFC1982] where * SERIAL_BITS = 16. */ enum { SSN_SIGN_BIT = (1<<15) }; -static inline int -SSN_lt(__u16 s, __u16 t) +static inline int SSN_lt(__u16 s, __u16 t) { return (((s) - (t)) & SSN_SIGN_BIT); } -static inline int -SSN_lte(__u16 s, __u16 t) +static inline int SSN_lte(__u16 s, __u16 t) { return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); } /* Run sctp_add_cmd() generating a BUG() if there is a failure. */ -static inline void -sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) { - if (unlikely(!sctp_add_cmd(seq, verb, obj))) { + if (unlikely(!sctp_add_cmd(seq, verb, obj))) BUG(); - } - -} /* sctp_add_cmd_sf() */ - +} #endif /* __sctp_sm_h__ */ diff --git a/include/net/sctp/sctp_structs.h b/include/net/sctp/sctp_structs.h index 12a92f1a732b..aa44b8da165f 100644 --- a/include/net/sctp/sctp_structs.h +++ b/include/net/sctp/sctp_structs.h @@ -63,14 +63,14 @@ #include /* We need sctp* header structs. */ /* - * This is (almost) a direct quote from RFC 2553. + * This is (almost) a direct quote from RFC 2553. */ /* * Desired design of maximum size and alignment */ #define _SS_MAXSIZE 128 /* Implementation specific max size */ -#define _SS_ALIGNSIZE (sizeof (int64_t)) +#define _SS_ALIGNSIZE (sizeof (__s64)) /* Implementation specific desired alignment */ /* * Definitions used for sockaddr_storage structure paddings design. @@ -80,23 +80,23 @@ _SS_PAD1SIZE + _SS_ALIGNSIZE)) struct sockaddr_storage { - sa_family_t __ss_family; /* address family */ - /* Following fields are implementation specific */ - char __ss_pad1[_SS_PAD1SIZE]; - /* 6 byte pad, to make implementation */ - /* specific pad up to alignment field that */ - /* follows explicit in the data structure */ - int64_t __ss_align; /* field to force desired structure */ - /* storage alignment */ - char __ss_pad2[_SS_PAD2SIZE]; + sa_family_t __ss_family; /* address family */ + /* Following fields are implementation specific */ + char __ss_pad1[_SS_PAD1SIZE]; + /* 6 byte pad, to make implementation */ + /* specific pad up to alignment field that */ + /* follows explicit in the data structure */ + __s64 __ss_align; /* field to force desired structure */ + /* storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; /* 112 byte pad to achieve desired size, */ /* _SS_MAXSIZE value minus size of ss_family */ /* __ss_pad1, __ss_align fields is 112 */ }; -/* A convenience structure for handling sockaddr structures. +/* A convenience structure for handling sockaddr structures. * We should wean ourselves off this. - */ + */ typedef union { struct sockaddr_in v4; struct sockaddr_in6 v6; @@ -128,9 +128,9 @@ typedef struct SCTP_inqueue sctp_inqueue_t; typedef struct SCTP_outqueue sctp_outqueue_t; typedef struct SCTP_bind_addr sctp_bind_addr_t; typedef struct sctp_opt sctp_opt_t; -typedef struct sctp_endpoint_common sctp_endpoint_common_t; +typedef struct sctp_endpoint_common sctp_endpoint_common_t; -#include +#include #include #include @@ -150,8 +150,7 @@ typedef struct sctp_bind_hashbucket { struct sctp_bind_bucket *chain; } sctp_bind_hashbucket_t; -/* Used for hashing all associations. - */ +/* Used for hashing all associations. */ typedef struct sctp_hashbucket { rwlock_t lock; sctp_endpoint_common_t *chain; @@ -159,23 +158,23 @@ typedef struct sctp_hashbucket { /* The SCTP protocol structure. */ -struct SCTP_protocol { +struct SCTP_protocol { /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values - * - * The following protocol parameters are RECOMMENDED: - * - * RTO.Initial - 3 seconds - * RTO.Min - 1 second - * RTO.Max - 60 seconds - * RTO.Alpha - 1/8 (3 when converted to right shifts.) - * RTO.Beta - 1/4 (2 when converted to right shifts.) - */ - uint32_t rto_initial; - uint32_t rto_min; - uint32_t rto_max; + * + * The following protocol parameters are RECOMMENDED: + * + * RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 (3 when converted to right shifts.) + * RTO.Beta - 1/4 (2 when converted to right shifts.) + */ + __u32 rto_initial; + __u32 rto_min; + __u32 rto_max; - /* Note: rto_alpha and rto_beta are really defined as inverse - * powers of two to facilitate integer operations. + /* Note: rto_alpha and rto_beta are really defined as inverse + * powers of two to facilitate integer operations. */ int rto_alpha; int rto_beta; @@ -183,36 +182,32 @@ struct SCTP_protocol { /* Max.Burst - 4 */ int max_burst; - /* Valid.Cookie.Life - 60 seconds - */ - int valid_cookie_life; + /* Valid.Cookie.Life - 60 seconds */ + int valid_cookie_life; - /* Association.Max.Retrans - 10 attempts - * Path.Max.Retrans - 5 attempts (per destination address) - * Max.Init.Retransmits - 8 attempts - */ + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ int max_retrans_association; int max_retrans_path; int max_retrans_init; - /* HB.interval - 30 seconds - */ - int hb_interval; + /* HB.interval - 30 seconds */ + int hb_interval; - /* - * The following variables are implementation specific. - */ + /* The following variables are implementation specific. */ /* Default initialization values to be applied to new associations. */ - uint16_t max_instreams; - uint16_t max_outstreams; - - /* This is a list of groups of functions for each address - * family that we support. - */ + __u16 max_instreams; + __u16 max_outstreams; + + /* This is a list of groups of functions for each address + * family that we support. + */ list_t address_families; - /* This is the hash of all endpoints. */ + /* This is the hash of all endpoints. */ int ep_hashsize; sctp_hashbucket_t *ep_hashbucket; @@ -234,8 +229,7 @@ struct SCTP_protocol { */ list_t local_addr_list; spinlock_t local_addr_lock; - -}; /* struct SCTP_protocol */ +}; /* @@ -244,18 +238,18 @@ struct SCTP_protocol { */ typedef struct sctp_func { int (*queue_xmit) (struct sk_buff *skb); - int (*setsockopt) (struct sock *sk, - int level, - int optname, - char *optval, + int (*setsockopt) (struct sock *sk, + int level, + int optname, + char *optval, int optlen); - int (*getsockopt) (struct sock *sk, - int level, - int optname, - char *optval, + int (*getsockopt) (struct sock *sk, + int level, + int optname, + char *optval, int *optlen); int (*get_dst_mtu) (const sockaddr_storage_t *address); - uint16_t net_header_len; + __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; list_t list; @@ -265,31 +259,30 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); /* SCTP Socket type: UDP or TCP style. */ typedef enum { - SCTP_SOCKET_UDP = 0, + SCTP_SOCKET_UDP = 0, SCTP_SOCKET_UDP_HIGH_BANDWIDTH, SCTP_SOCKET_TCP } sctp_socket_type_t; /* Per socket SCTP information. */ struct sctp_opt { - /* What kind of a socket is this? */ - sctp_socket_type_t type; + /* What kind of a socket is this? */ + sctp_socket_type_t type; - /* What is our base endpointer? */ - sctp_endpoint_t *ep; + /* What is our base endpointer? */ + sctp_endpoint_t *ep; /* Various Socket Options. */ - uint16_t default_stream; - uint32_t default_ppid; + __u16 default_stream; + __u32 default_ppid; struct sctp_initmsg initmsg; struct sctp_rtoinfo rtoinfo; struct sctp_paddrparams paddrparam; struct sctp_event_subscribe subscribe; - uint32_t autoclose; - uint8_t nodelay; - uint8_t disable_fragments; - -}; /* struct sctp_opt */ + __u32 autoclose; + __u8 nodelay; + __u8 disable_fragments; +}; @@ -299,82 +292,82 @@ struct sctp_opt { /* These are the parts of an association which we send in the cookie. * Most of these are straight out of: * RFC2960 12.2 Parameters necessary per association (i.e. the TCB) - * + * */ typedef struct sctp_cookie { /* My : Tag expected in every inbound packet and sent * Verification: in the INIT or INIT ACK chunk. - * Tag : + * Tag : */ - uint32_t my_vtag; + __u32 my_vtag; /* Peer's : Tag expected in every outbound packet except * Verification: in the INIT chunk. - * Tag : + * Tag : */ - uint32_t peer_vtag; - + __u32 peer_vtag; + /* The rest of these are not from the spec, but really need to * be in the cookie. */ /* My Tie Tag : Assist in discovering a restarting association. */ - uint32_t my_ttag; + __u32 my_ttag; /* Peer's Tie Tag: Assist in discovering a restarting association. */ - uint32_t peer_ttag; - + __u32 peer_ttag; + /* When does this cookie expire? */ struct timeval expiration; - /* Number of inbound/outbound streams which are set + /* Number of inbound/outbound streams which are set * and negotiated during the INIT process. */ - uint16_t sinit_num_ostreams; - uint16_t sinit_max_instreams; + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; /* This is the first sequence number I used. */ - uint32_t initial_tsn; + __u32 initial_tsn; /* This holds the originating address of the INIT packet. */ sockaddr_storage_t peer_addr; - - /* This is a shim for my peer's INIT packet, followed by - * a copy of the raw address list of the association. - * The length of the raw address list is saved in the + + /* This is a shim for my peer's INIT packet, followed by + * a copy of the raw address list of the association. + * The length of the raw address list is saved in the * raw_addr_list_len field, which will be used at the time when - * the association TCB is re-constructed from the cookie. + * the association TCB is re-constructed from the cookie. */ - uint32_t raw_addr_list_len; - sctp_init_chunk_t peer_init[0]; -} sctp_cookie_t; + __u32 raw_addr_list_len; + sctp_init_chunk_t peer_init[0]; +} sctp_cookie_t; /* The format of our cookie that we send to our peer. */ typedef struct sctp_signed_cookie { - uint8_t signature[SCTP_SECRET_SIZE]; - sctp_cookie_t c; -} sctp_signed_cookie_t ; + __u8 signature[SCTP_SECRET_SIZE]; + sctp_cookie_t c; +} sctp_signed_cookie_t; /* This convenience type allows us to avoid casting when walking * through a parameter list. */ typedef union { - uint8_t *v; - sctp_paramhdr_t *p; - - sctp_cookie_preserve_param_t *bht; - sctp_hostname_param_t *dns; - sctp_cookie_param_t *cookie; - sctp_supported_addrs_param_t *sat; - sctp_ipv4addr_param_t *v4; - sctp_ipv6addr_param_t *v6; + __u8 *v; + sctp_paramhdr_t *p; + + sctp_cookie_preserve_param_t *bht; + sctp_hostname_param_t *dns; + sctp_cookie_param_t *cookie; + sctp_supported_addrs_param_t *sat; + sctp_ipv4addr_param_t *v4; + sctp_ipv6addr_param_t *v6; } sctpParam_t; /* This is another convenience type to allocate memory for address - * params for the maximum size and pass such structures around + * params for the maximum size and pass such structures around * internally. */ typedef union { @@ -394,11 +387,9 @@ typedef struct sctp_sender_hb_info { sockaddr_storage_t daddr; unsigned long sent_at; } sctp_sender_hb_info_t __attribute__((packed)); - - /* RFC2960 1.4 Key Terms - * + * * o Chunk: A unit of information within an SCTP packet, consisting of * a chunk header and chunk-specific content. * @@ -406,16 +397,16 @@ typedef struct sctp_sender_hb_info { * each chunk as well as a few other header pointers... */ struct SCTP_chunk { - /* These first three elements MUST PRECISELY match the first - * three elements of struct sk_buff. This allows us to reuse - * all the skb_* queue management functions. - */ - sctp_chunk_t *next; - sctp_chunk_t *prev; - struct sk_buff_head *list; + /* These first three elements MUST PRECISELY match the first + * three elements of struct sk_buff. This allows us to reuse + * all the skb_* queue management functions. + */ + sctp_chunk_t *next; + sctp_chunk_t *prev; + struct sk_buff_head *list; - /* This is our link to the per-transport transmitted list. */ - struct list_head transmitted_list; + /* This is our link to the per-transport transmitted list. */ + struct list_head transmitted_list; /* This field is used by chunks that hold fragmented data. * For the first fragment this is the list that holds the rest of @@ -425,58 +416,58 @@ struct SCTP_chunk { struct list_head frag_list; /* This points to the sk_buff containing the actual data. */ - struct sk_buff *skb; + struct sk_buff *skb; - /* These are the SCTP headers by reverse order in a packet. + /* These are the SCTP headers by reverse order in a packet. * Note that some of these may happen more than once. In that * case, we point at the "current" one, whatever that means * for that level of header. */ - - /* We point this at the FIRST TLV parameter to chunk_hdr. */ - sctpParam_t param_hdr; - union { - uint8_t *v; - sctp_datahdr_t *data_hdr; - sctp_inithdr_t *init_hdr; - sctp_sackhdr_t *sack_hdr; + + /* We point this at the FIRST TLV parameter to chunk_hdr. */ + sctpParam_t param_hdr; + union { + __u8 *v; + sctp_datahdr_t *data_hdr; + sctp_inithdr_t *init_hdr; + sctp_sackhdr_t *sack_hdr; sctp_heartbeathdr_t *hb_hdr; sctp_sender_hb_info_t *hbs_hdr; - sctp_shutdownhdr_t *shutdown_hdr; + sctp_shutdownhdr_t *shutdown_hdr; sctp_signed_cookie_t *cookie_hdr; sctp_ecnehdr_t *ecne_hdr; - sctp_cwrhdr_t *ecn_cwr_hdr; + sctp_cwrhdr_t *ecn_cwr_hdr; sctp_errhdr_t *err_hdr; - } subh; - - uint8_t *chunk_end; - + } subh; + + __u8 *chunk_end; + sctp_chunkhdr_t *chunk_hdr; - - sctp_sctphdr_t *sctp_hdr; + + sctp_sctphdr_t *sctp_hdr; /* This needs to be recoverable for SCTP_SEND_FAILED events. */ struct sctp_sndrcvinfo sinfo; /* Which association does this belong to? */ - sctp_association_t *asoc; + sctp_association_t *asoc; /* What endpoint received this chunk? */ sctp_endpoint_common_t *rcvr; - /* We fill this in if we are calculating RTT. */ - unsigned long sent_at; - - uint8_t rtt_in_progress; /* Is this chunk used for RTT calculation? */ - uint8_t num_times_sent; /* How man times did we send this? */ - uint8_t has_tsn; /* Does this chunk have a TSN yet? */ - uint8_t singleton; /* Was this the only chunk in the packet? */ - uint8_t end_of_packet; /* Was this the last chunk in the packet? */ - uint8_t ecn_ce_done; /* Have we processed the ECN CE bit? */ - uint8_t pdiscard; /* Discard the whole packet now? */ - uint8_t tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ - uint8_t fast_retransmit; /* Is this chunk fast retransmitted? */ - uint8_t tsn_missing_report; /* Data chunk missing counter. */ + /* We fill this in if we are calculating RTT. */ + unsigned long sent_at; + + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ + __u8 num_times_sent; /* How man times did we send this? */ + __u8 has_tsn; /* Does this chunk have a TSN yet? */ + __u8 singleton; /* Was this the only chunk in the packet? */ + __u8 end_of_packet; /* Was this the last chunk in the packet? */ + __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ + __u8 pdiscard; /* Discard the whole packet now? */ + __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __u8 tsn_missing_report; /* Data chunk missing counter. */ /* What is the origin IP address for this chunk? */ sockaddr_storage_t source; @@ -486,10 +477,10 @@ struct SCTP_chunk { * go. It is NULL if we have no preference. */ sctp_transport_t *transport; -}; /* struct SCTP_chunk */ - -sctp_chunk_t *sctp_make_chunk(const sctp_association_t *, uint8_t type, - uint8_t flags, int size); +}; + +sctp_chunk_t *sctp_make_chunk(const sctp_association_t *, __u8 type, + __u8 flags, int size); void sctp_free_chunk(sctp_chunk_t *); sctp_chunk_t *sctp_copy_chunk(sctp_chunk_t *, int flags); void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); @@ -506,8 +497,8 @@ const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk); */ struct sockaddr_storage_list { list_t list; - sockaddr_storage_t a; -}; /* struct sockaddr_storage_list */ + sockaddr_storage_t a; +}; typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); @@ -516,48 +507,47 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); */ struct SCTP_packet { /* These are the SCTP header values (host order) for the packet. */ - uint16_t source_port; - uint16_t destination_port; - uint32_t vtag; - + __u16 source_port; + __u16 destination_port; + __u32 vtag; + /* This contains the payload chunks. */ struct sk_buff_head chunks; /* This is the total size of all chunks INCLUDING padding. */ size_t size; - /* The packet is destined for this transport address. - * The function we finally use to pass down to the next lower - * layer lives in the transport structure. - */ - sctp_transport_t *transport; - - /* Allow a callback for getting a high priority chunk - * bundled early into the packet (This is used for ECNE). - */ + /* The packet is destined for this transport address. + * The function we finally use to pass down to the next lower + * layer lives in the transport structure. + */ + sctp_transport_t *transport; + + /* Allow a callback for getting a high priority chunk + * bundled early into the packet (This is used for ECNE). + */ sctp_packet_phandler_t *get_prepend_chunk; /* This packet should advertise ECN capability to the network * via the ECT bit. */ int ecn_capable; - + /* This packet contains a COOKIE-ECHO chunk. */ int has_cookie_echo; int malloced; - -}; /* struct SCTP_packet */ +}; typedef int (sctp_outqueue_thandler_t)(sctp_outqueue_t *, void *); typedef int (sctp_outqueue_ehandler_t)(sctp_outqueue_t *); typedef sctp_packet_t *(sctp_outqueue_ohandler_init_t) (sctp_packet_t *, sctp_transport_t *, - uint16_t sport, - uint16_t dport); + __u16 sport, + __u16 dport); typedef sctp_packet_t *(sctp_outqueue_ohandler_config_t) (sctp_packet_t *, - uint32_t vtag, + __u32 vtag, int ecn_capable, sctp_packet_phandler_t *get_prepend_chunk); typedef sctp_xmit_t (sctp_outqueue_ohandler_t)(sctp_packet_t *, @@ -570,13 +560,13 @@ sctp_outqueue_ohandler_t sctp_packet_append_chunk; sctp_outqueue_ohandler_t sctp_packet_transmit_chunk; sctp_outqueue_ohandler_force_t sctp_packet_transmit; void sctp_packet_free(sctp_packet_t *); - + /* This represents a remote transport address. * For local transport addresses, we just use sockaddr_storage_t. * * RFC2960 Section 1.4 Key Terms - * + * * o Transport address: A Transport Address is traditionally defined * by Network Layer address, Transport Layer protocol and Transport * Layer port number. In the case of SCTP running over IP, a @@ -602,32 +592,32 @@ struct SCTP_transport { /* This is the peer's IP address and port. */ sockaddr_storage_t ipaddr; - - /* These are the functions we call to handle LLP stuff. */ + + /* These are the functions we call to handle LLP stuff. */ sctp_func_t *af_specific; - /* Which association do we belong to? */ - sctp_association_t *asoc; + /* Which association do we belong to? */ + sctp_association_t *asoc; /* RFC2960 * - * 12.3 Per Transport Address Data - * - * For each destination transport address in the peer's - * address list derived from the INIT or INIT ACK chunk, a - * number of data elements needs to be maintained including: - */ - uint32_t rtt; /* This is the most recent RTT. */ - - /* RTO : The current retransmission timeout value. */ - uint32_t rto; - - /* RTTVAR : The current RTT variation. */ - uint32_t rttvar; - - /* SRTT : The current smoothed round trip time. */ - uint32_t srtt; - + * 12.3 Per Transport Address Data + * + * For each destination transport address in the peer's + * address list derived from the INIT or INIT ACK chunk, a + * number of data elements needs to be maintained including: + */ + __u32 rtt; /* This is the most recent RTT. */ + + /* RTO : The current retransmission timeout value. */ + __u32 rto; + + /* RTTVAR : The current RTT variation. */ + __u32 rttvar; + + /* SRTT : The current smoothed round trip time. */ + __u32 srtt; + /* RTO-Pending : A flag used to track if one of the DATA * chunks sent to this address is currently being * used to compute a RTT. If this flag is 0, @@ -637,49 +627,49 @@ struct SCTP_transport { * calculation completes (i.e. the DATA chunk * is SACK'd) clear this flag. */ - int rto_pending; + int rto_pending; /* - * These are the congestion stats. - */ - /* cwnd : The current congestion window. */ - uint32_t cwnd; /* This is the actual cwnd. */ - - /* ssthresh : The current slow start threshold value. */ - uint32_t ssthresh; - + * These are the congestion stats. + */ + /* cwnd : The current congestion window. */ + __u32 cwnd; /* This is the actual cwnd. */ + + /* ssthresh : The current slow start threshold value. */ + __u32 ssthresh; + /* partial : The tracking method for increase of cwnd when in - * bytes acked : congestion avoidance mode (see Section 6.2.2) - */ - uint32_t partial_bytes_acked; + * bytes acked : congestion avoidance mode (see Section 6.2.2) + */ + __u32 partial_bytes_acked; /* Data that has been sent, but not acknowledged. */ - uint32_t flight_size; - + __u32 flight_size; + /* PMTU : The current known path MTU. */ - uint32_t pmtu; - - /* When was the last time(in jiffies) that a data packet was sent on + __u32 pmtu; + + /* When was the last time(in jiffies) that a data packet was sent on * this transport? This is used to adjust the cwnd when the transport * becomes inactive. - */ + */ unsigned long last_time_used; - + /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to - * the destination address every heartbeat interval. - */ - int hb_interval; - + * the destination address every heartbeat interval. + */ + int hb_interval; + /* When was the last time (in jiffies) that we heard from this * transport? We use this to pick new active and retran paths. */ unsigned long last_time_heard; - /* Last time(in jiffies) when cwnd is reduced due to the congestion + /* Last time(in jiffies) when cwnd is reduced due to the congestion * indication based on ECNE chunk. */ - unsigned long last_time_ecne_reduced; + unsigned long last_time_ecne_reduced; /* state : The current state of this destination, * : i.e. DOWN, UP, ALLOW-HB, NO-HEARTBEAT, etc. @@ -688,44 +678,44 @@ struct SCTP_transport { int active; int hb_allowed; } state; - + /* These are the error stats for this destination. */ - - /* Error count : The current error count for this destination. */ + + /* Error count : The current error count for this destination. */ unsigned short error_count; - + /* Error : Current error threshold for this destination * Threshold : i.e. what value marks the destination down if * : errorCount reaches this value. - */ + */ unsigned short error_threshold; - /* This is the max_retrans value for the transport and will - * be initialized to proto.max_retrans.path. This can be changed + /* This is the max_retrans value for the transport and will + * be initialized to proto.max_retrans.path. This can be changed * using SCTP_SET_PEER_ADDR_PARAMS socket option. - */ + */ int max_retrans; - - /* We use this name for debugging output... */ - char *debug_name; - - /* Per : A timer used by each destination. - * Destination : - * Timer : - * - * [Everywhere else in the text this is called T3-rtx. -ed] - */ - struct timer_list T3_rtx_timer; - /* Heartbeat timer is per destination. */ - struct timer_list hb_timer; + /* We use this name for debugging output... */ + char *debug_name; + + /* Per : A timer used by each destination. + * Destination : + * Timer : + * + * [Everywhere else in the text this is called T3-rtx. -ed] + */ + struct timer_list T3_rtx_timer; + + /* Heartbeat timer is per destination. */ + struct timer_list hb_timer; /* Since we're using per-destination retransmission timers * (see above), we're also using per-destination "transmitted" * queues. This probably ought to be a private struct * accessible only within the outqueue, but it's not, yet. */ - struct list_head transmitted; + struct list_head transmitted; /* We build bundle-able packets for this transport here. */ sctp_packet_t packet; @@ -734,10 +724,10 @@ struct SCTP_transport { struct list_head send_ready; int malloced; /* Is this structure kfree()able? */ -}; /* struct SCTP_transport */ +}; extern sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *, int); -extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, +extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, const sockaddr_storage_t *, int); extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); extern void sctp_transport_free(sctp_transport_t *); @@ -745,8 +735,8 @@ extern void sctp_transport_destroy(sctp_transport_t *); extern void sctp_transport_reset_timers(sctp_transport_t *); extern void sctp_transport_hold(sctp_transport_t *); extern void sctp_transport_put(sctp_transport_t *); -extern void sctp_transport_update_rto(sctp_transport_t *, uint32_t); -extern void sctp_transport_raise_cwnd(sctp_transport_t *, uint32_t, uint32_t); +extern void sctp_transport_update_rto(sctp_transport_t *, __u32); +extern void sctp_transport_raise_cwnd(sctp_transport_t *, __u32, __u32); extern void sctp_transport_lower_cwnd(sctp_transport_t *, sctp_lower_cwnd_t); /* This is the structure we use to queue packets as they come into @@ -754,22 +744,22 @@ extern void sctp_transport_lower_cwnd(sctp_transport_t *, sctp_lower_cwnd_t); * fragment reassembly and chunk unbundling. */ struct SCTP_inqueue { - /* This is actually a queue of sctp_chunk_t each - * containing a partially decoded packet. - */ - struct sk_buff_head in; + /* This is actually a queue of sctp_chunk_t each + * containing a partially decoded packet. + */ + struct sk_buff_head in; /* This is the packet which is currently off the in queue and is * being worked on through the inbound chunk processing. */ sctp_chunk_t *in_progress; - /* This is the delayed task to finish delivering inbound - * messages. - */ - struct tq_struct immediate; + /* This is the delayed task to finish delivering inbound + * messages. + */ + struct tq_struct immediate; - int malloced; /* Is this structure kfree()able? */ -}; /* struct SCTP_inqueue */ + int malloced; /* Is this structure kfree()able? */ +}; sctp_inqueue_t *sctp_inqueue_new(void); void sctp_inqueue_init(sctp_inqueue_t *); @@ -778,7 +768,6 @@ void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet); sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *); void sctp_inqueue_set_th_handler(sctp_inqueue_t *, void (*)(void *), void *); - /* This is the structure we use to hold outbound chunks. You push * chunks in and they automatically pop out the other end as bundled @@ -786,7 +775,7 @@ void sctp_inqueue_set_th_handler(sctp_inqueue_t *, * * This structure covers sections 6.3, 6.4, 6.7, 6.8, 6.10, 7., 8.1, * and 8.2 of the v13 draft. - * + * * It handles retransmissions. The connection to the timeout portion * of the state machine is through sctp_..._timeout() and timeout_handler. * @@ -800,46 +789,46 @@ void sctp_inqueue_set_th_handler(sctp_inqueue_t *, * When free()'d, it empties itself out via output_handler(). */ struct SCTP_outqueue { - sctp_association_t *asoc; + sctp_association_t *asoc; - /* BUG: This really should be an array of streams. - * This really holds a list of chunks (one stream). + /* BUG: This really should be an array of streams. + * This really holds a list of chunks (one stream). * FIXME: If true, why so? */ - struct sk_buff_head out; + struct sk_buff_head out; /* These are control chunks we want to send. */ - struct sk_buff_head control; + struct sk_buff_head control; /* These are chunks that have been sacked but are above the - * CTSN, or cumulative tsn ack point. + * CTSN, or cumulative tsn ack point. */ - struct list_head sacked; + struct list_head sacked; /* Put chunks on this list to schedule them for * retransmission. */ - struct list_head retransmit; + struct list_head retransmit; - /* Call these functions to send chunks down to the next lower - * layer. This is always SCTP_packet, but we separate the two - * structures to make testing simpler. - */ - sctp_outqueue_ohandler_init_t *init_output; - sctp_outqueue_ohandler_config_t *config_output; - sctp_outqueue_ohandler_t *append_output; - sctp_outqueue_ohandler_t *build_output; - sctp_outqueue_ohandler_force_t *force_output; + /* Call these functions to send chunks down to the next lower + * layer. This is always SCTP_packet, but we separate the two + * structures to make testing simpler. + */ + sctp_outqueue_ohandler_init_t *init_output; + sctp_outqueue_ohandler_config_t *config_output; + sctp_outqueue_ohandler_t *append_output; + sctp_outqueue_ohandler_t *build_output; + sctp_outqueue_ohandler_force_t *force_output; - /* How many unackd bytes do we have in-flight? */ - uint32_t outstanding_bytes; + /* How many unackd bytes do we have in-flight? */ + __u32 outstanding_bytes; - /* Is this structure empty? */ - int empty; + /* Is this structure empty? */ + int empty; /* Are we kfree()able? */ - int malloced; -}; /* struct SCTP_outqueue */ + int malloced; +}; sctp_outqueue_t *sctp_outqueue_new(sctp_association_t *); void sctp_outqueue_init(sctp_association_t *, sctp_outqueue_t *); @@ -857,44 +846,44 @@ int sctp_outqueue_set_output_handlers(sctp_outqueue_t *, sctp_outqueue_ohandler_t build, sctp_outqueue_ohandler_force_t force); void sctp_outqueue_restart(sctp_outqueue_t *); -void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, uint8_t); +void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8); /* These bind address data fields common between endpoints and associations */ struct SCTP_bind_addr { - + /* RFC 2960 12.1 Parameters necessary for the SCTP instance * * SCTP Port: The local SCTP port number the endpoint is - * bound to. - */ - uint16_t port; + * bound to. + */ + __u16 port; /* RFC 2960 12.1 Parameters necessary for the SCTP instance * - * Address List: The list of IP addresses that this instance - * has bound. This information is passed to one's - * peer(s) in INIT and INIT ACK chunks. - */ + * Address List: The list of IP addresses that this instance + * has bound. This information is passed to one's + * peer(s) in INIT and INIT ACK chunks. + */ list_t address_list; - int malloced; /* Are we kfree()able? */ -}; /* struct SCTP_bind_addr */ + int malloced; /* Are we kfree()able? */ +}; sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); -void sctp_bind_addr_init(sctp_bind_addr_t *, uint16_t port); +void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); void sctp_bind_addr_free(sctp_bind_addr_t *); -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, sctp_scope_t scope, int priority,int flags); int sctp_add_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *, int priority); int sctp_del_bind_addr(sctp_bind_addr_t *, sockaddr_storage_t *); int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const sockaddr_storage_t *); -sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, +sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, int priority); -int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, - uint8_t *raw_addr_list, +int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, + __u8 *raw_addr_list, int addrs_len, unsigned short port, int priority); @@ -911,67 +900,66 @@ typedef enum { SCTP_EP_TYPE_ASSOCIATION, } sctp_endpoint_type_t; -/* - * A common base class to bridge the implmentation view of a - * socket (usually listening) endpoint versus an association's - * local endpoint. +/* + * A common base class to bridge the implmentation view of a + * socket (usually listening) endpoint versus an association's + * local endpoint. * This common structure is useful for several purposes: - * 1) Common interface for lookup routines. + * 1) Common interface for lookup routines. * a) Subfunctions work for either endpoint or association * b) Single interface to lookup allows hiding the lookup lock rather - * than acquiring it externally. - * 2) Common interface for the inbound chunk handling/state machine. - * 3) Common object handling routines for reference counting, etc. + * than acquiring it externally. + * 2) Common interface for the inbound chunk handling/state machine. + * 3) Common object handling routines for reference counting, etc. * 4) Disentangle association lookup from endpoint lookup, where we - * do not have to find our endpoint to find our association. + * do not have to find our endpoint to find our association. * */ -struct sctp_endpoint_common { +struct sctp_endpoint_common { /* Fields to help us manage our entries in the hash tables. */ sctp_endpoint_common_t *next; - sctp_endpoint_common_t **pprev; + sctp_endpoint_common_t **pprev; int hashent; - + /* Runtime type information. What kind of endpoint is this? */ sctp_endpoint_type_t type; - - /* Some fields to help us manage this object. + + /* Some fields to help us manage this object. * refcnt - Reference count access to this object. - * dead - Do not attempt to use this object. - * malloced - Do we need to kfree this object? + * dead - Do not attempt to use this object. + * malloced - Do we need to kfree this object? */ atomic_t refcnt; char dead; char malloced; /* What socket does this endpoint belong to? */ - struct sock *sk; + struct sock *sk; /* This is where we receive inbound chunks. */ sctp_inqueue_t inqueue; - /* This substructure includes the defining parameters of the + /* This substructure includes the defining parameters of the * endpoint: * bind_addr.port is our shared port number. * bind_addr.address_list is our set of local IP addresses. - * */ sctp_bind_addr_t bind_addr; /* Protection during address list comparisons. */ rwlock_t addr_lock; -}; /* sctp_endpoint_common_t */ +}; /* RFC Section 1.4 Key Terms - * + * * o SCTP endpoint: The logical sender/receiver of SCTP packets. On a * multi-homed host, an SCTP endpoint is represented to its peers as a * combination of a set of eligible destination transport addresses to * which SCTP packets can be sent and a set of eligible source * transport addresses from which SCTP packets can be received. - * All transport addresses used by an SCTP endpoint must use the + * All transport addresses used by an SCTP endpoint must use the * same port number, but can use multiple IP addresses. A transport * address used by an SCTP endpoint must not be used by another * SCTP endpoint. In other words, a transport address is unique @@ -985,57 +973,56 @@ struct sctp_endpoint_common { struct SCTP_endpoint { /* Common substructure for endpoint and association. */ - sctp_endpoint_common_t base; - - /* These are the system-wide defaults and other stuff which is - * endpoint-independent. - */ - sctp_protocol_t *proto; + sctp_endpoint_common_t base; + + /* These are the system-wide defaults and other stuff which is + * endpoint-independent. + */ + sctp_protocol_t *proto; /* Associations: A list of current associations and mappings - * to the data consumers for each association. This - * may be in the form of a hash table or other - * implementation dependent structure. The data - * consumers may be process identification - * information such as file descriptors, named pipe - * pointer, or table pointers dependent on how SCTP - * is implemented. - */ + * to the data consumers for each association. This + * may be in the form of a hash table or other + * implementation dependent structure. The data + * consumers may be process identification + * information such as file descriptors, named pipe + * pointer, or table pointers dependent on how SCTP + * is implemented. + */ /* This is really a list of sctp_association_t entries. */ list_t asocs; /* Secret Key: A secret key used by this endpoint to compute - * the MAC. This SHOULD be a cryptographic quality - * random number with a sufficient length. - * Discussion in [RFC1750] can be helpful in - * selection of the key. - */ - uint8_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; - int current_key; - int last_key; - int key_changed_at; + * the MAC. This SHOULD be a cryptographic quality + * random number with a sufficient length. + * Discussion in [RFC1750] can be helpful in + * selection of the key. + */ + __u8 secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; + int current_key; + int last_key; + int key_changed_at; - /* Default timeouts. */ - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + /* Default timeouts. */ + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; - /* Various thresholds. */ + /* Various thresholds. */ - /* Name for debugging output... */ - char *debug_name; -}; /* sctp_endpoint_t */ + /* Name for debugging output... */ + char *debug_name; +}; /* Recover the outter endpoint structure. */ -static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t* base) -{ +static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) +{ sctp_endpoint_t *ep; - + /* We are not really a list, but the list_entry() macro is - * really quite generic to find the address of an outter struct. + * really quite generic to find the address of an outter struct. */ ep = list_entry(base, sctp_endpoint_t, base); return ep; - -} /* sctp_ep() */ +} /* These are function signatures for manipulating endpoints. */ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *, struct sock *, int); @@ -1048,39 +1035,39 @@ void sctp_endpoint_add_asoc(sctp_endpoint_t *, sctp_association_t *asoc); sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, const sockaddr_storage_t *paddr, sctp_transport_t **); -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, - const sockaddr_storage_t *); +sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, + const sockaddr_storage_t *); void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, const sockaddr_storage_t *peer_addr, sctp_init_chunk_t *peer_init, int priority); int sctp_process_param(sctp_association_t *asoc, - sctpParam_t param, + sctpParam_t param, const sockaddr_storage_t *peer_addr, sctp_cid_t cid, int priority); -uint32_t sctp_generate_tag(const sctp_endpoint_t *ep); -uint32_t sctp_generate_tsn(const sctp_endpoint_t *ep); +__u32 sctp_generate_tag(const sctp_endpoint_t *ep); +__u32 sctp_generate_tsn(const sctp_endpoint_t *ep); /* RFC2960 - * + * * 12. Recommended Transmission Control Block (TCB) Parameters - * + * * This section details a recommended set of parameters that should * be contained within the TCB for an implementation. This section is * for illustrative purposes and should not be deemed as requirements * on an implementation or as an exhaustive list of all parameters * inside an SCTP TCB. Each implementation may need its own additional - * parameters for optimization. + * parameters for optimization. */ /* Here we have information about each individual association. */ struct SCTP_association { - - /* A base structure common to endpoint and association. + + /* A base structure common to endpoint and association. * In this context, it represents the associations's view - * of the local endpoint of the association. + * of the local endpoint of the association. */ sctp_endpoint_common_t base; @@ -1091,21 +1078,21 @@ struct SCTP_association { * sctp_association_t data structure. Used for mapping an * association id to an association. */ - uint32_t eyecatcher; + __u32 eyecatcher; - /* This is our parent endpoint. */ - sctp_endpoint_t *ep; + /* This is our parent endpoint. */ + sctp_endpoint_t *ep; - /* These are those association elements needed in the cookie. */ - sctp_cookie_t c; + /* These are those association elements needed in the cookie. */ + sctp_cookie_t c; /* This is all information about our peer. */ struct { - /* rwnd + /* rwnd * * Peer Rwnd : Current calculated value of the peer's rwnd. */ - uint32_t rwnd; + __u32 rwnd; /* transport_addr_list * @@ -1115,7 +1102,7 @@ struct SCTP_association { * List : associate an inbound packet with a given * : association. Normally this information is * : hashed or keyed for quick lookup and access - * : of the TCB. + * : of the TCB. * * It is a list of SCTP_transport's. */ @@ -1124,14 +1111,14 @@ struct SCTP_association { /* port * The transport layer port number. */ - uint16_t port; - + __u16 port; + /* primary_path * * Primary : This is the current primary destination * Path : transport address of the peer endpoint. It - * : may also specify a source transport address - * : on this endpoint. + * : may also specify a source transport address + * : on this endpoint. * * All of these paths live on transport_addr_list. * @@ -1142,9 +1129,9 @@ struct SCTP_association { * transmit new data and most control chunks. */ sctp_transport_t *primary_path; - + /* active_path - * The path that we are currently using to + * The path that we are currently using to * transmit new data and most control chunks. */ sctp_transport_t *active_path; @@ -1163,7 +1150,7 @@ struct SCTP_association { /* Pointer to last transport I have sent on. */ sctp_transport_t *last_sent_to; - + /* This is the last transport I have recieved DATA on. */ sctp_transport_t *last_data_from; @@ -1179,19 +1166,19 @@ struct SCTP_association { * TSN : sequence. This value is set initially by * : taking the peer's Initial TSN, received in * : the INIT or INIT ACK chunk, and subtracting - * : one from it. + * : one from it. * * Throughout most of the specification this is called the * "Cumulative TSN ACK Point". In this case, we * ignore the advice in 12.2 in favour of the term * used in the bulk of the text. This value is hidden - * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). + * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). */ sctp_tsnmap_t tsn_map; - uint8_t _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; + __u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; /* We record duplicate TSNs here. We clear this after - * every SACK. + * every SACK. * FIXME: We should move this into the tsnmap? --jgrimm */ sctp_dup_tsn_t dup_tsns[SCTP_MAX_DUP_TSNS]; @@ -1199,61 +1186,61 @@ struct SCTP_association { /* Do we need to sack the peer? */ int sack_needed; - - /* These are capabilities which our peer advertised. */ - uint8_t ecn_capable; /* Can peer do ECN? */ - uint8_t ipv4_address; /* Peer understands IPv4 addresses? */ - uint8_t ipv6_address; /* Peer understands IPv6 addresses? */ - uint8_t hostname_address;/* Peer understands DNS addresses? */ + + /* These are capabilities which our peer advertised. */ + __u8 ecn_capable; /* Can peer do ECN? */ + __u8 ipv4_address; /* Peer understands IPv4 addresses? */ + __u8 ipv6_address; /* Peer understands IPv6 addresses? */ + __u8 hostname_address;/* Peer understands DNS addresses? */ sctp_inithdr_t i; int cookie_len; void *cookie; /* ADDIP Extention (ADDIP) --xguo */ /* minus 1 (ADDIP sec. 4.2 C1) */ - uint32_t addip_serial; + __u32 addip_serial; } peer; - /* State : A state variable indicating what state the - * : association is in, i.e. COOKIE-WAIT, - * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, - * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. - * - * Note: No "CLOSED" state is illustrated since if a - * association is "CLOSED" its TCB SHOULD be removed. - * - * In this implementation we DO have a CLOSED - * state which is used during initiation and shutdown. - * - * State takes values from SCTP_STATE_*. - */ - sctp_state_t state; + /* State : A state variable indicating what state the + * : association is in, i.e. COOKIE-WAIT, + * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, + * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. + * + * Note: No "CLOSED" state is illustrated since if a + * association is "CLOSED" its TCB SHOULD be removed. + * + * In this implementation we DO have a CLOSED + * state which is used during initiation and shutdown. + * + * State takes values from SCTP_STATE_*. + */ + sctp_state_t state; - /* When did we enter this state? */ - int state_timestamp; - - /* The cookie life I award for any cookie. */ - struct timeval cookie_life; - uint32_t cookie_preserve; + /* When did we enter this state? */ + int state_timestamp; - /* Overall : The overall association error count. - * Error Count : [Clear this any time I get something.] - */ - int overall_error_count; - - /* Overall : The threshold for this association that if - * Error : the Overall Error Count reaches will cause - * Threshold : this association to be torn down. - */ - int overall_error_threshold; + /* The cookie life I award for any cookie. */ + struct timeval cookie_life; + __u32 cookie_preserve; + + /* Overall : The overall association error count. + * Error Count : [Clear this any time I get something.] + */ + int overall_error_count; + + /* Overall : The threshold for this association that if + * Error : the Overall Error Count reaches will cause + * Threshold : this association to be torn down. + */ + int overall_error_threshold; /* These are the association's initial, max, and min RTO values. * These values will be initialized by system defaults, but can - * be modified via the SCTP_RTOINFO socket option. - */ - uint32_t rto_initial; - uint32_t rto_max; - uint32_t rto_min; + * be modified via the SCTP_RTOINFO socket option. + */ + __u32 rto_initial; + __u32 rto_max; + __u32 rto_min; /* Maximum number of new data packets that can be sent in a burst. */ int max_burst; @@ -1261,35 +1248,35 @@ struct SCTP_association { /* This is the max_retrans value for the association. This value will * be initialized initialized from system defaults, but can be * modified by the SCTP_ASSOCINFO socket option. - */ + */ int max_retrans; /* Maximum number of times the endpoint will retransmit INIT */ - uint16_t max_init_attempts; + __u16 max_init_attempts; /* How many times have we resent an INIT? */ - uint16_t init_retries; + __u16 init_retries; /* The largest timeout or RTO value to use in attempting an INIT */ - uint16_t max_init_timeo; + __u16 max_init_timeo; - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; - struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; + int timeouts[SCTP_NUM_TIMEOUT_TYPES]; + struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; /* Transport to which SHUTDOWN chunk was last sent. */ sctp_transport_t *shutdown_last_sent_to; - /* Next TSN : The next TSN number to be assigned to a new - * : DATA chunk. This is sent in the INIT or INIT - * : ACK chunk to the peer and incremented each - * : time a DATA chunk is assigned a TSN - * : (normally just prior to transmit or during - * : fragmentation). - */ - uint32_t next_tsn; + /* Next TSN : The next TSN number to be assigned to a new + * : DATA chunk. This is sent in the INIT or INIT + * : ACK chunk to the peer and incremented each + * : time a DATA chunk is assigned a TSN + * : (normally just prior to transmit or during + * : fragmentation). + */ + __u32 next_tsn; - /* + /* * Last Rcvd : This is the last TSN received in sequence. This value * TSN : is set initially by taking the peer's Initial TSN, * : received in the INIT or INIT ACK chunk, and @@ -1298,25 +1285,25 @@ struct SCTP_association { * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. */ - uint32_t ctsn_ack_point; - - /* The number of unacknowledged data chunks. Reported through - * the SCTP_STATUS sockopt. + __u32 ctsn_ack_point; + + /* The number of unacknowledged data chunks. Reported through + * the SCTP_STATUS sockopt. */ - uint16_t unack_data; + __u16 unack_data; /* This is the association's receive buffer space. This value is used - * to set a_rwnd field in an INIT or a SACK chunk. + * to set a_rwnd field in an INIT or a SACK chunk. */ - uint32_t rwnd; + __u32 rwnd; /* Number of bytes by which the rwnd has slopped. The rwnd is allowed * to slop over a maximum of the association's frag_point. */ - uint32_t rwnd_over; + __u32 rwnd_over; - /* This is the sndbuf size in use for the association. - * This corresponds to the sndbuf size for the association, + /* This is the sndbuf size in use for the association. + * This corresponds to the sndbuf size for the association, * as specified in the sk->sndbuf. */ int sndbuf_used; @@ -1326,65 +1313,65 @@ struct SCTP_association { */ wait_queue_head_t wait; - /* Association : The smallest PMTU discovered for all of the - * PMTU : peer's transport addresses. - */ - uint32_t pmtu; + /* Association : The smallest PMTU discovered for all of the + * PMTU : peer's transport addresses. + */ + __u32 pmtu; /* The message size at which SCTP fragmentation will occur. */ - uint32_t frag_point; - - /* Ack State : This flag indicates if the next received - * : packet is to be responded to with a - * : SACK. This is initializedto 0. When a packet - * : is received it is incremented. If this value - * : reaches 2 or more, a SACK is sent and the - * : value is reset to 0. Note: This is used only - * : when no DATA chunks are received out of - * : order. When DATA chunks are out of order, - * : SACK's are not delayed (see Section 6). - */ - /* Do we need to send an ack? - * When counters[SctpCounterAckState] is above 1 we do! - */ - int counters[SCTP_NUMBER_COUNTERS]; - - struct { - uint16_t stream; - uint32_t ppid; - } defaults; - - /* This tracks outbound ssn for a given stream. */ - uint16_t ssn[SCTP_MAX_STREAM]; - - /* All outbound chunks go through this structure. */ - sctp_outqueue_t outqueue; - - /* A smart pipe that will handle reordering and fragmentation, + __u32 frag_point; + + /* Ack State : This flag indicates if the next received + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). + */ + /* Do we need to send an ack? + * When counters[SctpCounterAckState] is above 1 we do! + */ + int counters[SCTP_NUMBER_COUNTERS]; + + struct { + __u16 stream; + __u32 ppid; + } defaults; + + /* This tracks outbound ssn for a given stream. */ + __u16 ssn[SCTP_MAX_STREAM]; + + /* All outbound chunks go through this structure. */ + sctp_outqueue_t outqueue; + + /* A smart pipe that will handle reordering and fragmentation, * as well as handle passing events up to the ULP. * In the future, we should make this at least dynamic, if - * not also some sparse structure. + * not also some sparse structure. */ - sctp_ulpqueue_t ulpq; - uint8_t _ssnmap[sctp_ulpqueue_storage_size(SCTP_MAX_STREAM)]; + sctp_ulpqueue_t ulpq; + __u8 _ssnmap[sctp_ulpqueue_storage_size(SCTP_MAX_STREAM)]; /* Need to send an ECNE Chunk? */ - int need_ecne; - + int need_ecne; + /* Last TSN that caused an ECNE Chunk to be sent. */ - uint32_t last_ecne_tsn; + __u32 last_ecne_tsn; /* Last TSN that caused a CWR Chunk to be sent. */ - uint32_t last_cwr_tsn; - + __u32 last_cwr_tsn; + /* How many duplicated TSNs have we seen? */ - int numduptsns; + int numduptsns; + + /* Number of seconds of idle time before an association is closed. */ + __u32 autoclose; - /* Number of seconds of idle time before an association is closed. */ - uint32_t autoclose; - - /* Name for debugging output... */ - char *debug_name; + /* Name for debugging output... */ + char *debug_name; /* These are to support * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses @@ -1397,7 +1384,7 @@ struct SCTP_association { int addip_enable; /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks - * + * * R1) One and only one ASCONF Chunk MAY be in transit and * unacknowledged at any one time. If a sender, after sending * an ASCONF chunk, decides it needs to transfer another @@ -1406,14 +1393,14 @@ struct SCTP_association { * subsequent ASCONF. Note this restriction binds each side, * so at any time two ASCONF may be in-transit on any given * association (one sent from each endpoint). - * + * * [This is our one-and-only-one ASCONF in flight. If we do * not have an ASCONF in flight, this is NULL.] */ sctp_chunk_t *addip_last_asconf; /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. - * + * * IMPLEMENTATION NOTE: As an optimization a receiver may wish * to save the last ASCONF-ACK for some predetermined period * of time and instead of re-processing the ASCONF (with the @@ -1440,7 +1427,7 @@ struct SCTP_association { * essential that these transfers MUST NOT cause congestion * within the network. To achieve this, we place these * restrictions on the transfer of ASCONF Chunks: - * + * * R1) One and only one ASCONF Chunk MAY be in transit and * unacknowledged at any one time. If a sender, after sending * an ASCONF chunk, decides it needs to transfer another @@ -1449,35 +1436,36 @@ struct SCTP_association { * subsequent ASCONF. Note this restriction binds each side, * so at any time two ASCONF may be in-transit on any given * association (one sent from each endpoint). - * - * + * + * * [I really think this is EXACTLY the sort of intelligence * which already resides in SCTP_outqueue. Please move this - * queue and its supporting logic down there. --piggy] */ + * queue and its supporting logic down there. --piggy] + */ struct sk_buff_head addip_chunks; /* ADDIP Section 4.1 ASCONF Chunk Procedures - * + * * A2) A serial number should be assigned to the Chunk. The * serial number should be a monotonically increasing * number. All serial numbers are defined to be initialized at * the start of the association to the same value as the * Initial TSN. - * + * * [and] * * ADDIP * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) - * + * * Serial Number : 32 bits (unsigned integer) - * + * * This value represents a Serial Number for the ASCONF * Chunk. The valid range of Serial Number is from 0 to * 4294967295 (2**32 - 1). Serial Numbers wrap back to 0 * after reaching 4294967295. */ - uint32_t addip_serial; -}; /* sctp_association_t */ + __u32 addip_serial; +}; /* An eyecatcher for determining if we are really looking at an @@ -1491,14 +1479,13 @@ enum { static inline sctp_association_t *sctp_assoc(sctp_endpoint_common_t *base) { sctp_association_t *asoc; - - /* We are not really a list, but the list_entry() macro is - * really quite generic find the address of an outter struct. + + /* We are not really a list, but the list_entry() macro is + * really quite generic find the address of an outter struct. */ asoc = list_entry(base, sctp_association_t, base); - return asoc; - -} /* sctp_asoc() */ + return asoc; +} /* These are function signatures for manipulating associations. */ @@ -1507,31 +1494,31 @@ sctp_association_t * sctp_association_new(const sctp_endpoint_t *, const struct sock *, sctp_scope_t scope, int priority); sctp_association_t * -sctp_association_init(sctp_association_t *, const sctp_endpoint_t *, - const struct sock *, sctp_scope_t scope, +sctp_association_init(sctp_association_t *, const sctp_endpoint_t *, + const struct sock *, sctp_scope_t scope, int priority); void sctp_association_free(sctp_association_t *); void sctp_association_put(sctp_association_t *); void sctp_association_hold(sctp_association_t *); sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *); -sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, +sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *, const sockaddr_storage_t *); -sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, +sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *, const sockaddr_storage_t *address, const int priority); void sctp_assoc_control_transport(sctp_association_t *, sctp_transport_t *, sctp_transport_cmd_t, sctp_sn_error_t); -sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, uint32_t); -sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, - const sockaddr_storage_t *, +sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *, __u32); +sctp_transport_t *sctp_assoc_is_match(sctp_association_t *, + const sockaddr_storage_t *, const sockaddr_storage_t *); void sctp_assoc_migrate(sctp_association_t *, struct sock *); void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); -uint32_t __sctp_association_get_next_tsn(sctp_association_t *); -uint32_t __sctp_association_get_tsn_block(sctp_association_t *, int); -uint16_t __sctp_association_get_next_ssn(sctp_association_t *, uint16_t sid); +__u32 __sctp_association_get_next_tsn(sctp_association_t *); +__u32 __sctp_association_get_tsn_block(sctp_association_t *, int); +__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); int sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2); @@ -1555,7 +1542,5 @@ typedef struct { char *label; atomic_t *counter; } sctp_dbg_objcnt_entry_t; - - #endif /* __sctp_structs_h__ */ diff --git a/include/net/sctp/sctp_tsnmap.h b/include/net/sctp/sctp_tsnmap.h index 6e39c306a494..2d75c3fc4d61 100644 --- a/include/net/sctp/sctp_tsnmap.h +++ b/include/net/sctp/sctp_tsnmap.h @@ -52,77 +52,76 @@ */ typedef struct sctp_tsnmap { - + /* This array counts the number of chunks with each TSN. * It points at one of the two buffers with which we will - * ping-pong between. + * ping-pong between. */ - uint8_t *tsn_map; + __u8 *tsn_map; /* This marks the tsn which overflows the tsn_map, when the * cumulative ack point reaches this point we know we can switch * maps (tsn_map and overflow_map swap). */ - uint32_t overflow_tsn; + __u32 overflow_tsn; /* This is the overflow array for tsn_map. * It points at one of the other ping-pong buffers. */ - uint8_t *overflow_map; + __u8 *overflow_map; /* This is the TSN at tsn_map[0]. */ - uint32_t base_tsn; + __u32 base_tsn; - /* Last Rcvd : This is the last TSN received in + /* Last Rcvd : This is the last TSN received in * TSN : sequence. This value is set initially by * : taking the peer's Initial TSN, received in * : the INIT or INIT ACK chunk, and subtracting - * : one from it. + * : one from it. * * Throughout most of the specification this is called the * "Cumulative TSN ACK Point". In this case, we * ignore the advice in 12.2 in favour of the term * used in the bulk of the text. - */ - uint32_t cumulative_tsn_ack_point; + */ + __u32 cumulative_tsn_ack_point; /* This is the minimum number of TSNs we can track. This corresponds - * to the size of tsn_map. Note: the overflow_map allows us to - * potentially track more than this quantity. + * to the size of tsn_map. Note: the overflow_map allows us to + * potentially track more than this quantity. */ - uint16_t len; + __u16 len; /* This is the highest TSN we've marked. */ - uint32_t max_tsn_seen; + __u32 max_tsn_seen; /* No. of data chunks pending receipt. used by SCTP_STATUS sockopt */ - uint16_t pending_data; + __u16 pending_data; int malloced; - uint8_t raw_map[0]; + __u8 raw_map[0]; } sctp_tsnmap_t; typedef struct sctp_tsnmap_iter { - uint32_t start; + __u32 start; } sctp_tsnmap_iter_t; /* Create a new tsnmap. */ -sctp_tsnmap_t *sctp_tsnmap_new(uint16_t len, uint32_t initial_tsn, +sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority); /* Dispose of a tsnmap. */ void sctp_tsnmap_free(sctp_tsnmap_t *map); -/* This macro assists in creation of external storage for variable length +/* This macro assists in creation of external storage for variable length * internal buffers. We double allocate so the overflow map works. */ -#define sctp_tsnmap_storage_size(count) (sizeof(uint8_t) * (count) * 2) +#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2) /* Initialize a block of memory as a tsnmap. */ -sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, - uint32_t initial_tsn); +sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn); @@ -132,16 +131,16 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, * >0 if the TSN has been seen (duplicate) * <0 if the TSN is invalid (too large to track) */ -int sctp_tsnmap_check(const sctp_tsnmap_t *map, uint32_t tsn); +int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn); /* Mark this TSN as seen. */ -void sctp_tsnmap_mark(sctp_tsnmap_t *map, uint32_t tsn); +void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn); /* Retrieve the Cumulative TSN ACK Point. */ -uint32_t sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map); +__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map); /* Retrieve the highest TSN we've seen. */ -uint32_t sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map); +__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map); /* Is there a gap in the TSN map? */ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map); @@ -152,9 +151,8 @@ void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter); /* Get the next gap ack blocks. We return 0 if there are no more * gap ack blocks. */ -int -sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, - uint16_t *start, uint16_t *end); +int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + __u16 *start, __u16 *end); #endif /* __sctp_tsnmap_h__ */ diff --git a/include/net/sctp/sctp_ulpevent.h b/include/net/sctp/sctp_ulpevent.h index 631c61609454..75e8ba9efc05 100644 --- a/include/net/sctp/sctp_ulpevent.h +++ b/include/net/sctp/sctp_ulpevent.h @@ -45,8 +45,8 @@ #define __sctp_ulpevent_h__ /* A structure to carry information to the ULP (e.g. Sockets API) */ -/* Warning: This sits inside an skb.cb[] area. Be very careful of - * growing this structure as it is at the maximum limit now. +/* Warning: This sits inside an skb.cb[] area. Be very careful of + * growing this structure as it is at the maximum limit now. */ typedef struct sctp_ulpevent { int malloced; @@ -58,83 +58,73 @@ typedef struct sctp_ulpevent { } sctp_ulpevent_t; -sctp_ulpevent_t * -sctp_ulpevent_new(int size, int msg_flags, int priority); +sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority); -sctp_ulpevent_t * -sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags); +sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags); -void -sctp_ulpevent_free(sctp_ulpevent_t *event); +void sctp_ulpevent_free(sctp_ulpevent_t *event); +int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event); -int -sctp_ulpevent_is_notification(const sctp_ulpevent_t *event); - -sctp_ulpevent_t * -sctp_ulpevent_make_assoc_change(const struct SCTP_association *asoc, - uint16_t flags, - uint16_t state, - uint16_t error, - uint16_t outbound, - uint16_t inbound, +sctp_ulpevent_t *sctp_ulpevent_make_assoc_change( + const struct SCTP_association *asoc, + __u16 flags, + __u16 state, + __u16 error, + __u16 outbound, + __u16 inbound, int priority); -sctp_ulpevent_t * -sctp_ulpevent_make_peer_addr_change(const struct SCTP_association *asoc, - const struct sockaddr_storage *aaddr, - int flags, - int state, - int error, - int priority); +sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( + const struct SCTP_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority); -sctp_ulpevent_t * -sctp_ulpevent_make_remote_error(const struct SCTP_association *asoc, +sctp_ulpevent_t *sctp_ulpevent_make_remote_error( + const struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + __u16 flags, + int priority); +sctp_ulpevent_t *sctp_ulpevent_make_send_failed( + const struct SCTP_association *asoc, struct SCTP_chunk *chunk, - uint16_t flags, + __u16 flags, + __u32 error, int priority); -sctp_ulpevent_t * -sctp_ulpevent_make_send_failed(const struct SCTP_association *asoc, - struct SCTP_chunk *chunk, - uint16_t flags, - uint32_t error, - int priority); -sctp_ulpevent_t * -sctp_ulpevent_make_shutdown_event(const struct SCTP_association *asoc, - uint16_t flags, - int priority); +sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( + const struct SCTP_association *asoc, + __u16 flags, + int priority); -sctp_ulpevent_t * -sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc, - struct SCTP_chunk *chunk, - int priority); +sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc, + struct SCTP_chunk *chunk, + int priority); -void -sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, - struct msghdr *msghdr); +void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr); -uint16_t -sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event); +__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event); /* Given an event subscription, is this event enabled? */ -static inline int -sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event, - const struct sctp_event_subscribe *mask) +static inline int sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event, + const struct sctp_event_subscribe *mask) { - const char *amask = (const char *)mask; - uint16_t sn_type; - + const char *amask = (const char *) mask; + __u16 sn_type; int enabled = 1; + if (sctp_ulpevent_is_notification(event)) { sn_type = sctp_ulpevent_get_notification_type(event); enabled = amask[sn_type - SCTP_SN_TYPE_BASE]; } - return(enabled); - -} /* sctp_ulpevent_is_enabled() */ + return enabled; +} #endif /* __sctp_ulpevent_h__ */ diff --git a/include/net/sctp/sctp_ulpqueue.h b/include/net/sctp/sctp_ulpqueue.h index 2881457af222..83c1b9749659 100644 --- a/include/net/sctp/sctp_ulpqueue.h +++ b/include/net/sctp/sctp_ulpqueue.h @@ -50,47 +50,40 @@ typedef struct sctp_ulpqueue { sctp_association_t *asoc; struct sk_buff_head reasm; struct sk_buff_head lobby; - uint16_t ssn[0]; + __u16 ssn[0]; } sctp_ulpqueue_t; -/* This macro assists in creation of external storage for variable length - * internal buffers. +/* This macro assists in creation of external storage for variable length + * internal buffers. */ -#define sctp_ulpqueue_storage_size(inbound) (sizeof(uint16_t) * (inbound)) +#define sctp_ulpqueue_storage_size(inbound) (sizeof(__u16) * (inbound)) -sctp_ulpqueue_t * -sctp_ulpqueue_new(sctp_association_t *asoc, - uint16_t inbound, - int priority); +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, - uint16_t inbound); +sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, + sctp_association_t *asoc, + __u16 inbound); -void -sctp_ulpqueue_free(sctp_ulpqueue_t *); +void sctp_ulpqueue_free(sctp_ulpqueue_t *); /* Add a new DATA chunk for processing. */ -int -sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, - sctp_chunk_t *chunk, - int priority); +int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, + 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_ulpqueue_tail_event(sctp_ulpqueue_t *, + sctp_ulpevent_t *event); /* Is the ulpqueue empty. */ -int -sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); +int sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); -int -sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); +int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); #endif /* __sctp_ulpqueue_h__ */ diff --git a/include/net/sctp/sctp_user.h b/include/net/sctp/sctp_user.h index afe665ace370..54eaadd802e2 100644 --- a/include/net/sctp/sctp_user.h +++ b/include/net/sctp/sctp_user.h @@ -56,7 +56,7 @@ typedef void * sctp_assoc_t; -/* The following symbols come from the Sockets API Extensions for +/* The following symbols come from the Sockets API Extensions for * SCTP . */ enum sctp_optname { @@ -102,10 +102,10 @@ 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 -}; /* enum sctp_optname */ +}; -/* +/* * 5.2 SCTP msg_control Structures * * A key element of all SCTP-specific socket extensions is the use of @@ -119,9 +119,9 @@ enum sctp_optname { * contained in in the cmsg_data[] member. */ -/* +/* * 5.2.1 SCTP Initiation Structure (SCTP_INIT) - * + * * This cmsghdr structure provides information for initializing new * SCTP associations with sendmsg(). The SCTP_INITMSG socket option * uses this same data structure. This structure is not used for @@ -133,16 +133,16 @@ enum sctp_optname { * */ struct sctp_initmsg { - uint16_t sinit_num_ostreams; - uint16_t sinit_max_instreams; - uint16_t sinit_max_attempts; - uint16_t sinit_max_init_timeo; -}; /* struct sctp_initmsg */ + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + __u16 sinit_max_attempts; + __u16 sinit_max_init_timeo; +}; -/* +/* * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) - * + * * This cmsghdr structure specifies SCTP options for sendmsg() and * describes SCTP header information about a received message through * recvmsg(). @@ -153,15 +153,15 @@ struct sctp_initmsg { * */ struct sctp_sndrcvinfo { - uint16_t sinfo_stream; - uint16_t sinfo_ssn; - uint16_t sinfo_flags; - uint32_t sinfo_ppid; - uint32_t sinfo_context; - uint32_t sinfo_timetolive; - uint32_t sinfo_tsn; - sctp_assoc_t sinfo_assoc_id; -}; /* struct sctp_sndrcvinfo */ + __u16 sinfo_stream; + __u16 sinfo_ssn; + __u16 sinfo_flags; + __u32 sinfo_ppid; + __u32 sinfo_context; + __u32 sinfo_timetolive; + __u32 sinfo_tsn; + sctp_assoc_t sinfo_assoc_id; +}; /* * sinfo_flags: 16 bits (unsigned integer) @@ -175,23 +175,23 @@ enum sctp_sinfo_flags { MSG_ADDR_OVER = 2, /* Override the primary destination. */ MSG_ABORT=4, /* Send an ABORT message to the peer. */ /* MSG_EOF is already defined per socket.h */ -}; /* enum sctp_sinfo_flags */ +}; typedef union { - u_int8_t raw; - struct sctp_initmsg init; - struct sctp_sndrcvinfo sndrcv; + __u8 raw; + struct sctp_initmsg init; + struct sctp_sndrcvinfo sndrcv; } sctp_cmsg_data_t; /* These are cmsg_types. */ typedef enum sctp_cmsg_type { - SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ - SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ } sctp_cmsg_t; -/* +/* * 5.3.1.1 SCTP_ASSOC_CHANGE * * Communication notifications inform the ULP that an SCTP association @@ -202,22 +202,22 @@ typedef enum sctp_cmsg_type { */ struct sctp_assoc_change { - uint16_t sac_type; - uint16_t sac_flags; - uint32_t sac_length; - uint16_t sac_state; - uint16_t sac_error; - uint16_t sac_outbound_streams; - uint16_t sac_inbound_streams; + __u16 sac_type; + __u16 sac_flags; + __u32 sac_length; + __u16 sac_state; + __u16 sac_error; + __u16 sac_outbound_streams; + __u16 sac_inbound_streams; sctp_assoc_t sac_assoc_id; -}; /* sctp_assoc_change */ +}; /* * sac_state: 32 bits (signed integer) * * This field holds one of a number of values that communicate the * event that happened to the association. They include: - * + * * Note: The following state names deviate from the API draft as * the names clash too easily with other kernel symbols. */ @@ -227,24 +227,24 @@ enum sctp_sac_state { SCTP_RESTART, SCTP_SHUTDOWN_COMP, SCTP_CANT_STR_ASSOC, -}; /* sctp_sac_state */ +}; -/* +/* * 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * When a destination address on a multi-homed peer encounters a change * an interface details event is sent. The information has the * following structure: */ -struct sctp_paddr_change{ - uint16_t spc_type; - uint16_t spc_flags; - uint32_t spc_length; +struct sctp_paddr_change { + __u16 spc_type; + __u16 spc_flags; + __u32 spc_length; struct sockaddr_storage spc_aaddr; int spc_state; int spc_error; sctp_assoc_t spc_assoc_id; -}; /* sctp_paddr_change */ +}; /* * spc_state: 32 bits (signed integer) @@ -258,10 +258,10 @@ enum sctp_spc_state { ADDRESS_REMOVED, ADDRESS_ADDED, ADDRESS_MADE_PRIM, -}; /* sctp_spc_state */ +}; -/* +/* * 5.3.1.3 SCTP_REMOTE_ERROR * * A remote peer may send an Operational Error message to its peer. @@ -272,30 +272,30 @@ enum sctp_spc_state { * error formats. SCTP error TLVs have the format: */ struct sctp_remote_error { - uint16_t sre_type; - uint16_t sre_flags; - uint32_t sre_length; - uint16_t sre_error; - uint16_t sre_len; - sctp_assoc_t sre_assoc_id; - uint8_t sre_data[0]; + __u16 sre_type; + __u16 sre_flags; + __u32 sre_length; + __u16 sre_error; + __u16 sre_len; + sctp_assoc_t sre_assoc_id; + __u8 sre_data[0]; }; -/* +/* * 5.3.1.4 SCTP_SEND_FAILED * * If SCTP cannot deliver a message it may return the message as a * notification. */ struct sctp_send_failed { - uint16_t ssf_type; - uint16_t ssf_flags; - uint32_t ssf_length; - uint32_t ssf_error; - struct sctp_sndrcvinfo ssf_info; - sctp_assoc_t ssf_assoc_id; - uint8_t ssf_data[0]; + __u16 ssf_type; + __u16 ssf_flags; + __u32 ssf_length; + __u32 ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + __u8 ssf_data[0]; }; /* @@ -324,60 +324,60 @@ enum sctp_ssf_flags { */ struct sctp_shutdown_event { - uint16_t sse_type; - uint16_t sse_flags; - uint32_t sse_length; - sctp_assoc_t sse_assoc_id; + __u16 sse_type; + __u16 sse_flags; + __u32 sse_length; + sctp_assoc_t sse_assoc_id; }; -/* +/* * 5.3.1.6 SCTP_ADAPTION_INDICATION * * When a peer sends a Adaption Layer Indication parameter , SCTP - * delivers this notification to inform the application + * delivers this notification to inform the application * that of the peers requested adaption layer. */ struct sctp_adaption_event { - uint16_t sai_type; - uint16_t sai_flags; - uint32_t sai_length; - uint32_t sai_adaptation_bits; - sctp_assoc_t sse_assoc_id; + __u16 sai_type; + __u16 sai_flags; + __u32 sai_length; + __u32 sai_adaptation_bits; + sctp_assoc_t sse_assoc_id; }; -/* +/* * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * * When a reciever is engaged in a partial delivery of a * message this notification will be used to inidicate - * various events. + * various events. */ struct sctp_rcv_pdapi_event { - uint16_t pdapi_type; - uint16_t pdapi_flags; - uint32_t pdapi_length; - uint32_t pdapi_indication; - sctp_assoc_t pdapi_assoc_id; + __u16 pdapi_type; + __u16 pdapi_flags; + __u32 pdapi_length; + __u32 pdapi_indication; + sctp_assoc_t pdapi_assoc_id; }; -/* - * Described in Section 7.3 +/* + * Described in Section 7.3 * Ancillary Data and Notification Interest Options */ struct sctp_event_subscribe { - uint8_t sctp_data_io_event; - uint8_t sctp_association_event; - uint8_t sctp_address_event; - uint8_t sctp_send_failure_event; - uint8_t sctp_peer_error_event; - uint8_t sctp_shutdown_event; - uint8_t sctp_partial_delivery_event; - uint8_t sctp_adaption_layer_event; -}; /* struct sctp_event_subscribe */ - -/* + __u8 sctp_data_io_event; + __u8 sctp_association_event; + __u8 sctp_address_event; + __u8 sctp_send_failure_event; + __u8 sctp_peer_error_event; + __u8 sctp_shutdown_event; + __u8 sctp_partial_delivery_event; + __u8 sctp_adaption_layer_event; +}; + +/* * 5.3.1 SCTP Notification Structure * * The notification structure is defined as the union of all @@ -386,18 +386,18 @@ struct sctp_event_subscribe { */ union sctp_notification { struct { - uint16_t sn_type; /* Notification type. */ - uint16_t sn_flags; - uint32_t sn_length; + __u16 sn_type; /* Notification type. */ + __u16 sn_flags; + __u32 sn_length; } h; - struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_padr_change; - struct sctp_remote_error sn_remote_error; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_padr_change; + struct sctp_remote_error sn_remote_error; struct sctp_send_failed sn_send_failed; - struct sctp_shutdown_event sn_shutdown_event; + struct sctp_shutdown_event sn_shutdown_event; struct sctp_adaption_event sn_adaption_event; - struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; -}; + struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; +}; /* Section 5.3.1 * All standard values for sn_type flags are greater than 2^15. @@ -415,13 +415,13 @@ enum sctp_sn_type { SCTP_ADAPTION_INDICATION, }; -/* Notification error codes used to fill up the error fields in some +/* Notification error codes used to fill up the error fields in some * notifications. * SCTP_PEER_ADDRESS_CHAGE : spc_error * SCTP_ASSOC_CHANGE : sac_error - * These names should be potentially included in the draft 04 of the SCTP + * These names should be potentially included in the draft 04 of the SCTP * sockets API specification. - */ + */ typedef enum sctp_sn_error { SCTP_FAILED_THRESHOLD, SCTP_RECEIVED_SACK, @@ -432,7 +432,7 @@ typedef enum sctp_sn_error { SCTP_PEER_FAULTY, } sctp_sn_error_t; -/* +/* * * 7.1.14 Peer Address Parameters * @@ -445,13 +445,13 @@ typedef enum sctp_sn_error { */ struct sctp_paddrparams { - struct sockaddr_storage spp_address; - uint32_t spp_hbinterval; - uint16_t spp_pathmaxrxt; - sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; + sctp_assoc_t spp_assoc_id; }; -/* +/* * 7.2.2 Peer Address Information * * Applications can retrieve information about a specific peer address @@ -462,17 +462,17 @@ struct sctp_paddrparams { */ struct sctp_paddrinfo { - sctp_assoc_t spinfo_assoc_id; - struct sockaddr_storage spinfo_address; - int32_t spinfo_state; - uint32_t spinfo_cwnd; - uint32_t spinfo_srtt; - uint32_t spinfo_rto; - uint32_t spinfo_mtu; + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; }; -/* +/* * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) * * The protocol parameters used to initialize and bound retransmission @@ -482,13 +482,13 @@ struct sctp_paddrinfo { */ struct sctp_rtoinfo { - uint32_t srto_initial; - uint32_t srto_max; - uint32_t srto_min; - sctp_assoc_t srto_assoc_id; + __u32 srto_initial; + __u32 srto_max; + __u32 srto_min; + sctp_assoc_t srto_assoc_id; }; -/* +/* * 7.1.2 Association Retransmission Parameter (SCTP_ASSOCRTXINFO) * * The protocol parameter used to set the number of retransmissions @@ -498,12 +498,12 @@ struct sctp_rtoinfo { */ struct sctp_assocparams { - uint16_t sasoc_asocmaxrxt; - sctp_assoc_t sasoc_assoc_id; + __u16 sasoc_asocmaxrxt; + sctp_assoc_t sasoc_assoc_id; }; -/* +/* * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) * * Requests that the peer mark the enclosed address as the association @@ -513,11 +513,11 @@ struct sctp_assocparams { */ struct sctp_setprim { - struct sockaddr_storage ssp_addr; - sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; + sctp_assoc_t ssp_assoc_id; }; -/* +/* * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as @@ -527,11 +527,11 @@ struct sctp_setprim { */ struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; + sctp_assoc_t sspp_assoc_id; }; -/* +/* * 7.2.1 Association Status (SCTP_STATUS) * * Applications can retrieve current status information about an @@ -541,41 +541,41 @@ struct sctp_setpeerprim { * used to access this information: */ struct sctp_status { - sctp_assoc_t sstat_assoc_id; - int32_t sstat_state; - uint32_t sstat_rwnd; - uint16_t sstat_unackdata; - uint16_t sstat_penddata; - uint16_t sstat_instrms; - uint16_t sstat_outstrms; - uint32_t sstat_fragmentation_point; - struct sctp_paddrinfo sstat_primary; + sctp_assoc_t sstat_assoc_id; + __s32 sstat_state; + __u32 sstat_rwnd; + __u16 sstat_unackdata; + __u16 sstat_penddata; + __u16 sstat_instrms; + __u16 sstat_outstrms; + __u32 sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; }; -/* - * 7.1.12 Set Adaption Layer Indicator - * - * Requests that the local endpoint set the specified Adaption Layer +/* + * 7.1.12 Set Adaption Layer Indicator + * + * Requests that the local endpoint set the specified Adaption Layer * Indication parameter for all future - * INIT and INIT-ACK exchanges. + * INIT and INIT-ACK exchanges. */ struct sctp_setadaption { - u_int32_t ssb_adaption_ind; + __u32 ssb_adaption_ind; }; -/* +/* * 7.1.12 Set default message time outs (SCTP_SET_STREAM_TIMEOUTS) - * + * * This option requests that the requested stream apply a * default time-out for messages in queue. */ struct sctp_setstrm_timeout { - sctp_assoc_t ssto_assoc_id; - u_int32_t ssto_timeout; - u_int16_t ssto_streamid_start; - u_int16_t ssto_streamid_end; + sctp_assoc_t ssto_assoc_id; + __u32 ssto_timeout; + __u16 ssto_streamid_start; + __u16 ssto_streamid_end; }; @@ -584,18 +584,18 @@ struct sctp_setstrm_timeout { enum sctp_msg_flags { MSG_NOTIFICATION = 0x8000, #define MSG_NOTIFICATION MSG_NOTIFICATION -}; /* enum sctp_msg_flags */ +}; -/* +/* * 8.1 sctp_bindx() * - * The flags parameter is formed from the bitwise OR of zero or more of the + * The flags parameter is formed from the bitwise OR of zero or more of the * following currently defined flags: */ #define BINDX_ADD_ADDR 0x01 #define BINDX_REM_ADDR 0x02 -/* This is the structure that is passed as an argument(optval) to +/* This is the structure that is passed as an argument(optval) to * getsockopt(SCTP_SOCKOPT_PEELOFF). */ typedef struct { diff --git a/net/sctp/Config.help b/net/sctp/Config.help index 5dfb7250d6f7..25c1be2550cf 100644 --- a/net/sctp/Config.help +++ b/net/sctp/Config.help @@ -17,6 +17,11 @@ CONFIG_IP_SCTP -- network-level fault tolerance through supporting of multi- homing at either or both ends of an association." + This protocol support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module will be called sctp.o. If you want to compile it + as a module, say M here and read . + If in doubt, say N. CONFIG_SCTP_ADLER32 diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 4506c069a186..ff293fd2fac4 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -4,25 +4,25 @@ obj-$(CONFIG_IP_SCTP) += sctp.o -obj-y := sctp_sm_statetable.o sctp_sm_statefuns.o sctp_sm_sideeffect.o \ - sctp_protocol.o sctp_endpointola.o sctp_associola.o \ - sctp_transport.o sctp_sm_make_chunk.o sctp_ulpevent.o \ - sctp_inqueue.o sctp_outqueue.o sctp_ulpqueue.o sctp_command.o \ - sctp_tsnmap.o sctp_bind_addr.o sctp_socket.o sctp_primitive.o \ - sctp_output.o sctp_input.o sctp_hashdriver.o sctp_sla1.o \ - sctp_debug.o +sctp-y := sctp_sm_statetable.o sctp_sm_statefuns.o sctp_sm_sideeffect.o \ + sctp_protocol.o sctp_endpointola.o sctp_associola.o \ + sctp_transport.o sctp_sm_make_chunk.o sctp_ulpevent.o \ + sctp_inqueue.o sctp_outqueue.o sctp_ulpqueue.o sctp_command.o \ + sctp_tsnmap.o sctp_bind_addr.o sctp_socket.o sctp_primitive.o \ + sctp_output.o sctp_input.o sctp_hashdriver.o sctp_sla1.o \ + sctp_debug.o ifeq ($(CONFIG_SCTP_ADLER32), y) -obj-y += sctp_adler32.o +sctp-y += sctp_adler32.o else -obj-y += sctp_crc32c.o +sctp-y += sctp_crc32c.o endif -obj-$(CONFIG_SCTP_DBG_OBJCNT) += sctp_objcnt.o -obj-$(CONFIG_SYSCTL) += sctp_sysctl.o +sctp-$(CONFIG_SCTP_DBG_OBJCNT) += sctp_objcnt.o +sctp-$(CONFIG_SYSCTL) += sctp_sysctl.o -obj-$(subst m,y,$(CONFIG_IPV6)) += sctp_ipv6.o +sctp-$(subst m,y,$(CONFIG_IPV6)) += sctp_ipv6.o -sctp-objs := $(obj-y) +sctp-objs := $(sctp-y) include $(TOPDIR)/Rules.make diff --git a/net/sctp/sctp_adler32.c b/net/sctp/sctp_adler32.c index d00dc9c5a120..ebacd8e7778e 100644 --- a/net/sctp/sctp_adler32.c +++ b/net/sctp/sctp_adler32.c @@ -47,21 +47,21 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_adler32.c,v 1.5 2002/0 /* This is an entry point for external calls * Define this function in the header file. This is * direct from rfc1950, ... - + * * The following C code computes the Adler-32 checksum of a data buffer. - It is written for clarity, not for speed. The sample code is in the - ANSI C programming language. Non C users may find it easier to read - with these hints: - - & Bitwise AND operator. - >> Bitwise right shift operator. When applied to an - unsigned quantity, as here, right shift inserts zero bit(s) - at the left. - << Bitwise left shift operator. Left shift inserts zero - bit(s) at the right. - ++ "n++" increments the variable n. - % modulo operator: a % b is the remainder of a divided by b. - + * It is written for clarity, not for speed. The sample code is in the + * ANSI C programming language. Non C users may find it easier to read + * with these hints: + * + * & Bitwise AND operator. + * >> Bitwise right shift operator. When applied to an + * unsigned quantity, as here, right shift inserts zero bit(s) + * at the left. + * << Bitwise left shift operator. Left shift inserts zero + * bit(s) at the right. + * ++ "n++" increments the variable n. + * % modulo operator: a % b is the remainder of a divided by b. + * * Well, the above is a bit of a lie, I have optimized this a small * tad, but I have commented the original lines below */ @@ -81,71 +81,70 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_adler32.c,v 1.5 2002/0 * it back and we will incorporate it :-) */ - unsigned long update_adler32(unsigned long adler, unsigned char *buf, int len) { - uint32_t s1 = adler & 0xffff; - uint32_t s2 = (adler >> 16) & 0xffff; + __u32 s1 = adler & 0xffff; + __u32 s2 = (adler >> 16) & 0xffff; int n; - - for (n = 0; n < len; n++,buf++) { - - /* s1 = (s1 + buf[n]) % BASE */ - /* first we add */ - s1 = (s1 + *buf); - /* Now if we need to, we do a mod by - * subtracting. It seems a bit faster - * since I really will only ever do - * one subtract at the MOST, since buf[n] - * is a max of 255. - */ - if(s1 >= BASE){ - s1 -= BASE; - } - /* s2 = (s2 + s1) % BASE */ - /* first we add */ - s2 = (s2 + s1); - /* again, it is more efficent (it seems) to - * subtract since the most s2 will ever be - * is (BASE-1 + BASE-1) in the worse case. - * This would then be (2 * BASE) - 2, which - * will still only do one subtract. On Intel - * this is much better to do this way and - * avoid the divide. Have not -pg'd on - * sparc. - */ - if(s2 >= BASE){ - /* s2 %= BASE;*/ - s2 -= BASE; - } - } - /* Return the adler32 of the bytes buf[0..len-1] */ - return (s2 << 16) + s1; + + for (n = 0; n < len; n++,buf++) { + /* s1 = (s1 + buf[n]) % BASE */ + /* first we add */ + s1 = (s1 + *buf); + + /* Now if we need to, we do a mod by + * subtracting. It seems a bit faster + * since I really will only ever do + * one subtract at the MOST, since buf[n] + * is a max of 255. + */ + if(s1 >= BASE) + s1 -= BASE; + + /* s2 = (s2 + s1) % BASE */ + /* first we add */ + s2 = (s2 + s1); + + /* again, it is more efficent (it seems) to + * subtract since the most s2 will ever be + * is (BASE-1 + BASE-1) in the worse case. + * This would then be (2 * BASE) - 2, which + * will still only do one subtract. On Intel + * this is much better to do this way and + * avoid the divide. Have not -pg'd on + * sparc. + */ + if (s2 >= BASE) { + /* s2 %= BASE;*/ + s2 -= BASE; + } + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + return (s2 << 16) + s1; } -uint32_t -count_crc(uint8_t *ptr, - uint16_t count) +__u32 count_crc(__u8 *ptr, __u16 count) { - /* - * Update a running Adler-32 checksum with the bytes - * buf[0..len-1] and return the updated checksum. The Adler-32 - * checksum should be initialized to 1. - */ - uint32_t adler = 1L; - uint32_t zero = 0L; + /* + * Update a running Adler-32 checksum with the bytes + * buf[0..len-1] and return the updated checksum. The Adler-32 + * checksum should be initialized to 1. + */ + __u32 adler = 1L; + __u32 zero = 0L; /* Calculate the CRC up to the checksum field. */ - adler = update_adler32(adler, ptr, - sizeof(struct sctphdr) - sizeof(uint32_t)); + adler = update_adler32(adler, ptr, + sizeof(struct sctphdr) - sizeof(__u32)); /* Skip over the checksum field. */ - adler = update_adler32(adler, &zero, sizeof(uint32_t)); + adler = update_adler32(adler, &zero, sizeof(__u32)); ptr += sizeof(struct sctphdr); count -= sizeof(struct sctphdr); + /* Calculate the rest of the Adler-32. */ adler = update_adler32(adler, ptr, count); - - return(adler); -} + return adler; +} diff --git a/net/sctp/sctp_associola.c b/net/sctp/sctp_associola.c index 57d03a6a8acd..4694f76dfc3c 100644 --- a/net/sctp/sctp_associola.c +++ b/net/sctp/sctp_associola.c @@ -49,7 +49,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_associola.c,v 1.48 2002/08/16 19:30:49 jgrimm Exp $"; -#include #include #include #include @@ -62,7 +61,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_associola.c,v 1.48 200 #include #include - /* Forward declarations for internal functions. */ static void sctp_assoc_bh_rcv(sctp_association_t *asoc); @@ -70,57 +68,55 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc); /* 1st Level Abstractions. */ /* Allocate and initialize a new association */ -sctp_association_t * -sctp_association_new(const sctp_endpoint_t *ep, const struct sock *sk, - sctp_scope_t scope, int priority) +sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, + const struct sock *sk, + sctp_scope_t scope, int priority) { - sctp_association_t *asoc; + sctp_association_t *asoc; - asoc = t_new(sctp_association_t, priority); - if (!asoc) { + asoc = t_new(sctp_association_t, priority); + if (!asoc) goto fail; - } - if (!sctp_association_init(asoc, ep, sk, scope, priority)) { + if (!sctp_association_init(asoc, ep, sk, scope, priority)) goto fail_init; - } asoc->base.malloced = 1; SCTP_DBG_OBJCNT_INC(assoc); return asoc; - + fail_init: kfree(asoc); fail: return NULL; - -} /* sctp_association_new() */ +} /* Intialize a new association from provided memory. */ -sctp_association_t * -sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, - const struct sock *sk, sctp_scope_t scope, - int priority) +sctp_association_t *sctp_association_init(sctp_association_t *asoc, + const sctp_endpoint_t *ep, + const struct sock *sk, + sctp_scope_t scope, + int priority) { - int i; sctp_opt_t *sp; + int i; /* Retrieve the SCTP per socket area. */ - sp = sctp_sk((struct sock *)sk); + sp = sctp_sk((struct sock *)sk); /* Init all variables to a known value. */ - memset(asoc, 0, sizeof(sctp_association_t)); + memset(asoc, 0, sizeof(sctp_association_t)); /* Discarding const is appropriate here. */ - asoc->ep = (sctp_endpoint_t *)ep; + asoc->ep = (sctp_endpoint_t *)ep; sctp_endpoint_hold(asoc->ep); /* Hold the sock. */ asoc->base.sk = (struct sock *)sk; sock_hold(asoc->base.sk); - /* Initialize the common base substructure. */ + /* Initialize the common base substructure. */ asoc->base.type = SCTP_EP_TYPE_ASSOCIATION; /* Initialize the object handling fields. */ @@ -131,15 +127,15 @@ sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, /* Initialize the bind addr area. */ sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); asoc->base.addr_lock = RW_LOCK_UNLOCKED; - - asoc->state = SCTP_STATE_CLOSED; - asoc->state_timestamp = jiffies; - /* Set things that have constant value. */ - asoc->cookie_life.tv_sec = SCTP_DEFAULT_COOKIE_LIFE_SEC; - asoc->cookie_life.tv_usec = SCTP_DEFAULT_COOKIE_LIFE_USEC; + asoc->state = SCTP_STATE_CLOSED; + asoc->state_timestamp = jiffies; + + /* Set things that have constant value. */ + asoc->cookie_life.tv_sec = SCTP_DEFAULT_COOKIE_LIFE_SEC; + asoc->cookie_life.tv_usec = SCTP_DEFAULT_COOKIE_LIFE_USEC; - asoc->pmtu = 0; + asoc->pmtu = 0; asoc->frag_point = 0; /* Initialize the default association max_retrans and RTO values. */ @@ -151,80 +147,78 @@ sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, asoc->overall_error_threshold = 0; asoc->overall_error_count = 0; - /* Initialize the maximum mumber of new data packets that can be sent - * in a burst. + /* Initialize the maximum mumber of new data packets that can be sent + * in a burst. */ asoc->max_burst = ep->proto->max_burst; - /* Copy things from the endpoint. */ - for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { - asoc->timeouts[i] = ep->timeouts[i]; - init_timer(&asoc->timers[i]); - asoc->timers[i].function = sctp_timer_events[i]; - asoc->timers[i].data = (unsigned long)asoc; - } + /* Copy things from the endpoint. */ + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + asoc->timeouts[i] = ep->timeouts[i]; + init_timer(&asoc->timers[i]); + asoc->timers[i].function = sctp_timer_events[i]; + asoc->timers[i].data = (unsigned long) asoc; + } - /* Pull default initialization values from the sock options. - * Note: This assumes that the values have already been - * validated in the sock. + /* Pull default initialization values from the sock options. + * Note: This assumes that the values have already been + * validated in the sock. */ - asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; - asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; - asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; + asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; + asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; + asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ; /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * + * * The stream sequence number in all the streams shall start * from 0 when the association is established. Also, when the * stream sequence number reaches the value 65535 the next * stream sequence number shall be set to 0. */ - for(i=0; i < SCTP_MAX_STREAM; i++) { - asoc->ssn[i] = 0; - } + for (i = 0; i < SCTP_MAX_STREAM; i++) + asoc->ssn[i] = 0; - /* Set the local window size for receive. - * This is also the rcvbuf space per association. - * RFC 6 - A SCTP receiver MUST be able to receive a minimum of - * 1500 bytes in one SCTP packet. + /* Set the local window size for receive. + * This is also the rcvbuf space per association. + * RFC 6 - A SCTP receiver MUST be able to receive a minimum of + * 1500 bytes in one SCTP packet. */ - if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) { + if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) asoc->rwnd = SCTP_DEFAULT_MINWINDOW; - } else { + else asoc->rwnd = sk->rcvbuf; - } asoc->rwnd_over = 0; - /* Use my own max window until I learn something better. */ + /* Use my own max window until I learn something better. */ asoc->peer.rwnd = SCTP_DEFAULT_MAXWINDOW; /* Set the sndbuf size for transmit. */ asoc->sndbuf_used = 0; - + init_waitqueue_head(&asoc->wait); - asoc->c.my_vtag = sctp_generate_tag(ep); - asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ + asoc->c.my_vtag = sctp_generate_tag(ep); + asoc->peer.i.init_tag = 0; /* INIT needs a vtag of 0. */ asoc->c.peer_vtag = 0; asoc->c.my_ttag = 0; - asoc->c.peer_ttag = 0; + asoc->c.peer_ttag = 0; - asoc->c.initial_tsn = sctp_generate_tsn(ep); + asoc->c.initial_tsn = sctp_generate_tsn(ep); asoc->next_tsn = asoc->c.initial_tsn; - - asoc->ctsn_ack_point = asoc->next_tsn - 1; + + asoc->ctsn_ack_point = asoc->next_tsn - 1; asoc->unack_data = 0; - SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", + SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", asoc->ep->debug_name, asoc->ctsn_ack_point); - + /* ADDIP Section 4.1 Asconf Chunk Procedures - * + * * When an endpoint has an ASCONF signaled change to be sent to the * remote endpoint it should do the following: * ... @@ -235,54 +229,53 @@ sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, */ asoc->addip_serial = asoc->c.initial_tsn; - /* Make an empty list of remote transport addresses. */ + /* Make an empty list of remote transport addresses. */ INIT_LIST_HEAD(&asoc->peer.transport_addr_list); - - /* RFC 2960 5.1 Normal Establishment of an Association + + /* RFC 2960 5.1 Normal Establishment of an Association + * + * After the reception of the first data chunk in an + * association the endpoint must immediately respond with a + * sack to acknowledge the data chunk. Subsequent + * acknowledgements should be done as described in Section + * 6.2. * - * After the reception of the first data chunk in an - * association the endpoint must immediately respond with a - * sack to acknowledge the data chunk. Subsequent - * acknowledgements should be done as described in Section - * 6.2. - * - * [We implement this by telling a new association that it - * already received one packet.] + * [We implement this by telling a new association that it + * already received one packet.] */ - asoc->peer.sack_needed = 1; + asoc->peer.sack_needed = 1; - /* Create an input queue. */ - sctp_inqueue_init(&asoc->base.inqueue); - sctp_inqueue_set_th_handler(&asoc->base.inqueue, - (void (*)(void *))sctp_assoc_bh_rcv, + /* Create an input queue. */ + sctp_inqueue_init(&asoc->base.inqueue); + sctp_inqueue_set_th_handler(&asoc->base.inqueue, + (void (*)(void *))sctp_assoc_bh_rcv, asoc); - - /* Create an output queue. */ - sctp_outqueue_init(asoc, &asoc->outqueue); - sctp_outqueue_set_output_handlers(&asoc->outqueue, - sctp_packet_init, - sctp_packet_config, - sctp_packet_append_chunk, - sctp_packet_transmit_chunk, - sctp_packet_transmit); - - if (NULL == sctp_ulpqueue_init(&asoc->ulpq, asoc, SCTP_MAX_STREAM)) { + + /* Create an output queue. */ + sctp_outqueue_init(asoc, &asoc->outqueue); + sctp_outqueue_set_output_handlers(&asoc->outqueue, + sctp_packet_init, + sctp_packet_config, + sctp_packet_append_chunk, + sctp_packet_transmit_chunk, + sctp_packet_transmit); + + if (NULL == sctp_ulpqueue_init(&asoc->ulpq, asoc, SCTP_MAX_STREAM)) goto fail_init; - } - /* Set up the tsn tracking. */ + /* Set up the tsn tracking. */ sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); asoc->peer.next_dup_tsn = 0; - skb_queue_head_init(&asoc->addip_chunks); + skb_queue_head_init(&asoc->addip_chunks); asoc->need_ecne = 0; - - asoc->debug_name = "unnamedasoc"; - asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; + + asoc->debug_name = "unnamedasoc"; + asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; /* Assume that peer would support both address types unless we are - * told otherwise. + * told otherwise. */ asoc->peer.ipv4_address = 1; asoc->peer.ipv6_address = 1; @@ -295,32 +288,30 @@ sctp_association_init(sctp_association_t *asoc, const sctp_endpoint_t *ep, fail_init: sctp_endpoint_put(asoc->ep); sock_put(asoc->base.sk); - return NULL; - -} /* sctp_association_init() */ + return NULL; +} -/* Free this association if possible. There may still be users, so - * the actual deallocation may be delayed. -*/ -void -sctp_association_free(sctp_association_t *asoc) +/* Free this association if possible. There may still be users, so + * the actual deallocation may be delayed. + */ +void sctp_association_free(sctp_association_t *asoc) { - sctp_transport_t *transport; + sctp_transport_t *transport; sctp_endpoint_t *ep; - list_t *pos, *temp; + list_t *pos, *temp; int i; ep = asoc->ep; list_del(&asoc->asocs); - /* Mark as dead, so other users can know this structure is - * going away. + /* Mark as dead, so other users can know this structure is + * going away. */ asoc->base.dead = 1; - /* Dispose of any data lying around in the outqueue. */ - sctp_outqueue_free(&asoc->outqueue); + /* Dispose of any data lying around in the outqueue. */ + sctp_outqueue_free(&asoc->outqueue); /* Dispose of any pending messages for the upper layer. */ sctp_ulpqueue_free(&asoc->ulpq); @@ -330,74 +321,71 @@ sctp_association_free(sctp_association_t *asoc) /* Clean up the bound address list. */ sctp_bind_addr_free(&asoc->base.bind_addr); - - /* Do we need to go through all of our timers and - * delete them? To be safe we will try to delete all, but we + + /* Do we need to go through all of our timers and + * delete them? To be safe we will try to delete all, but we * should be able to go through and make a guess based - * on our state. + * on our state. */ - - for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { - if (timer_pending(&asoc->timers[i]) - && del_timer(&asoc->timers[i])) { + for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { + if (timer_pending(&asoc->timers[i]) && + del_timer(&asoc->timers[i])) sctp_association_put(asoc); - } - } + } /* Release the transport structures. */ - list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, sctp_transport_t, transports); list_del(pos); sctp_transport_free(transport); - } /* for (all transports). */ - - asoc->eyecatcher = 0; + } - sctp_association_put(asoc); + asoc->eyecatcher = 0; -} /* sctp_association_free() */ + sctp_association_put(asoc); +} /* Cleanup and free up an association. */ -static void -sctp_association_destroy(sctp_association_t *asoc) +static void sctp_association_destroy(sctp_association_t *asoc) { SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); - sctp_endpoint_put(asoc->ep); + sctp_endpoint_put(asoc->ep); sock_put(asoc->base.sk); if (asoc->base.malloced) { kfree(asoc); SCTP_DBG_OBJCNT_DEC(assoc); } - -} /* sctp_association_destroy() */ +} /* Add a transport address to an association. */ -sctp_transport_t * -sctp_assoc_add_peer(sctp_association_t *asoc, const sockaddr_storage_t *addr, - int priority) +sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, + const sockaddr_storage_t *addr, + int priority) { - sctp_transport_t *peer; - sctp_opt_t *sp; - const uint16_t *port; + sctp_transport_t *peer; + sctp_opt_t *sp; + const __u16 *port; - switch (addr->sa.sa_family){ + switch (addr->sa.sa_family) { case AF_INET: port = &addr->v4.sin_port; break; + case AF_INET6: SCTP_V6( port = &addr->v6.sin6_port; break; ); + default: return NULL; - } /* switch addr type */ + }; - /* Set the port if it has not been set yet. */ + /* Set the port if it has not been set yet. */ if (0 == asoc->peer.port) { asoc->peer.port = *port; } @@ -407,28 +395,30 @@ sctp_assoc_add_peer(sctp_association_t *asoc, const sockaddr_storage_t *addr, /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); - if (peer) { return peer; } + if (peer) + return peer; - peer = sctp_transport_new(addr, priority); - if (NULL == peer) { return NULL; } + peer = sctp_transport_new(addr, priority); + if (NULL == peer) + return NULL; sctp_transport_set_owner(peer, asoc); - /* If this is the first transport addr on this association, - * initialize the association PMTU to the peer's PMTU. - * If not and the current association PMTU is higher than the new - * peer's PMTU, reset the association PMTU to the new peer's PMTU. - */ - if (asoc->pmtu) { - asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu); - } else { - asoc->pmtu = peer->pmtu; - } + /* If this is the first transport addr on this association, + * initialize the association PMTU to the peer's PMTU. + * If not and the current association PMTU is higher than the new + * peer's PMTU, reset the association PMTU to the new peer's PMTU. + */ + if (asoc->pmtu) { + asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu); + } else { + asoc->pmtu = peer->pmtu; + } - SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " + SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " "%d\n", asoc, asoc->pmtu); - asoc->frag_point = asoc->pmtu - + asoc->frag_point = asoc->pmtu - (SCTP_IP_OVERHEAD + sizeof(sctp_data_chunk_t)); /* The asoc->peer.port might not be meaningful as of now, but @@ -439,86 +429,83 @@ sctp_assoc_add_peer(sctp_association_t *asoc, const sockaddr_storage_t *addr, asoc->base.bind_addr.port, asoc->peer.port); - /* 7.2.1 Slow-Start - * - * o The initial cwnd before data transmission or after a - * sufficiently long idle period MUST be <= 2*MTU. - * - * o The initial value of ssthresh MAY be arbitrarily high - * (for example, implementations MAY use the size of the - * receiver advertised window). - */ + /* 7.2.1 Slow-Start + * + * o The initial cwnd before data transmission or after a + * sufficiently long idle period MUST be <= 2*MTU. + * + * o The initial value of ssthresh MAY be arbitrarily high + * (for example, implementations MAY use the size of the + * receiver advertised window). + */ peer->cwnd = asoc->pmtu * 2; - /* At this point, we may not have the receiver's advertised window, - * so initialize ssthresh to the default value and it will be set + + /* At this point, we may not have the receiver's advertised window, + * so initialize ssthresh to the default value and it will be set * later when we process the INIT. */ - peer->ssthresh = SCTP_DEFAULT_MAXWINDOW; + peer->ssthresh = SCTP_DEFAULT_MAXWINDOW; peer->partial_bytes_acked = 0; peer->flight_size = 0; - peer->error_threshold = peer->max_retrans; + peer->error_threshold = peer->max_retrans; - /* Update the overall error threshold value of the association + /* Update the overall error threshold value of the association * taking the new peer's error threshold into account. - */ - asoc->overall_error_threshold = + */ + asoc->overall_error_threshold = min(asoc->overall_error_threshold + peer->error_threshold, asoc->max_retrans); - + /* Initialize the peer's heartbeat interval based on the - * sock configured value. - */ + * sock configured value. + */ sp = sctp_sk(asoc->base.sk); peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; /* Attach the remote transport to our asoc. */ list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); - - /* If we do not yet have a primary path, set one. */ - if (NULL == asoc->peer.primary_path) { - asoc->peer.primary_path = peer; - asoc->peer.active_path = peer; - asoc->peer.retran_path = peer; - } - if (asoc->peer.active_path == asoc->peer.retran_path) { - asoc->peer.retran_path = peer; - } + /* If we do not yet have a primary path, set one. */ + if (NULL == asoc->peer.primary_path) { + asoc->peer.primary_path = peer; + asoc->peer.active_path = peer; + asoc->peer.retran_path = peer; + } - return peer; + if (asoc->peer.active_path == asoc->peer.retran_path) + asoc->peer.retran_path = peer; -} /* sctp_assoc_add_peer() */ + return peer; +} /* Lookup a transport by address. */ -sctp_transport_t * -sctp_assoc_lookup_paddr(const sctp_association_t *asoc, - const sockaddr_storage_t *address) +sctp_transport_t *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, + const sockaddr_storage_t *address) { sctp_transport_t *t; list_t *pos; /* Cycle through all transports searching for a peer address. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { + list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, sctp_transport_t, transports); - if ( sctp_cmp_addr_exact(address, &t->ipaddr) ) { return t; } - } /* for (all transports) */ - - return NULL; + if (sctp_cmp_addr_exact(address, &t->ipaddr)) + return t; + } -} /* sctp_assoc_lookup_paddr() */ + return NULL; +} /* Engage in transport control operations. * Mark the transport up or down and send a notification to the user. * Select and update the new active and retran paths. */ -void -sctp_assoc_control_transport(sctp_association_t *asoc, - sctp_transport_t *transport, - sctp_transport_cmd_t command, - sctp_sn_error_t error) +void sctp_assoc_control_transport(sctp_association_t *asoc, + sctp_transport_t *transport, + sctp_transport_cmd_t command, + sctp_sn_error_t error) { sctp_transport_t *t = NULL; sctp_transport_t *first; @@ -527,32 +514,30 @@ sctp_assoc_control_transport(sctp_association_t *asoc, list_t *pos; int spc_state = 0; - /* Record the transition on the transport. */ switch (command) { case SCTP_TRANSPORT_UP: transport->state.active = 1; spc_state = ADDRESS_AVAILABLE; break; + case SCTP_TRANSPORT_DOWN: transport->state.active = 0; spc_state = ADDRESS_UNREACHABLE; break; + default: BUG(); - } /* switch (command) */ - + }; /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the - * user. + * user. */ event = sctp_ulpevent_make_peer_addr_change(asoc, - (struct sockaddr_storage *)&transport->ipaddr, + (struct sockaddr_storage *) &transport->ipaddr, 0, spc_state, error, GFP_ATOMIC); - if (event) { + if (event) sctp_ulpqueue_tail_event(&asoc->ulpq, event); - } - /* Select new active and retran paths. */ @@ -567,17 +552,15 @@ sctp_assoc_control_transport(sctp_association_t *asoc, list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, sctp_transport_t, transports); - if (!t->state.active) { continue; } - + if (!t->state.active) + continue; if (!first || t->last_time_heard > first->last_time_heard) { second = first; first = t; } - if (!second || t->last_time_heard > second->last_time_heard) { + if (!second || t->last_time_heard > second->last_time_heard) second = t; - } - - } /* for (all transports) */ + } /* RFC 2960 6.4 Multi-Homed SCTP Endpoints * @@ -589,17 +572,16 @@ sctp_assoc_control_transport(sctp_association_t *asoc, * [If the primary is active but not most recent, bump the most * recently used transport.] */ - if (asoc->peer.primary_path->state.active - && first != asoc->peer.primary_path) { + if (asoc->peer.primary_path->state.active && + first != asoc->peer.primary_path) { second = first; first = asoc->peer.primary_path; } - /* If we failed to find a usable transport, just camp on the * primary, even if it is inactive. */ - if ( NULL == first ) { + if (NULL == first) { first = asoc->peer.primary_path; second = asoc->peer.primary_path; } @@ -607,161 +589,137 @@ sctp_assoc_control_transport(sctp_association_t *asoc, /* Set the active and retran transports. */ asoc->peer.active_path = first; asoc->peer.retran_path = second; - - return; - -} /* sctp_assoc_control_transport() */ - +} /* Hold a reference to an association. */ void sctp_association_hold(sctp_association_t *asoc) { atomic_inc(&asoc->base.refcnt); - -} /* sctp_association_hold() */ +} /* Release a reference to an association and cleanup - * if there are no more references. + * if there are no more references. */ void sctp_association_put(sctp_association_t *asoc) { - if (atomic_dec_and_test(&asoc->base.refcnt)) { + if (atomic_dec_and_test(&asoc->base.refcnt)) sctp_association_destroy(asoc); - } - -} /* sctp_association_put() */ - +} /* Allocate the next TSN, Transmission Sequence Number, for the given * association. */ -uint32_t -__sctp_association_get_next_tsn(sctp_association_t *asoc) +__u32 __sctp_association_get_next_tsn(sctp_association_t *asoc) { - /* From Section 1.6 Serial Number Arithmetic: - * Transmission Sequence Numbers wrap around when they reach - * 2**32 - 1. That is, the next TSN a DATA chunk MUST use - * after transmitting TSN = 2*32 - 1 is TSN = 0. - */ - uint32_t retval = asoc->next_tsn; + /* From Section 1.6 Serial Number Arithmetic: + * Transmission Sequence Numbers wrap around when they reach + * 2**32 - 1. That is, the next TSN a DATA chunk MUST use + * after transmitting TSN = 2*32 - 1 is TSN = 0. + */ + __u32 retval = asoc->next_tsn; asoc->next_tsn++; asoc->unack_data++; return retval; - -} /* __sctp_association_get_next_tsn() */ - +} /* Allocate 'num' TSNs by incrementing the association's TSN by num. */ -uint32_t -__sctp_association_get_tsn_block(sctp_association_t *asoc, int num) +__u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num) { - uint32_t retval = asoc->next_tsn; - asoc->next_tsn += num; - asoc->unack_data += num; + __u32 retval = asoc->next_tsn; - return retval; - -} /* __sctp_association_get_tsn_block() */ + asoc->next_tsn += num; + asoc->unack_data += num; + return retval; +} /* Fetch the next Stream Sequence Number for stream number 'sid'. */ -uint16_t -__sctp_association_get_next_ssn(sctp_association_t *asoc, uint16_t sid) +__u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) { - return(asoc->ssn[sid]++); - -} /* __sctp_association_get_next_ssn() */ - + return asoc->ssn[sid]++; +} /* Compare two addresses to see if they match. Wildcard addresses * always match within their address family. - * + * * FIXME: We do not match address scopes correctly. */ -int -sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2) +int sctp_cmp_addr(const sockaddr_storage_t *ss1, const sockaddr_storage_t *ss2) { int len; const void *base1; const void *base2; - if (ss1->sa.sa_family != ss2->sa.sa_family) { + if (ss1->sa.sa_family != ss2->sa.sa_family) return 0; - } - if (ss1->v4.sin_port != ss2->v4.sin_port) { + if (ss1->v4.sin_port != ss2->v4.sin_port) return 0; - } switch (ss1->sa.sa_family) { case AF_INET: if (INADDR_ANY == ss1->v4.sin_addr.s_addr || - INADDR_ANY == ss2->v4.sin_addr.s_addr) { + INADDR_ANY == ss2->v4.sin_addr.s_addr) goto match; - } len = sizeof(struct in_addr); base1 = &ss1->v4.sin_addr; base2 = &ss2->v4.sin_addr; break; + case AF_INET6: SCTP_V6( - if (IPV6_ADDR_ANY == - sctp_ipv6_addr_type(&ss1->v6.sin6_addr)) { + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss1->v6.sin6_addr)) goto match; - } - if (IPV6_ADDR_ANY == - sctp_ipv6_addr_type(&ss2->v6.sin6_addr)) { + if (IPV6_ADDR_ANY == + sctp_ipv6_addr_type(&ss2->v6.sin6_addr)) goto match; - } + len = sizeof(struct in6_addr); base1 = &ss1->v6.sin6_addr; base2 = &ss2->v6.sin6_addr; break; ) - + default: printk(KERN_WARNING "WARNING, bogus socket address family %d\n", ss1->sa.sa_family); return 0; - } + }; return (0 == memcmp(base1, base2, len)); - match: - return 1; -} /* sctp_cmp_addr() */ +match: + return 1; +} /* Compare two addresses to see if they match. Wildcard addresses * only match themselves. * * FIXME: We do not match address scopes correctly. */ -int -sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, - const sockaddr_storage_t *ss2) +int sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, + const sockaddr_storage_t *ss2) { int len; const void *base1; const void *base2; - - if (ss1->sa.sa_family != ss2->sa.sa_family) { + if (ss1->sa.sa_family != ss2->sa.sa_family) return 0; - } - - if (ss1->v4.sin_port != ss2->v4.sin_port) { + if (ss1->v4.sin_port != ss2->v4.sin_port) return 0; - } - - switch(ss1->sa.sa_family) { + + switch (ss1->sa.sa_family) { case AF_INET: len = sizeof(struct in_addr); base1 = &ss1->v4.sin_addr; base2 = &ss2->v4.sin_addr; break; + case AF_INET6: SCTP_V6( len = sizeof(struct in6_addr); @@ -769,32 +727,29 @@ sctp_cmp_addr_exact(const sockaddr_storage_t *ss1, base2 = &ss2->v6.sin6_addr; break; ) + default: printk(KERN_WARNING "WARNING, bogus socket address family %d\n", ss1->sa.sa_family); return 0; - } + }; return (0 == memcmp(base1, base2, len)); - -} /* sctp_cmp_addr_exact() */ - +} /* Return an ecne chunk to get prepended to a packet. * Note: We are sly and return a shared, prealloced chunk. */ -sctp_chunk_t * -sctp_get_ecne_prepend(sctp_association_t *asoc) +sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc) { sctp_chunk_t *chunk; int need_ecne; - uint32_t lowest_tsn; + __u32 lowest_tsn; - /* Can be called from task or bh. Both need_ecne and - * last_ecne_tsn are written during bh. + /* Can be called from task or bh. Both need_ecne and + * last_ecne_tsn are written during bh. */ - need_ecne = asoc->need_ecne; lowest_tsn = asoc->last_ecne_tsn; @@ -806,98 +761,84 @@ sctp_get_ecne_prepend(sctp_association_t *asoc) * out the network. If we run out of memory, just return * NULL. */ - } else { chunk = NULL; } return chunk; - -} /* sctp_get_ecne_prepend(asoc) */ - +} /* Use this function for the packet prepend callback when no ECNE * packet is desired (e.g. some packets don't like to be bundled). */ -sctp_chunk_t * -sctp_get_no_prepend(sctp_association_t *asoc) +sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) { return NULL; - -} /* sctp_get_no_prepend(asoc) */ - +} /* - * Find which transport this TSN was sent on. + * Find which transport this TSN was sent on. */ -sctp_transport_t * -sctp_assoc_lookup_tsn(sctp_association_t *asoc, uint32_t tsn) +sctp_transport_t *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) { sctp_transport_t *active; sctp_transport_t *match; list_t *entry, *pos; sctp_transport_t *transport; - sctp_chunk_t *chunk; - - uint32_t key = htonl(tsn); - + __u32 key = htonl(tsn); + match = NULL; - /* + /* * FIXME: In general, find a more efficient data structure for - * searching. + * searching. */ - /* + /* * The general strategy is to search each transport's transmitted * list. Return which transport this TSN lives on. - * + * * Let's be hopeful and check the active_path first. * Another optimization would be to know if there is only one * outbound path and not have to look for the TSN at all. - * + * */ active = asoc->peer.active_path; - - list_for_each(entry, &active->transmitted) { + list_for_each(entry, &active->transmitted) { chunk = list_entry(entry, sctp_chunk_t, transmitted_list); - - if (key == chunk->subh.data_hdr->tsn){ + + if (key == chunk->subh.data_hdr->tsn) { match = active; goto out; } - } /* for (each unacknowledged TSN) */ - - /* If not found, go search all the other transports. */ + } + /* If not found, go search all the other transports. */ list_for_each(pos, &asoc->peer.transport_addr_list) { transport = list_entry(pos, sctp_transport_t, transports); - if (transport == active) { break; } + if (transport == active) + break; list_for_each(entry, &transport->transmitted) { - - chunk = list_entry(entry, sctp_chunk_t, + chunk = list_entry(entry, sctp_chunk_t, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = transport; goto out; } - } /* for (all unacknowledged TSNs) */ - - } /* for (all transports) */ - + } + } out: return match; - -} /* sctp_assoc_lookup_tsn() */ +} /* Is this the association we are looking for? */ -sctp_transport_t * -sctp_assoc_is_match(sctp_association_t *asoc, const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr) +sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, + const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr) { sctp_transport_t *transport; @@ -905,87 +846,77 @@ sctp_assoc_is_match(sctp_association_t *asoc, const sockaddr_storage_t *laddr, if ((asoc->base.bind_addr.port == laddr->v4.sin_port) && (asoc->peer.port == paddr->v4.sin_port)) { - transport = sctp_assoc_lookup_paddr(asoc, paddr); - if (!transport) { goto out; } - - if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) { + if (!transport) + goto out; + + if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) goto out; - } - } transport = NULL; out: sctp_read_unlock(&asoc->base.addr_lock); return transport; - -} /* sctp_assoc_is_match() */ +} /* Do delayed input processing. This is scheduled by sctp_rcv(). */ -static void -sctp_assoc_bh_rcv(sctp_association_t *asoc) +static void sctp_assoc_bh_rcv(sctp_association_t *asoc) { - sctp_endpoint_t *ep; - sctp_chunk_t *chunk; + sctp_endpoint_t *ep; + sctp_chunk_t *chunk; struct sock *sk; - sctp_inqueue_t *inqueue; - int state, subtype; + sctp_inqueue_t *inqueue; + int state, subtype; sctp_assoc_t associd = sctp_assoc2id(asoc); - int error = 0; + int error = 0; /* The association should be held so we should be safe. */ - ep = asoc->ep; + ep = asoc->ep; sk = asoc->base.sk; - inqueue = &asoc->base.inqueue; - while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { - state = asoc->state; - subtype = chunk->chunk_hdr->type; + inqueue = &asoc->base.inqueue; + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + state = asoc->state; + subtype = chunk->chunk_hdr->type; /* Remember where the last DATA chunk came from so we * know where to send the SACK. */ - if (sctp_chunk_is_data(chunk)) { + if (sctp_chunk_is_data(chunk)) asoc->peer.last_data_from = chunk->transport; - } - if (chunk->transport) { + if (chunk->transport) chunk->transport->last_time_heard = jiffies; - } /* Run through the state machine. */ - error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), + error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), state, ep, asoc, chunk, GFP_ATOMIC); - /* Check to see if the association is freed in response to + /* Check to see if the association is freed in response to * the incoming chunk. If so, get out of the while loop. */ - if (!sctp_id2assoc(sk, associd)) { goto out; } - - if (error != 0) { goto err_out; } + if (!sctp_id2assoc(sk, associd)) + goto out; - } /* while (we have more chunks to receive) */ + if (error != 0) + goto err_out; + } err_out: - /* Is this the right way to pass errors up to the ULP? */ - if (error) { - sk->err = -error; - } - + /* Is this the right way to pass errors up to the ULP? */ + if (error) + sk->err = -error; out: - return; - -} /* sctp_bh_rcv_asoc() */ +} /* This routine moves an association from its old sk to a new sk. */ -void -sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) +void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) { sctp_opt_t *newsp = sctp_sk(newsk); /* Delete the association from the old endpoint's list of - * associations. + * associations. */ list_del(&assoc->asocs); @@ -1001,77 +932,68 @@ sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) assoc->base.sk = newsk; sock_hold(assoc->base.sk); - /* Add the association to the new endpoint's list of associations. */ + /* Add the association to the new endpoint's list of associations. */ sctp_endpoint_add_asoc(newsp->ep, assoc); - -} /* sctp_assoc_migrate() */ +} /* Update an association (possibly from unexpected COOKIE-ECHO processing). */ -void -sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) +void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) { int i; - + /* Copy in new parameters of peer. */ asoc->c = new->c; - asoc->peer.rwnd = new->peer.rwnd; + asoc->peer.rwnd = new->peer.rwnd; asoc->peer.next_dup_tsn = new->peer.next_dup_tsn; asoc->peer.sack_needed = new->peer.sack_needed; asoc->peer.i = new->peer.i; - sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, + sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, asoc->peer.i.initial_tsn); - + /* FIXME: * Do we need to copy primary_path etc? - * + * * More explicitly, addresses may have been removed and * this needs accounting for. */ - - + /* If the case is A (association restart), use * initial_tsn as next_tsn. If the case is B, use * current next_tsn in case there is data sent to peer * has been discarded and needs retransmission. */ - if (SCTP_STATE_ESTABLISHED == asoc->state){ + if (SCTP_STATE_ESTABLISHED == asoc->state) { asoc->next_tsn = new->next_tsn; - asoc->ctsn_ack_point = new->ctsn_ack_point; - + asoc->ctsn_ack_point = new->ctsn_ack_point; + /* Reinitialize SSN for both local streams * and peer's streams. */ - for(i=0; i < SCTP_MAX_STREAM; i++) { + for (i = 0; i < SCTP_MAX_STREAM; i++) { asoc->ssn[i] = 0; asoc->ulpq.ssn[i] = 0; - } - + } } else { - asoc->ctsn_ack_point = asoc->next_tsn-1; + asoc->ctsn_ack_point = asoc->next_tsn - 1; } - - return; +} -} /* sctp_assoc_update() */ - -/* Choose the transport for sending a shutdown packet. +/* Choose the transport for sending a shutdown packet. * Round-robin through the active transports, else round-robin * through the inactive transports as this is the next best thing - * we can try. + * we can try. */ -sctp_transport_t * -sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) { +sctp_transport_t *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +{ sctp_transport_t *t, *next; list_t *head = &asoc->peer.transport_addr_list; list_t *pos; - /* If this is the first time SHUTDOWN is sent, use the active * path. */ - if (!asoc->shutdown_last_sent_to) { + if (!asoc->shutdown_last_sent_to) return asoc->peer.active_path; - } /* Otherwise, find the next transport in a round-robin fashion. */ @@ -1080,33 +1002,30 @@ sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) { next = NULL; while (1) { - /* Skip the head. */ - if (pos->next == head) { + if (pos->next == head) pos = head->next; - } else { + else pos = pos->next; - } - + t = list_entry(pos, sctp_transport_t, transports); - + /* Try to find an active transport. */ if (t->state.active) { - break; + break; } else { /* Keep track of the next transport in case * we don't find any active transport. */ - if (!next) { + if (!next) next = t; - } } /* We have exhausted the list, but didn't find any * other active transports. If so, use the next - * transport. - */ + * transport. + */ if (t == asoc->shutdown_last_sent_to) { t = next; break; @@ -1114,5 +1033,4 @@ sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) { } return t; - -} /* sctp_assoc_choose_shutdown_transport() */ +} diff --git a/net/sctp/sctp_bind_addr.c b/net/sctp/sctp_bind_addr.c index be6d11202997..5cfa1af79664 100644 --- a/net/sctp/sctp_bind_addr.c +++ b/net/sctp/sctp_bind_addr.c @@ -46,7 +46,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_bind_addr.c,v 1.16 2002/07/12 15:15:45 jgrimm Exp $"; -#include #include #include #include @@ -57,7 +56,7 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_bind_addr.c,v 1.16 200 #include /* Forward declarations for internal helpers. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, +static int sctp_copy_one_addr(sctp_bind_addr_t *, sockaddr_storage_t *, sctp_scope_t scope, int priority, int flags); static void sctp_bind_addr_clean(sctp_bind_addr_t *); @@ -66,69 +65,62 @@ static void sctp_bind_addr_clean(sctp_bind_addr_t *); /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses * in 'src' which have a broader scope than 'scope'. */ -int -sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, - sctp_scope_t scope, int priority, int flags) +int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, + sctp_scope_t scope, int priority, int flags) { - int error = 0; struct sockaddr_storage_list *addr; list_t *pos; + int error = 0; /* All addresses share the same port. */ dest->port = src->port; /* Extract the addresses which are relevant for this scope. */ list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); - error = sctp_copy_one_addr(dest, &addr->a, scope, priority, - flags); - if (error < 0) { goto out; } - - } /* for (each address in the source bind_addr) */ - - out: - if (0 != error) { - sctp_bind_addr_clean(dest); + addr = list_entry(pos, struct sockaddr_storage_list, list); + error = sctp_copy_one_addr(dest, &addr->a, scope, + priority, flags); + if (error < 0) + goto out; } + +out: + if (error) + sctp_bind_addr_clean(dest); return error; - -} /* sctp_bind_addr_copy() */ +} /* Create a new SCTP_bind_addr from nothing. */ -sctp_bind_addr_t * -sctp_bind_addr_new(int priority) +sctp_bind_addr_t *sctp_bind_addr_new(int priority) { sctp_bind_addr_t *retval; retval = t_new(sctp_bind_addr_t, priority); - if (NULL == retval) { goto nomem; } + if (!retval) + goto nomem; sctp_bind_addr_init(retval, 0); retval->malloced = 1; SCTP_DBG_OBJCNT_INC(bind_addr); - nomem: - return retval; - -} /* sctp_bind_addr_new() */ +nomem: + return retval; +} /* Initialize the SCTP_bind_addr structure for either an endpoint or * an association. */ -void -sctp_bind_addr_init(sctp_bind_addr_t *bp, uint16_t port) +void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) { bp->malloced = 0; INIT_LIST_HEAD(&bp->address_list); bp->port = port; - -} /* sctp_bind_addr_init() */ +} /* Dispose of the address list. */ -static void -sctp_bind_addr_clean(sctp_bind_addr_t *bp) +static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) { struct sockaddr_storage_list *addr; list_t *pos, *temp; @@ -139,16 +131,12 @@ sctp_bind_addr_clean(sctp_bind_addr_t *bp) list_del(pos); kfree(addr); SCTP_DBG_OBJCNT_DEC(addr); - } /* for (each bound address) */ - -} /* sctp_bind_addr_clean() */ + } +} -/* Dispose of an SCTP_bind_addr structure - */ -void -sctp_bind_addr_free(sctp_bind_addr_t *bp) +/* Dispose of an SCTP_bind_addr structure */ +void sctp_bind_addr_free(sctp_bind_addr_t *bp) { - /* Empty the bind address list. */ sctp_bind_addr_clean(bp); @@ -156,48 +144,41 @@ sctp_bind_addr_free(sctp_bind_addr_t *bp) kfree(bp); SCTP_DBG_OBJCNT_DEC(bind_addr); } - -} /* sctp_bind_addr_free() */ +} /* Add an address to the bind address list in the SCTP_bind_addr structure. */ -int -sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, - int priority) +int sctp_add_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *new, + int priority) { - struct sockaddr_storage_list *addr; - - /* Add the address to the bind address list. */ - addr = t_new(struct sockaddr_storage_list, priority); - if (NULL == addr) { - return -ENOMEM; - } - - addr->a = *new; - - /* Fix up the port if it has not yet been set. + + /* Add the address to the bind address list. */ + addr = t_new(struct sockaddr_storage_list, priority); + if (!addr) + return -ENOMEM; + + addr->a = *new; + + /* Fix up the port if it has not yet been set. * Both v4 and v6 have the port at the same offset. */ - if (0 == addr->a.v4.sin_port) { + if (!addr->a.v4.sin_port) addr->a.v4.sin_port = bp->port; - } INIT_LIST_HEAD(&addr->list); list_add_tail(&addr->list, &bp->address_list); SCTP_DBG_OBJCNT_INC(addr); return 0; - -} /* sctp_add_bind_addr() */ +} /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int -sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) +int sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) { list_t *pos, *temp; - struct sockaddr_storage_list *addr; + struct sockaddr_storage_list *addr; list_for_each_safe(pos, temp, &bp->address_list) { addr = list_entry(pos, struct sockaddr_storage_list, list); @@ -206,29 +187,28 @@ sctp_del_bind_addr(sctp_bind_addr_t *bp, sockaddr_storage_t *del_addr) list_del(pos); kfree(addr); SCTP_DBG_OBJCNT_DEC(addr); + return 0; } - } /* for (each bound address) */ - - return -EINVAL; + } -} /* sctp_del_bind_addr() */ + return -EINVAL; +} /* Create a network byte-order representation of all the addresses * formated as SCTP parameters. * * The second argument is the return value for the length. */ -sctpParam_t -sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, - int priority) +sctpParam_t sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, + int priority) { - sctpParam_t rawaddr; + sctpParam_t rawaddr; sctpParam_t addrparms; sctpParam_t retval; int addrparms_len; - sctpIpAddress_t rawaddr_space; - int len; + sctpIpAddress_t rawaddr_space; + int len; struct sockaddr_storage_list *addr; list_t *pos; @@ -239,12 +219,13 @@ sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, /* Allocate enough memory at once. */ list_for_each(pos, &bp->address_list) { len += sizeof(sctp_ipv6addr_param_t); - } /* for (each bound address) */ + } - addrparms.v = kmalloc(len, priority); - if (NULL == addrparms.v) { goto end_raw; } - - retval = addrparms; + addrparms.v = kmalloc(len, priority); + if (!addrparms.v) + goto end_raw; + + retval = addrparms; rawaddr.v4 = &rawaddr_space.v4; list_for_each(pos, &bp->address_list) { @@ -253,35 +234,30 @@ sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, int *addrs_len, memcpy(addrparms.v, rawaddr.v, len); addrparms.v += len; addrparms_len += len; - } /* for (all addresses in the bind address list) */ - + } + end_raw: - - *addrs_len = addrparms_len; - return retval; - -} /* sctp_bind_addrs_to_raw() */ + *addrs_len = addrparms_len; + return retval; +} /* - * Create an address list out of the raw address list format (IPv4 and IPv6 - * address parameters). - * + * Create an address list out of the raw address list format (IPv4 and IPv6 + * address parameters). */ -int -sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, uint8_t *raw_addr_list, - int addrs_len, uint16_t port, int priority) +int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, + int addrs_len, __u16 port, int priority) { - sctpParam_t rawaddr; + sctpParam_t rawaddr; sockaddr_storage_t addr; int retval = 0; - int len; + int len; /* Convert the raw address to standard address format */ while (addrs_len) { rawaddr.v = raw_addr_list; - if (SCTP_PARAM_IPV4_ADDRESS==rawaddr.p->type + if (SCTP_PARAM_IPV4_ADDRESS==rawaddr.p->type || SCTP_PARAM_IPV6_ADDRESS==rawaddr.p->type) { - sctp_param2sockaddr(&addr, rawaddr, port); retval = sctp_add_bind_addr(bp, &addr, priority); if (retval) { @@ -300,288 +276,258 @@ sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, uint8_t *raw_addr_list, break; } } - + return retval; - -} /* sctp_raw_to_bind_addrs() */ +} /******************************************************************** * 2nd Level Abstractions ********************************************************************/ /* Does this contain a specified address? */ -int -sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) +int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const sockaddr_storage_t *addr) { - list_t *pos; - struct sockaddr_storage_list *laddr; - - list_for_each(pos, &bp->address_list) { - laddr = list_entry(pos, struct sockaddr_storage_list, list); - if (sctp_cmp_addr(&laddr->a, addr)) { + struct sockaddr_storage_list *laddr; + list_t *pos; + + list_for_each(pos, &bp->address_list) { + laddr = list_entry(pos, struct sockaddr_storage_list, list); + if (sctp_cmp_addr(&laddr->a, addr)) return 1; - } - } /* for (all bound addresses). */ - - return 0; - -} /* sctp_bind_addr_has_addr() */ + } + + return 0; +} /* Copy out addresses from the global local address list. */ -static int -sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, - sctp_scope_t scope, int priority, int flags) +static int sctp_copy_one_addr(sctp_bind_addr_t *dest, sockaddr_storage_t *addr, + sctp_scope_t scope, int priority, int flags) { sctp_protocol_t *proto = sctp_get_protocol(); int error = 0; if (sctp_is_any(addr)) { - error = sctp_copy_local_addr_list(proto, dest, scope, + error = sctp_copy_local_addr_list(proto, dest, scope, priority, flags); } else if (sctp_in_scope(addr, scope)) { /* Now that the address is in scope, check to see if * the address type is supported by local sock as * well as the remote peer. */ - if ((((AF_INET == addr->sa.sa_family) - && (flags & SCTP_ADDR4_PEERSUPP))) - || (((AF_INET6 == addr->sa.sa_family) - && (flags & SCTP_ADDR6_ALLOWED) - && (flags & SCTP_ADDR6_PEERSUPP)))) { - + if ((((AF_INET == addr->sa.sa_family) && + (flags & SCTP_ADDR4_PEERSUPP))) || + (((AF_INET6 == addr->sa.sa_family) && + (flags & SCTP_ADDR6_ALLOWED) && + (flags & SCTP_ADDR6_PEERSUPP)))) error = sctp_add_bind_addr(dest, addr, priority); - } } return error; - -} /* sctp_copy_one_addr() */ - +} /* Is addr one of the wildcards? */ -int -sctp_is_any(const sockaddr_storage_t *addr) +int sctp_is_any(const sockaddr_storage_t *addr) { int retval = 0; switch (addr->sa.sa_family) { case AF_INET: - if (INADDR_ANY == addr->v4.sin_addr.s_addr) { + if (INADDR_ANY == addr->v4.sin_addr.s_addr) retval = 1; - } break; + case AF_INET6: SCTP_V6( if (IPV6_ADDR_ANY == - sctp_ipv6_addr_type(&addr->v6.sin6_addr)) { + sctp_ipv6_addr_type(&addr->v6.sin6_addr)) retval = 1; - } ); break; + default: break; - } + }; return retval; - -} /* sctp_is_any() */ +} /* Is 'addr' valid for 'scope'? */ -int -sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) +int sctp_in_scope(const sockaddr_storage_t *addr, sctp_scope_t scope) { - sctp_scope_t addr_scope = sctp_scope(addr); switch (addr->sa.sa_family) { case AF_INET: /* According to the SCTP IPv4 address scoping document - - * , the scope has - * a heirarchy of 5 levels: + * , the scope has + * a heirarchy of 5 levels: * Level 0 - unusable SCTP addresses - * Level 1 - loopback address - * Level 2 - link-local addresses - * Level 3 - private addresses. - * Level 4 - global addresses - * For INIT and INIT-ACK address list, let L be the level of - * of requested destination address, sender and receiver + * Level 1 - loopback address + * Level 2 - link-local addresses + * Level 3 - private addresses. + * Level 4 - global addresses + * For INIT and INIT-ACK address list, let L be the level of + * of requested destination address, sender and receiver * SHOULD include all of its addresses with level greater - * than or equal to L. - */ + * than or equal to L. + */ /* The unusable SCTP addresses will not be considered with * any defined scopes. */ - if (SCTP_SCOPE_UNUSABLE == addr_scope) { - return 0 ; - } + if (SCTP_SCOPE_UNUSABLE == addr_scope) + return 0; /* Note that we are assuming that the scoping are the same * for both IPv4 addresses and IPv6 addresses, i.e., if the - * scope is link local, both IPv4 link local addresses and - * IPv6 link local addresses would be treated as in the + * scope is link local, both IPv4 link local addresses and + * IPv6 link local addresses would be treated as in the * scope. There is no filtering for IPv4 vs. IPv6 addresses * based on scoping alone. - */ - if (addr_scope <= scope) { + */ + if (addr_scope <= scope) return 1; - } break; case AF_INET6: - /* FIXME: * This is almost certainly wrong since scopes have an * heirarchy. I don't know what RFC to look at. * There may be some guidance in the SCTP implementors * guide (an Internet Draft as of October 2001). * - * Further verification on the correctness of the IPv6 + * Further verification on the correctness of the IPv6 * scoping is needed. According to the IPv6 scoping draft, - * the link local and site local address may require - * further scoping. + * the link local and site local address may require + * further scoping. * * Is the heirachy of the IPv6 scoping the same as what's - * defined for IPv4? - * If the same heirarchy indeed applies to both famiies, - * this function can be simplified with one set of code. + * defined for IPv4? + * If the same heirarchy indeed applies to both famiies, + * this function can be simplified with one set of code. * (see the comments for IPv4 above) - * */ - if (addr_scope <= scope) { + if (addr_scope <= scope) return 1; - } - break; - + default: return 0; - } + }; return 0; - -} /* sctp_in_scope() */ +} /******************************************************************** * 3rd Level Abstractions ********************************************************************/ /* What is the scope of 'addr'? */ -sctp_scope_t -sctp_scope(const sockaddr_storage_t *addr) +sctp_scope_t sctp_scope(const sockaddr_storage_t *addr) { - sctp_scope_t retval = SCTP_SCOPE_GLOBAL; switch (addr->sa.sa_family) { case AF_INET: /* We are checking the loopback, private and other address - * scopes as defined in RFC 1918. + * scopes as defined in RFC 1918. * The IPv4 scoping is based on the draft for SCTP IPv4 * scoping . * The set of SCTP address scope hopefully can cover both * types of addresses. */ - /* Should IPv4 scoping be a sysctl configurable option - * so users can turn it off (default on) for certain - * unconventional networking environments? + + /* Should IPv4 scoping be a sysctl configurable option + * so users can turn it off (default on) for certain + * unconventional networking environments? */ + /* Check for unusable SCTP addresses. */ if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { - retval = SCTP_SCOPE_UNUSABLE ; - + retval = SCTP_SCOPE_UNUSABLE; } else if (LOOPBACK(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_LOOPBACK; - } else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_LINK; - - } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)){ + } else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_PRIVATE; - } else { retval = SCTP_SCOPE_GLOBAL; - } - - break; case AF_INET6: - { + { SCTP_V6( int v6scope; v6scope = ipv6_addr_scope((struct in6_addr *) &addr->v6.sin6_addr); - /* The IPv6 scope is really a set of bit + /* The IPv6 scope is really a set of bit * fields. See IFA_* in . - * Mapping them to the generic SCTP scope - * set is an attempt to have code + * Mapping them to the generic SCTP scope + * set is an attempt to have code * consistencies with the IPv4 scoping. */ switch (v6scope) { case IFA_HOST: retval = SCTP_SCOPE_LOOPBACK; break; + case IFA_LINK: retval = SCTP_SCOPE_LINK; break; + case IFA_SITE: retval = SCTP_SCOPE_PRIVATE; break; + default: retval = SCTP_SCOPE_GLOBAL; - } + break; + }; ); - break; } default: retval = SCTP_SCOPE_GLOBAL; - } + break; + }; return retval; - -} /* sctp_scope() */ +} /* This function checks if the address is a valid address to be used for - * SCTP. + * SCTP. * * Output: - * Return 0 - If the address is a non-unicast or an illegal address. + * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -int -sctp_addr_is_valid(const sockaddr_storage_t *addr) +int sctp_addr_is_valid(const sockaddr_storage_t *addr) { unsigned short sa_family = addr->sa.sa_family; switch (sa_family) { case AF_INET: /* Is this a non-unicast address or a unusable SCTP address? */ - if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) { + if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) return 0; - } break; case AF_INET6: SCTP_V6( { - int ret; - - ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); + /* Is this a non-unicast address */ - if (!(ret & IPV6_ADDR_UNICAST)) { + if (!(ret & IPV6_ADDR_UNICAST)) return 0; - } break; }); + default: return 0; - } + }; return 1; - - -} /* sctp_addr_is_valid() */ - +} diff --git a/net/sctp/sctp_command.c b/net/sctp/sctp_command.c index cf41e09ffa95..a3f28edbcddf 100644 --- a/net/sctp/sctp_command.c +++ b/net/sctp/sctp_command.c @@ -42,82 +42,67 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_command.c,v 1.4 2002/04/24 16:33:39 jgrimm Exp $"; -#include #include #include #include /* Create a new sctp_command_sequence. */ -sctp_cmd_seq_t * -sctp_new_cmd_seq(int priority) +sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) { - sctp_cmd_seq_t *retval; - - 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 */ sctp_init_cmd_seq(retval); return retval; - -} /* sctp_new_cmd_seq() */ +} /* Initialize a block of memory as a command sequence. */ -int -sctp_init_cmd_seq(sctp_cmd_seq_t *seq) +int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) { memset(seq, 0, sizeof(sctp_cmd_seq_t)); return 1; /* We always succeed. */ - -} /* sctp_init_cmd_seq() */ +} /* Add a command to a sctp_cmd_seq_t. * Return 0 if the command sequence is full. */ -int -sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) { - if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS) { + if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS) goto fail; - } seq->cmds[seq->next_free_slot].verb = verb; seq->cmds[seq->next_free_slot++].obj = obj; return 1; - fail: - return 0; -} /* sctp_add_cmd() */ +fail: + return 0; +} /* Rewind an sctp_cmd_seq_t to iterate from the start. */ -int -sctp_rewind_sequence(sctp_cmd_seq_t *seq) +int sctp_rewind_sequence(sctp_cmd_seq_t *seq) { seq->next_cmd = 0; return 1; /* We always succeed. */ - -} /* sctp_rewind_sequence() */ +} /* Return the next command structure in a sctp_cmd_seq. * Returns NULL at the end of the sequence. */ -sctp_cmd_t * -sctp_next_cmd(sctp_cmd_seq_t *seq) +sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq) { sctp_cmd_t *retval = NULL; - if (seq->next_cmd < seq->next_free_slot) { + if (seq->next_cmd < seq->next_free_slot) retval = &seq->cmds[seq->next_cmd++]; - } return retval; - -} /* sctp_next_cmd() */ +} /* Dispose of a command sequence. */ -void -sctp_free_cmd_seq(sctp_cmd_seq_t *seq) +void sctp_free_cmd_seq(sctp_cmd_seq_t *seq) { kfree(seq); - -} /* sctp_free_cmd_seq() */ +} diff --git a/net/sctp/sctp_crc32c.c b/net/sctp/sctp_crc32c.c index fc9a9cc29873..300de0c0b5ec 100644 --- a/net/sctp/sctp_crc32c.c +++ b/net/sctp/sctp_crc32c.c @@ -46,128 +46,120 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_crc32c.c,v 1.9 2002/07 * * The code has now been modified specifically for SCTP knowledge. */ - #include #include + +#define CRC32C_POLY 0x1EDC6F41 +#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* Copyright 2001, D. Otis. Use this program, code or tables */ +/* extracted from it, as desired without restriction. */ +/* */ +/* 32 Bit Reflected CRC table generation for SCTP. */ +/* To accommodate serial byte data being shifted out least */ +/* significant bit first, the table's 32 bit words are reflected */ +/* which flips both byte and bit MS and LS positions. The CRC */ +/* is calculated MS bits first from the perspective of the serial*/ +/* stream. The x^32 term is implied and the x^0 term may also */ +/* be shown as +1. The polynomial code used is 0x1EDC6F41. */ +/* Castagnoli93 */ +/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ +/* x^11+x^10+x^9+x^8+x^6+x^0 */ +/* Guy Castagnoli Stefan Braeuer and Martin Herrman */ +/* "Optimization of Cyclic Redundancy-Check Codes */ +/* with 24 and 32 Parity Bits", */ +/* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +__u32 crc_c[256] = { + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, + 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, + 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, + 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, + 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, + 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, + 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, + 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, + 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, + 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, + 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, + 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, + 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, + 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, + 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, + 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, + 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, + 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, + 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, + 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, + 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, + 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, + 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, + 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, + 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, + 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, + 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, + 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, + 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, + 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, + 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, + 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, + 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, +}; -#define CRC32C_POLY 0x1EDC6F41 -#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -/* Copyright 2001, D. Otis. Use this program, code or tables */ -/* extracted from it, as desired without restriction. */ -/* */ -/* 32 Bit Reflected CRC table generation for SCTP. */ -/* To accommodate serial byte data being shifted out least */ -/* significant bit first, the table's 32 bit words are reflected */ -/* which flips both byte and bit MS and LS positions. The CRC */ -/* is calculated MS bits first from the perspective of the serial*/ -/* stream. The x^32 term is implied and the x^0 term may also */ -/* be shown as +1. The polynomial code used is 0x1EDC6F41. */ -/* Castagnoli93 */ -/* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ -/* x^11+x^10+x^9+x^8+x^6+x^0 */ -/* Guy Castagnoli Stefan Braeuer and Martin Herrman */ -/* "Optimization of Cyclic Redundancy-Check Codes */ -/* with 24 and 32 Parity Bits", */ -/* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -unsigned long crc_c[256] = -{ - 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, - 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, - 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, - 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, - 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, - 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, - 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, - 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, - 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, - 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, - 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, - 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, - 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, - 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, - 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, - 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, - 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, - 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, - 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, - 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, - 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, - 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, - 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, - 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, - 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, - 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, - 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, - 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, - 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, - 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, - 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, - 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, - 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, - 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, - 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, - 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, - 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, - 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, - 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, - 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, - 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, - 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, - 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, - 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, - 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, - 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, - 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, - 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, - 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, - 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, - 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, - 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, - 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, - 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, - 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, - 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, - 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, - 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, - 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, - 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, - 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, - 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, - 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, - 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, -}; - - - -uint32_t -count_crc(uint8_t *buffer, uint16_t length) -{ - unsigned int i; - unsigned long crc32 = ~0L; - unsigned long result; - unsigned char byte0, byte1, byte2, byte3; - +__u32 count_crc(__u8 *buffer, __u16 length) +{ + __u32 crc32 = ~(__u32) 0; + __u32 i, result; + __u8 byte0, byte1, byte2, byte3; + /* Optimize this routine to be SCTP specific, knowing how * to skip the checksum field of the SCTP header. */ /* Calculate CRC up to the checksum. */ - for (i = 0; i < (sizeof(struct sctphdr) - sizeof(uint32_t)); i++) { + for (i = 0; i < (sizeof(struct sctphdr) - sizeof(__u32)); i++) CRC32C(crc32, buffer[i]); - } + /* Skip checksum field of the header. */ - for (i = 0; i < sizeof(uint32_t); i++){ + for (i = 0; i < sizeof(__u32); i++) CRC32C(crc32, 0); - } /* Calculate the rest of the CRC. */ - for (i = sizeof(struct sctphdr); i < length ; i++){ + for (i = sizeof(struct sctphdr); i < length ; i++) CRC32C(crc32, buffer[i]); - } - + result = ~crc32; /* result now holds the negated polynomial remainder; @@ -175,25 +167,24 @@ count_crc(uint8_t *buffer, uint16_t length) * That is, result has the same value as if we mapped the message * to a polyomial, computed the host-bit-order polynomial * remainder, performed final negation, then did an end-for-end - * bit-reversal. + * bit-reversal. * Note that a 32-bit bit-reversal is identical to four inplace * 8-bit reversals followed by an end-for-end byteswap. * In other words, the bytes of each bit are in the right order, * but the bytes have been byteswapped. So we now do an explicit - * byteswap. On a little-endian machine, this byteswap and + * byteswap. On a little-endian machine, this byteswap and * the final ntohl cancel out and could be elided. */ byte0 = result & 0xff; byte1 = (result>>8) & 0xff; byte2 = (result>>16) & 0xff; byte3 = (result>>24) & 0xff; - + crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); - return(crc32); - -} /* count_crc() */ + return crc32; +} diff --git a/net/sctp/sctp_debug.c b/net/sctp/sctp_debug.c index 12ca661ad0c0..b90e0314a04f 100644 --- a/net/sctp/sctp_debug.c +++ b/net/sctp/sctp_debug.c @@ -57,7 +57,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_debug.c,v 1.10 2002/07 int sctp_debug_flag = 1; /* Initially enable DEBUG */ #endif /* SCTP_DEBUG */ - /* These are printable forms of Chunk ID's from section 3.1. */ static const char *sctp_cid_tbl[SCTP_NUM_BASE_CHUNK_TYPES] = { "DATA", @@ -75,33 +74,31 @@ static const char *sctp_cid_tbl[SCTP_NUM_BASE_CHUNK_TYPES] = { "ECN_ECNE", "ECN_CWR", "SHUTDOWN_COMPLETE", -}; /* char *sctp_cid_tbl[] */ +}; /* Lookup "chunk type" debug name. */ -const char * -sctp_cname(const sctp_subtype_t cid) +const char *sctp_cname(const sctp_subtype_t cid) { - if ( cid.chunk < 0 ) { + if (cid.chunk < 0) return "illegal chunk id"; - } - - if ( cid.chunk <= SCTP_CID_BASE_MAX ) { + if (cid.chunk <= SCTP_CID_BASE_MAX) return sctp_cid_tbl[cid.chunk]; - } - switch ( cid.chunk ) { - case SCTP_CID_ASCONF : return "ASCONF"; - case SCTP_CID_ASCONF_ACK : return "ASCONF_ACK"; + switch (cid.chunk) { + case SCTP_CID_ASCONF: + return "ASCONF"; + + case SCTP_CID_ASCONF_ACK: + return "ASCONF_ACK"; + default: return "unknown chunk"; - } - + }; return "unknown chunk"; +} -} /* sctp_cname() */ - /* These are printable form of variable-length parameters. */ -const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE+1] = { +const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = { "", "PARAM_HEATBEAT_INFO", "", @@ -115,8 +112,7 @@ const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE+1] = { "", "PARAM_HOST_NAME_ADDRESS", "PARAM_SUPPORTED_ADDRESS_TYPES", -}; /* char *sctp_param_tbl[] */ - +}; /* These are printable forms of the states. */ const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = { @@ -129,7 +125,7 @@ const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = { "STATE_SHUTDOWN_SENT", "STATE_SHUTDOWN_RECEIVED", "STATE_SHUTDOWN_ACK_SENT", -}; /* char *sctp_state_tbl[] */ +}; /* Events that could change the state of an association. */ const char *sctp_evttype_tbl[] = { @@ -174,20 +170,14 @@ static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = { }; /* Lookup primitive debug name. */ -const char * -sctp_pname(const sctp_subtype_t id) +const char *sctp_pname(const sctp_subtype_t id) { - if ( id.primitive < 0 ) { + if (id.primitive < 0) return "illegal primitive"; - } - - if ( id.primitive <= SCTP_EVENT_PRIMITIVE_MAX ) { + if (id.primitive <= SCTP_EVENT_PRIMITIVE_MAX) return sctp_primitive_tbl[id.primitive]; - } - return "unknown_primitive"; - -} /* sctp_pname() */ +} static const char *sctp_other_tbl[] = { "NO_PENDING_TSN", @@ -195,19 +185,14 @@ static const char *sctp_other_tbl[] = { }; /* Lookup "other" debug name. */ -const char * -sctp_oname(const sctp_subtype_t id) +const char *sctp_oname(const sctp_subtype_t id) { - if ( id.other < 0 ) { + if (id.other < 0) return "illegal 'other' event"; - } - - if ( id.other < SCTP_EVENT_OTHER_MAX ) { + if (id.other < SCTP_EVENT_OTHER_MAX) return sctp_other_tbl[id.other]; - } - return "unknown 'other' event"; -} /* sctp_oname() */ +} static const char *sctp_timer_tbl[] = { "TIMEOUT_NONE", @@ -223,19 +208,11 @@ static const char *sctp_timer_tbl[] = { }; /* Lookup timer debug name. */ -const char * -sctp_tname(const sctp_subtype_t id) +const char *sctp_tname(const sctp_subtype_t id) { - if ( id.timeout < 0 ) { + if (id.timeout < 0) return "illegal 'timer' event"; - } - - if ( id.timeout <= SCTP_EVENT_TIMEOUT_MAX ) { + if (id.timeout <= SCTP_EVENT_TIMEOUT_MAX) return sctp_timer_tbl[id.timeout]; - } - return "unknown_timer"; - -} /* sctp_tname() */ - - +} diff --git a/net/sctp/sctp_endpointola.c b/net/sctp/sctp_endpointola.c index 16799bcc5970..1c49ef90ef1e 100644 --- a/net/sctp/sctp_endpointola.c +++ b/net/sctp/sctp_endpointola.c @@ -52,7 +52,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_endpointola.c,v 1.26 2002/08/16 19:30:49 jgrimm Exp $"; -#include #include #include #include @@ -63,28 +62,23 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_endpointola.c,v 1.26 2 #include #include - /* Forward declarations for internal helpers. */ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); - -/* Create a sctp_endpoint_t with all that boring stuff initialized. +/* Create a sctp_endpoint_t with all that boring stuff initialized. * Returns NULL if there isn't enough memory. */ -sctp_endpoint_t * -sctp_endpoint_new(sctp_protocol_t *proto, struct sock *sk, int priority) +sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, + struct sock *sk, int priority) { - sctp_endpoint_t *ep; - - /* Build a local endpoint. */ - ep = t_new(sctp_endpoint_t, priority); - if (NULL == ep) { - goto fail; - } + sctp_endpoint_t *ep; - if (NULL == sctp_endpoint_init(ep, proto, sk, priority)) { + /* Build a local endpoint. */ + ep = t_new(sctp_endpoint_t, priority); + if (!ep) + goto fail; + if (!sctp_endpoint_init(ep, proto, sk, priority)) goto fail_init; - } ep->base.malloced = 1; SCTP_DBG_OBJCNT_INC(ep); return ep; @@ -93,22 +87,18 @@ fail_init: kfree(ep); fail: return NULL; +} -} /* sctp_endpoint_new() */ - - -/* - * Initialize the base fields of the endpoint structure. +/* + * Initialize the base fields of the endpoint structure. */ -sctp_endpoint_t * -sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, - struct sock *sk, int priority) +sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, + struct sock *sk, int priority) { - - memset(ep, 0, sizeof(sctp_endpoint_t)); + memset(ep, 0, sizeof(sctp_endpoint_t)); /* Initialize the base structure. */ - /* What type of endpoint are we? */ + /* What type of endpoint are we? */ ep->base.type = SCTP_EP_TYPE_SOCKET; /* Initialize the basic object fields. */ @@ -116,52 +106,53 @@ sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ep->base.dead = 0; ep->base.malloced = 1; - /* Create an input queue. */ - sctp_inqueue_init(&ep->base.inqueue); + /* Create an input queue. */ + sctp_inqueue_init(&ep->base.inqueue); - /* Set its top-half handler */ - sctp_inqueue_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, + /* Set its top-half handler */ + sctp_inqueue_set_th_handler(&ep->base.inqueue, + (void (*)(void *))sctp_endpoint_bh_rcv, ep); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); ep->base.addr_lock = RW_LOCK_UNLOCKED; - /* Remember who we are attached to. */ - ep->base.sk = sk; + /* Remember who we are attached to. */ + ep->base.sk = sk; sock_hold(ep->base.sk); - /* This pointer is useful to access the default protocol parameter + /* This pointer is useful to access the default protocol parameter * values. */ ep->proto = proto; - /* Create the lists of associations. */ + /* Create the lists of associations. */ INIT_LIST_HEAD(&ep->asocs); - /* Set up the base timeout information. */ - ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] + /* Set up the base timeout information. */ + ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = SCTP_DEFAULT_TIMEOUT_T1_INIT; - ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = sctp_sk(sk)->rtoinfo.srto_initial; - ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] + ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = SCTP_DEFAULT_TIMEOUT_SACK; - ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sctp_sk(sk)->autoclose * HZ; - ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] + ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] = SCTP_DEFAULT_TIMEOUT_PMTU_RAISE; /* Set up the default send/receive buffer space. */ - /* FIXME - Should the min and max window size be configurable - * sysctl parameters as opposed to be constants? + + /* FIXME - Should the min and max window size be configurable + * sysctl parameters as opposed to be constants? */ sk->rcvbuf = SCTP_DEFAULT_MAXWINDOW; sk->sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; @@ -170,96 +161,77 @@ sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, sk->write_space = sctp_write_space; sk->use_write_queue = 1; - /* Initialize the secret key used with cookie. */ + /* Initialize the secret key used with cookie. */ get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); - ep->last_key = ep->current_key = 0; - ep->key_changed_at = jiffies; - - ep->debug_name = "unnamedEndpoint"; + ep->last_key = ep->current_key = 0; + ep->key_changed_at = jiffies; + ep->debug_name = "unnamedEndpoint"; return ep; +} -} /* sctp_endpoint_init() */ - - -/* Add an association to an endpoint. - */ -void -sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +/* Add an association to an endpoint. */ +void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) { /* Now just add it to our list of asocs */ list_add_tail(&asoc->asocs, &ep->asocs); +} -} /* sctp_endpoint_add_asoc() */ - - -/* Free the endpoint structure. Delay cleanup until +/* Free the endpoint structure. Delay cleanup until * all users have released their reference count on this structure. */ -void -sctp_endpoint_free(sctp_endpoint_t *ep) -{ - ep->base.dead = 1; +void sctp_endpoint_free(sctp_endpoint_t *ep) +{ + ep->base.dead = 1; sctp_endpoint_put(ep); +} -} /* sctp_free_endpoint() */ - -/* Final destructor for endpoint. */ +/* Final destructor for endpoint. */ void sctp_endpoint_destroy(sctp_endpoint_t *ep) { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); - /* Unlink this endpoint, so we can't find it again! */ + /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); - /* Cleanup the inqueue. */ + /* Cleanup the inqueue. */ sctp_inqueue_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); - /* Remove and free the port */ - if (ep->base.sk->prev != NULL) { + /* Remove and free the port */ + if (ep->base.sk->prev != NULL) sctp_put_port(ep->base.sk); - } /* Give up our hold on the sock. */ - if (ep->base.sk) { + if (ep->base.sk) sock_put(ep->base.sk); - } - - /* Finally, free up our memory. */ - if (ep->base.malloced) { + + /* Finally, free up our memory. */ + if (ep->base.malloced) { kfree(ep); SCTP_DBG_OBJCNT_DEC(ep); } - return; - -} /* sctp_endpoint_destroy() */ - +} /* Hold a reference to an endpoint. */ void sctp_endpoint_hold(sctp_endpoint_t *ep) { atomic_inc(&ep->base.refcnt); - -} /* sctp_endpoint_hold() */ - +} /* Release a reference to an endpoint and clean up if there are - * no more references. + * no more references. */ void sctp_endpoint_put(sctp_endpoint_t *ep) { - if (atomic_dec_and_test(&ep->base.refcnt)) { + if (atomic_dec_and_test(&ep->base.refcnt)) sctp_endpoint_destroy(ep); - } +} -} /* sctp_endpoint_put() */ - - -/* Is this the endpoint we are looking for? */ -sctp_endpoint_t * -sctp_endpoint_is_match(sctp_endpoint_t *ep, const sockaddr_storage_t *laddr) +/* Is this the endpoint we are looking for? */ +sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, + const sockaddr_storage_t *laddr) { sctp_endpoint_t *retval; @@ -268,58 +240,50 @@ sctp_endpoint_is_match(sctp_endpoint_t *ep, const sockaddr_storage_t *laddr) if (sctp_bind_addr_has_addr(&ep->base.bind_addr, laddr)) { retval = ep; goto out; - } - } - + } + } + retval = NULL; - + out: sctp_read_unlock(&ep->base.addr_lock); return retval; - -} /* sctp_endpoint_is_match() */ +} /* Find the association that goes with this chunk. * We do a linear search of the associations for this endpoint. * We return the matching transport address too. */ - - -sctp_association_t * -__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, - const sockaddr_storage_t *paddr, - sctp_transport_t **transport) +sctp_association_t *__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) { - int rport; - sctp_association_t *asoc; + int rport; + sctp_association_t *asoc; list_t *pos; - - rport = paddr->v4.sin_port; - + + rport = paddr->v4.sin_port; + list_for_each(pos, &endpoint->asocs) { asoc = list_entry(pos, sctp_association_t, asocs); if (rport == asoc->peer.port) { - sctp_read_lock(&asoc->base.addr_lock); *transport = sctp_assoc_lookup_paddr(asoc, paddr); sctp_read_unlock(&asoc->base.addr_lock); - if (*transport) { + if (*transport) return asoc; - } } - } /* for (all associations on endpoint) */ + } *transport = NULL; - return NULL; - -} /* __sctp_endpoint_lookup_assoc() */ + return NULL; +} -/* Lookup association on an endpoint based on a peer address. BH-safe. */ -sctp_association_t * -sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const sockaddr_storage_t *paddr, - sctp_transport_t **transport) +/* Lookup association on an endpoint based on a peer address. BH-safe. */ +sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, + const sockaddr_storage_t *paddr, + sctp_transport_t **transport) { sctp_association_t *asoc; @@ -328,89 +292,80 @@ sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_local_bh_enable(); return asoc; +} -} /* sctp_endpoint_lookup_assoc() */ - - - -/* Do delayed input processing. This is scheduled by sctp_rcv(). - * This may be called on BH or task time. +/* Do delayed input processing. This is scheduled by sctp_rcv(). + * This may be called on BH or task time. */ -static void -sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) { - sctp_association_t *asoc; + sctp_association_t *asoc; struct sock *sk; sctp_transport_t *transport; - sctp_chunk_t *chunk; - sctp_inqueue_t *inqueue; + sctp_chunk_t *chunk; + sctp_inqueue_t *inqueue; sctp_subtype_t subtype; - sctp_state_t state; - int error = 0; + sctp_state_t state; + int error = 0; - if (ep->base.dead) { goto out; } + if (ep->base.dead) + goto out; asoc = NULL; - inqueue = &ep->base.inqueue; + inqueue = &ep->base.inqueue; sk = ep->base.sk; - while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { - subtype.chunk = chunk->chunk_hdr->type; + while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { + subtype.chunk = chunk->chunk_hdr->type; /* We might have grown an association since last we * looked, so try again. * * This happens when we've just processed our - * COOKIE-ECHO chunk. + * COOKIE-ECHO chunk. */ if (NULL == chunk->asoc) { asoc = sctp_endpoint_lookup_assoc(ep, sctp_source(chunk), - &transport); + &transport); chunk->asoc = asoc; chunk->transport = transport; - } - - state = asoc ? asoc->state : SCTP_STATE_CLOSED; - + } + + state = asoc ? asoc->state : SCTP_STATE_CLOSED; + /* Remember where the last DATA chunk came from so we * know where to send the SACK. */ - if ( asoc != NULL && sctp_chunk_is_data(chunk) ) { - asoc->peer.last_data_from = - chunk->transport; - } + if (asoc && sctp_chunk_is_data(chunk)) + asoc->peer.last_data_from = chunk->transport; - if (chunk->transport) { + if (chunk->transport) chunk->transport->last_time_heard = jiffies; - } - - /* FIX ME We really would rather NOT have to use - * GFP_ATOMIC. - */ + /* FIX ME We really would rather NOT have to use + * GFP_ATOMIC. + */ error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state, ep, asoc, chunk, GFP_ATOMIC); + if (error != 0) + goto err_out; - if (error != 0) { goto err_out; } - /* Check to see if the endpoint is freed in response to * the incoming chunk. If so, get out of the while loop. */ - if (NULL == sctp_sk(sk)->ep) { goto out; } - - } /* while (we have more chunks to receive) */ + if (!sctp_sk(sk)->ep) + goto out; + } err_out: - /* Is this the right way to pass errors up to the ULP? */ - if (error) { - ep->base.sk->err = -error; - } -out: - return; + /* Is this the right way to pass errors up to the ULP? */ + if (error) + ep->base.sk->err = -error; -} /* sctp_bh_rcv_ep() */ +out: +} diff --git a/net/sctp/sctp_hashdriver.c b/net/sctp/sctp_hashdriver.c index f42a06ab8c85..6f2a4d00eef7 100644 --- a/net/sctp/sctp_hashdriver.c +++ b/net/sctp/sctp_hashdriver.c @@ -44,92 +44,86 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_hashdriver.c,v 1.2 200 #include #include - /* SCTP Main driver. - passing a two pointers and two lengths, - returning a digest pointer filled. The md5 code - was taken directly from the RFC (2104) so to understand it - you may want to go look at the RFC referenced in the - SCTP spec. We did modify this code to either user OUR - implementation of SLA1 or the MD5 that comes from its - RFC. SLA1 may have IPR issues so you need to check in - to this if you wish to use it... Or at least that is - what the FIP-180.1 web page says. + * passing a two pointers and two lengths, + * returning a digest pointer filled. The md5 code + * was taken directly from the RFC (2104) so to understand it + * you may want to go look at the RFC referenced in the + * SCTP spec. We did modify this code to either user OUR + * implementation of SLA1 or the MD5 that comes from its + * RFC. SLA1 may have IPR issues so you need to check in + * to this if you wish to use it... Or at least that is + * what the FIP-180.1 web page says. */ -void -sctp_hash_digest(const char *key, const int in_key_len, - const char *text, const int text_len, - uint8_t *digest) +void sctp_hash_digest(const char *key, const int in_key_len, + const char *text, const int text_len, + __u8 *digest) { int key_len = in_key_len; - unsigned long *p; - struct SLA_1_Context context; + struct SLA_1_Context context; - uint8_t k_ipad[65]; /* inner padding - - * key XORd with ipad - */ - uint8_t k_opad[65]; /* outer padding - - * key XORd with opad - */ - uint8_t tk[20]; - int i; - /* if key is longer than 64 bytes reset it to key=MD5(key) */ - if (key_len > 64) { - struct SLA_1_Context tctx; - SLA1_Init(&tctx); - SLA1_Process(&tctx, key, key_len); - SLA1_Final(&tctx,tk); - key = tk; - key_len = 20; - } - - /* - * the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected - */ + __u8 k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + __u8 k_opad[65]; /* outer padding - + * key XORd with opad + */ + __u8 tk[20]; + int i; - /* start out by storing key in pads */ - memset( k_ipad, 0, sizeof k_ipad); - memset( k_opad, 0, sizeof k_opad); - memcpy( k_ipad, key, key_len); - memcpy( k_opad, key, key_len); + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + struct SLA_1_Context tctx; - /* XOR key with ipad and opad values */ - for (i=0; i<64; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; + SLA1_Init(&tctx); + SLA1_Process(&tctx, key, key_len); + SLA1_Final(&tctx,tk); + key = tk; + key_len = 20; } - /* - * perform inner hash - */ - SLA1_Init(&context); /* init context for 1st - * pass - */ - SLA1_Process(&context, k_ipad, 64); /* start with inner pad */ - SLA1_Process(&context, text, text_len); /* then text of datagram */ - SLA1_Final(&context,digest); /* finish up 1st pass */ + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ - /* + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof k_ipad); + memset(k_opad, 0, sizeof k_opad); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner hash */ + SLA1_Init(&context); /* init context for 1st + * pass + */ + SLA1_Process(&context, k_ipad, 64); /* start with inner pad */ + SLA1_Process(&context, text, text_len); /* then text of datagram */ + SLA1_Final(&context,digest); /* finish up 1st pass */ + + /* * perform outer hash */ - - SLA1_Init(&context); /* init context for 2nd - * pass - */ - SLA1_Process(&context, k_opad, 64); /* start with outer pad */ - SLA1_Process(&context, digest, 20); /* then results of 1st - * hash - */ - SLA1_Final(&context, digest); /* finish up 2nd pass */ - - p = (unsigned long *)digest; + SLA1_Init(&context); /* init context for 2nd + * pass + */ + SLA1_Process(&context, k_opad, 64); /* start with outer pad */ + SLA1_Process(&context, digest, 20); /* then results of 1st + * hash + */ + SLA1_Final(&context, digest); /* finish up 2nd pass */ } diff --git a/net/sctp/sctp_input.c b/net/sctp/sctp_input.c index 996e81abd85b..77ec39d85ae4 100644 --- a/net/sctp/sctp_input.c +++ b/net/sctp/sctp_input.c @@ -49,7 +49,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_input.c,v 1.24 2002/07/24 12:26:20 jgrimm Exp $"; -#include #include #include /* For struct list_head */ #include @@ -61,38 +60,36 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_input.c,v 1.24 2002/07 #include /* Forward declarations for internal helpers. */ -static inline int sctp_rcv_checksum(struct sk_buff *skb); static int sctp_rcv_ootb(struct sk_buff *); -sctp_association_t * -__sctp_rcv_lookup(struct sk_buff *skb, const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr, - sctp_transport_t **transportp); -sctp_endpoint_t * -__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); - +sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, + const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp); +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr); /* Initialize a sockaddr_storage from in incoming skb. * FIXME: This belongs with AF specific sctp_func_t. --jgrimm */ -static sockaddr_storage_t * -sctp_sockaddr_storage_init(sockaddr_storage_t *addr, const struct sk_buff *skb, - int is_saddr) +static sockaddr_storage_t *sctp_sockaddr_storage_init(sockaddr_storage_t *addr, + const struct sk_buff *skb, + int is_saddr) { - sockaddr_storage_t *ret=NULL; + sockaddr_storage_t *ret = NULL; void *to, *saddr, *daddr; - uint16_t *port; + __u16 *port; size_t len; struct sctphdr *sh; - switch (skb->nh.iph->version){ + switch (skb->nh.iph->version) { case 4: to = &addr->v4.sin_addr.s_addr; port = &addr->v4.sin_port; saddr = &skb->nh.iph->saddr; daddr = &skb->nh.iph->daddr; len = sizeof(struct in_addr); - addr->v4.sin_family = AF_INET; + addr->v4.sin_family = AF_INET; break; + case 6: SCTP_V6( to = &addr->v6.sin6_addr; @@ -105,12 +102,12 @@ sctp_sockaddr_storage_init(sockaddr_storage_t *addr, const struct sk_buff *skb, addr->v6.sin6_scope_id = 0; /* FIXME */ break; ) + default: goto out; - } - - sh = (struct sctphdr *)skb->h.raw; + }; + sh = (struct sctphdr *) skb->h.raw; if (is_saddr) { *port = ntohs(sh->source); memcpy(to, saddr, len); @@ -118,95 +115,100 @@ sctp_sockaddr_storage_init(sockaddr_storage_t *addr, const struct sk_buff *skb, *port = ntohs(sh->dest); memcpy(to, daddr, len); } - + ret = addr; out: return ret; - -} /* sctp_sockaddr_storage_init() */ +} + +/* Calculate the SCTP checksum of an SCTP packet. */ +static inline int sctp_rcv_checksum(struct sk_buff *skb) +{ + struct sctphdr *sh; + __u32 cmp, val; + + sh = (struct sctphdr *) skb->h.raw; + cmp = ntohl(sh->checksum); + val = count_crc((__u8 *)sh, skb->len); + if (val != cmp) { + /* CRC failure, dump it. */ + return -1; + } + return 0; +} /* * This is the routine which IP calls when receiving an SCTP packet. */ -int -sctp_rcv(struct sk_buff *skb) +int sctp_rcv(struct sk_buff *skb) { struct sock *sk; - sctp_association_t *asoc; + sctp_association_t *asoc; sctp_endpoint_t *ep = NULL; sctp_endpoint_common_t *rcvr; - sctp_transport_t *transport = NULL; - sctp_chunk_t *chunk; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk; struct sctphdr *sh; sockaddr_storage_t src; sockaddr_storage_t dest; - int ret = 0; + int ret = 0; - if (skb->pkt_type!=PACKET_HOST) { + if (skb->pkt_type!=PACKET_HOST) goto discard_it; - } - sh = (struct sctphdr *)skb->h.raw; + sh = (struct sctphdr *) skb->h.raw; /* Pull up the IP and SCTP headers. */ __skb_pull(skb, skb->h.raw - skb->data); - - if (skb->len < sizeof(struct sctphdr)) { + if (skb->len < sizeof(struct sctphdr)) goto bad_packet; - } - - if (sctp_rcv_checksum(skb) < 0) { + if (sctp_rcv_checksum(skb) < 0) goto bad_packet; - } - - skb_pull(skb, sizeof(struct sctphdr)); + + skb_pull(skb, sizeof(struct sctphdr)); sctp_sockaddr_storage_init(&src, skb, 1); sctp_sockaddr_storage_init(&dest, skb, 0); - + /* If the packet is to or from a non-unicast address, * silently discard the packet. * * This is not clearly defined in the RFC except in section - * 8.4 - OOTB handling. However, based on the book "Stream Control - * Transmission Protocol" 2.1, "It is important to note that the + * 8.4 - OOTB handling. However, based on the book "Stream Control + * Transmission Protocol" 2.1, "It is important to note that the * IP address of an SCTP transport address must be a routable * unicast address. In other words, IP multicast addresses and * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) { + if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest)) goto discard_it; - } asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); - /* + /* * RFC 2960, 8.4 - Handle "Out of the blue" Packets. - * An SCTP packet is called an "out of the blue" (OOTB) - * packet if it is correctly formed, i.e., passed the - * receiver's checksum check, but the receiver is not - * able to identify the association to which this - * packet belongs. + * An SCTP packet is called an "out of the blue" (OOTB) + * packet if it is correctly formed, i.e., passed the + * receiver's checksum check, but the receiver is not + * able to identify the association to which this + * packet belongs. */ - if (!asoc) { + if (!asoc) { ep = __sctp_rcv_lookup_endpoint(&dest); - if (sctp_rcv_ootb(skb)) { + if (sctp_rcv_ootb(skb)) goto discard_release; - } } /* Retrieve the common input handling substructure. */ rcvr = asoc ? &asoc->base : &ep->base; sk = rcvr->sk; - if (!ipsec_sk_policy(sk, skb)) { + if (!ipsec_sk_policy(sk, skb)) goto discard_release; - } - /* Create an SCTP packet structure. */ + /* Create an SCTP packet structure. */ chunk = sctp_chunkify(skb, asoc, sk); - if (!chunk) { ret = -ENOMEM; goto discard_release; @@ -215,9 +217,9 @@ sctp_rcv(struct sk_buff *skb) /* Remember what endpoint is to handle this packet. */ chunk->rcvr = rcvr; - /* Remember the SCTP header. */ - chunk->sctp_hdr = sh; - + /* Remember the SCTP header. */ + chunk->sctp_hdr = sh; + /* Set the source address. */ sctp_init_source(chunk); @@ -230,32 +232,32 @@ sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); - if (__sctp_sock_busy(sk)) { - sk_add_backlog(sk, (struct sk_buff *)chunk); + if (__sctp_sock_busy(sk)) { + sk_add_backlog(sk, (struct sk_buff *) chunk); } else { - sctp_backlog_rcv(sk, (struct sk_buff *)chunk); + sctp_backlog_rcv(sk, (struct sk_buff *) chunk); } - /* Release the sock and any reference counts we took in the + /* Release the sock and any reference counts we took in the * lookup calls. */ - sctp_bh_unlock_sock(sk); + sctp_bh_unlock_sock(sk); if (asoc) { sctp_association_put(asoc); } else { - sctp_endpoint_put(ep); + sctp_endpoint_put(ep); } sock_put(sk); - return ret; + return ret; bad_packet: #if 0 /* FIXME */ SCTP_INC_STATS(SctpInErrs); #endif /* FIXME*/ - + discard_it: kfree_skb(skb); - return ret; + return ret; discard_release: /* Release any structures we may be holding. */ @@ -264,20 +266,18 @@ discard_release: sctp_association_put(asoc); } else { sock_put(ep->base.sk); - sctp_endpoint_put(ep); + sctp_endpoint_put(ep); } - - goto discard_it; -} /* sctp_rcv() */ + goto discard_it; +} /* Handle second half of inbound skb processing. If the sock was busy, * we may have need to delay processing until later when the sock is - * released (on the backlog). If not busy, we call this routine - * directly from the bottom half. + * released (on the backlog). If not busy, we call this routine + * directly from the bottom half. */ -int -sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { sctp_chunk_t *chunk; sctp_inqueue_t *inqueue; @@ -285,14 +285,12 @@ sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) /* One day chunk will live inside the skb, but for * now this works. */ - chunk = (sctp_chunk_t *)skb; + chunk = (sctp_chunk_t *) skb; inqueue = &chunk->rcvr->inqueue; sctp_push_inqueue(inqueue, chunk); - return 0; - -} /* sctp_backlog_rcv() */ +} /* * This routine is called by the ICMP module when it gets some @@ -309,32 +307,10 @@ 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(). */ -} /* void sctp_v4_err(struct sk_buff *skb, u32 info) */ - - -/* Calculate the SCTP checksum of an SCTP packet. */ -static inline int -sctp_rcv_checksum(struct sk_buff *skb) -{ - uint32_t cmp,val; - struct sctphdr *sh; - - sh = (struct sctphdr *)skb->h.raw; - cmp = ntohl(sh->checksum); - val = count_crc((uint8_t *)sh, skb->len); - if (val != cmp) { - /* CRC failure, dump it. */ - return -1; - } - return 0; - -} /* sctp_rcv_checksum() */ - - + /* This should probably involve a call to SCTPhandleICMP(). */ +} /* * RFC 2960, 8.4 - Handle "Out of the blue" Packets. @@ -348,85 +324,73 @@ sctp_rcv_checksum(struct sk_buff *skb) * Return 0 - If further processing is needed. * Return 1 - If the packet can be discarded right away. */ -int -sctp_rcv_ootb(struct sk_buff *skb) +int sctp_rcv_ootb(struct sk_buff *skb) { sctp_chunkhdr_t *ch; - uint8_t *ch_end; + __u8 *ch_end; - ch = (sctp_chunkhdr_t *)skb->data; + ch = (sctp_chunkhdr_t *) skb->data; /* Scan through all the chunks in the packet. */ do { - ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); + ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); - /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the - * receiver MUST silently discard the OOTB packet and take no + /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the + * receiver MUST silently discard the OOTB packet and take no * further action. */ - - if (SCTP_CID_ABORT == ch->type) { + if (SCTP_CID_ABORT == ch->type) goto discard; - } - - /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE - * chunk, the receiver should silently discard the packet + + /* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE + * chunk, the receiver should silently discard the packet * and take no further action. */ - - if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE) { + if (ch->type == SCTP_CID_SHUTDOWN_COMPLETE) 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) { + /* 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) goto discard; - } if (ch->type == SCTP_CID_ERROR) { /* FIXME - Need to check the "Stale cookie" ERROR. */ goto discard; } - ch = (sctp_chunkhdr_t *)ch_end; - + ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb->tail); return 0; - + discard: return 1; - -} /* sctp_rcv_ootb() */ - +} /* Insert endpoint into the hash table. */ void __sctp_hash_endpoint(sctp_endpoint_t *ep) { sctp_endpoint_common_t **epp; sctp_endpoint_common_t *epb; - sctp_hashbucket_t *head; - + sctp_hashbucket_t *head; + epb = &ep->base; - + epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); head = &sctp_proto.ep_hashbucket[epb->hashent]; - + sctp_write_lock(&head->lock); epp = &head->chain; epb->next = *epp; - if (epb->next) { + if (epb->next) (*epp)->pprev = &epb->next; - } *epp = epb; epb->pprev = epp; sctp_write_unlock(&head->lock); - -} /* __sctp_hash_endpoint() */ +} /* Add an endpoint to the hash. Local BH-safe. */ void sctp_hash_endpoint(sctp_endpoint_t *ep) @@ -434,9 +398,7 @@ void sctp_hash_endpoint(sctp_endpoint_t *ep) sctp_local_bh_disable(); __sctp_hash_endpoint(ep); sctp_local_bh_enable(); - -} /* __sctp_hash_endpoint() */ - +} /* Remove endpoint from the hash table. */ void __sctp_unhash_endpoint(sctp_endpoint_t *ep) @@ -447,22 +409,20 @@ void __sctp_unhash_endpoint(sctp_endpoint_t *ep) epb = &ep->base; epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); - + head = &sctp_proto.ep_hashbucket[epb->hashent]; sctp_write_lock(&head->lock); if (epb->pprev) { - if (epb->next) { + if (epb->next) epb->next->pprev = epb->pprev; - } *epb->pprev = epb->next; epb->pprev = NULL; } sctp_write_unlock(&head->lock); - -} /* __sctp_unhash_endpoint() */ +} /* Remove endpoint from the hash. Local BH-safe. */ void sctp_unhash_endpoint(sctp_endpoint_t *ep) @@ -470,13 +430,10 @@ void sctp_unhash_endpoint(sctp_endpoint_t *ep) sctp_local_bh_disable(); __sctp_unhash_endpoint(ep); sctp_local_bh_enable(); - -} /* sctp_unhash_endpoint() */ - +} /* Look up an endpoint. */ -sctp_endpoint_t * -__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) +sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) { sctp_hashbucket_t *head; sctp_endpoint_common_t *epb; @@ -488,20 +445,19 @@ __sctp_rcv_lookup_endpoint(const sockaddr_storage_t *laddr) read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { ep = sctp_ep(epb); - if (sctp_endpoint_is_match(ep, laddr)) { goto hit; } - } - + if (sctp_endpoint_is_match(ep, laddr)) + goto hit; + } + ep = sctp_sk((sctp_get_ctl_sock()))->ep; epb = &ep->base; -hit: +hit: sctp_endpoint_hold(ep); sock_hold(epb->sk); read_unlock(&head->lock); return ep; - -} /* __sctp_rcv_lookup_endpoint() */ - +} /* Add an association to the hash. Local BH-safe. */ void sctp_hash_established(sctp_association_t *asoc) @@ -509,8 +465,7 @@ void sctp_hash_established(sctp_association_t *asoc) sctp_local_bh_disable(); __sctp_hash_established(asoc); sctp_local_bh_enable(); - -} /* sctp_hash_association() */ +} /* Insert association into the hash table. */ void __sctp_hash_established(sctp_association_t *asoc) @@ -518,25 +473,23 @@ void __sctp_hash_established(sctp_association_t *asoc) sctp_endpoint_common_t **epp; sctp_endpoint_common_t *epb; sctp_hashbucket_t *head; - + epb = &asoc->base; /* Calculate which chain this entry will belong to. */ epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); - + head = &sctp_proto.assoc_hashbucket[epb->hashent]; - + sctp_write_lock(&head->lock); epp = &head->chain; epb->next = *epp; - if (epb->next) { + if (epb->next) (*epp)->pprev = &epb->next; - } *epp = epb; epb->pprev = epp; sctp_write_unlock(&head->lock); - -} /* __sctp_hash_established() */ +} /* Remove association from the hash table. Local BH-safe. */ void sctp_unhash_established(sctp_association_t *asoc) @@ -544,9 +497,8 @@ void sctp_unhash_established(sctp_association_t *asoc) sctp_local_bh_disable(); __sctp_unhash_established(asoc); sctp_local_bh_enable(); +} -} /* sctp_unhash_established() */ - /* Remove association from the hash table. */ void __sctp_unhash_established(sctp_association_t *asoc) { @@ -557,29 +509,25 @@ void __sctp_unhash_established(sctp_association_t *asoc) epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); - + head = &sctp_proto.assoc_hashbucket[epb->hashent]; sctp_write_lock(&head->lock); if (epb->pprev) { - if (epb->next) { + if (epb->next) epb->next->pprev = epb->pprev; - } *epb->pprev = epb->next; epb->pprev = NULL; } sctp_write_unlock(&head->lock); - -} /* __sctp_unhash_established() */ - +} /* Look up an association. */ -sctp_association_t * -__sctp_rcv_lookup_association(const sockaddr_storage_t *laddr, - const sockaddr_storage_t *paddr, - sctp_transport_t **transportp) +sctp_association_t *__sctp_rcv_lookup_association(const sockaddr_storage_t *laddr, + const sockaddr_storage_t *paddr, + sctp_transport_t **transportp) { sctp_hashbucket_t *head; sctp_endpoint_common_t *epb; @@ -588,18 +536,18 @@ __sctp_rcv_lookup_association(const sockaddr_storage_t *laddr, int hash; /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. + * have wildcards anyways. */ - hash = sctp_assoc_hashfn(laddr->v4.sin_port, paddr->v4.sin_port); head = &sctp_proto.assoc_hashbucket[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { asoc = sctp_assoc(epb); transport = sctp_assoc_is_match(asoc, laddr, paddr); - if (transport) { goto hit; } - } - + if (transport) + goto hit; + } + read_unlock(&head->lock); return NULL; @@ -610,11 +558,10 @@ hit: sock_hold(epb->sk); read_unlock(&head->lock); return asoc; - -} /* __sctp_rcv_lookup_association() */ +} /* - * SCTP Implementors Guide, 2.18 Handling of address + * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. * * D) When searching for a matching TCB upon reception of an INIT @@ -622,7 +569,7 @@ hit: * source address of the packet (containing the INIT or * INIT-ACK) but the receiver SHOULD also use all valid * address parameters contained within the chunk. - * + * * 2.18.3 Solution description * * This new text clearly specifies to an implementor the need @@ -631,93 +578,86 @@ hit: * in certain circumstances. * */ -static sctp_association_t * -__sctp_rcv_initack_lookup(struct sk_buff *skb, - const sockaddr_storage_t *laddr, - sctp_transport_t **transportp) +static sctp_association_t *__sctp_rcv_initack_lookup(struct sk_buff *skb, + const sockaddr_storage_t *laddr, sctp_transport_t **transportp) { sctp_association_t *asoc; sockaddr_storage_t addr; sockaddr_storage_t *paddr = &addr; - struct sctphdr *sh = (struct sctphdr *)skb->h.raw; + struct sctphdr *sh = (struct sctphdr *) skb->h.raw; sctp_chunkhdr_t *ch; - uint8_t *ch_end, *data; + __u8 *ch_end, *data; sctpParam_t parm; - ch = (sctp_chunkhdr_t *)skb->data; + ch = (sctp_chunkhdr_t *) skb->data; - ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); + ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); - if (SCTP_CID_INIT_ACK != ch->type) { + if (SCTP_CID_INIT_ACK != ch->type) return NULL; - } - /* - * This code will NOT touch anything inside the chunk--it is - * strictly READ-ONLY. - * - * RFC 2960 3 SCTP packet Format - * - * Multiple chunks can be bundled into one SCTP packet up to - * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN - * COMPLETE chunks. These chunks MUST NOT be bundled with any - * other chunk in a packet. See Section 6.10 for more details - * on chunk bundling. - */ - - /* Find the start of the TLVs and the end of the chunk. This is + /* + * This code will NOT touch anything inside the chunk--it is + * strictly READ-ONLY. + * + * RFC 2960 3 SCTP packet Format + * + * Multiple chunks can be bundled into one SCTP packet up to + * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN + * COMPLETE chunks. These chunks MUST NOT be bundled with any + * other chunk in a packet. See Section 6.10 for more details + * on chunk bundling. + */ + + /* Find the start of the TLVs and the end of the chunk. This is * the region we search for address parameters. */ - data = skb->data + sizeof(sctp_init_chunk_t); - - /* See sctp_process_init() for how to go thru TLVs. */ - while ( data < ch_end ) { - + data = skb->data + sizeof(sctp_init_chunk_t); + + /* See sctp_process_init() for how to go thru TLVs. */ + while (data < ch_end) { parm.v = data; - - if (parm.p->length == 0) { break; } - + + if (!parm.p->length) + break; + data += WORD_ROUND(ntohs(parm.p->length)); - - /* Note: Ignoring hostname addresses. */ - if((SCTP_PARAM_IPV4_ADDRESS != parm.p->type) - && (SCTP_PARAM_IPV6_ADDRESS != parm.p->type)) { + + /* Note: Ignoring hostname addresses. */ + if ((SCTP_PARAM_IPV4_ADDRESS != parm.p->type) && + (SCTP_PARAM_IPV6_ADDRESS != parm.p->type)) continue; - } - + sctp_param2sockaddr(paddr, parm, ntohs(sh->source)); - + asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); - if (asoc) { return asoc; } - - } /* while (not at end of chunk) */ + if (asoc) + return asoc; + } return NULL; - -} /* __sctp_rcv_initack_lookup() */ +} /* Lookup an association for an inbound skb. */ -sctp_association_t * -__sctp_rcv_lookup(struct sk_buff *skb, const sockaddr_storage_t *paddr, - const sockaddr_storage_t *laddr, - sctp_transport_t **transportp) +sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, + const sockaddr_storage_t *paddr, + const sockaddr_storage_t *laddr, + sctp_transport_t **transportp) { sctp_association_t *asoc; asoc = __sctp_rcv_lookup_association(laddr, paddr, transportp); - - /* Further lookup for INIT-ACK packet. - * SCTP Implementors Guide, 2.18 Handling of address + + /* Further lookup for INIT-ACK packet. + * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. */ - if (!asoc) { + if (!asoc) asoc = __sctp_rcv_initack_lookup(skb, laddr, transportp); - } - - return asoc; -} /* __sctp_rcv_lookup() */ + return asoc; +} diff --git a/net/sctp/sctp_inqueue.c b/net/sctp/sctp_inqueue.c index 70a46f650bf2..457ed52678b6 100644 --- a/net/sctp/sctp_inqueue.c +++ b/net/sctp/sctp_inqueue.c @@ -51,169 +51,152 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_inqueue.c,v 1.10 2002/ #include /* Initialize an SCTP_inqueue. */ -void -sctp_inqueue_init(sctp_inqueue_t *queue) +void sctp_inqueue_init(sctp_inqueue_t *queue) { - skb_queue_head_init(&queue->in); + skb_queue_head_init(&queue->in); queue->in_progress = NULL; - /* Create a task for delivering data. */ - INIT_LIST_HEAD(&queue->immediate.list); - queue->immediate.sync = 0; - queue->immediate.routine = NULL; - queue->immediate.data = NULL; + /* Create a task for delivering data. */ + INIT_LIST_HEAD(&queue->immediate.list); + queue->immediate.sync = 0; + queue->immediate.routine = NULL; + queue->immediate.data = NULL; - queue->malloced = 0; - -} /* sctp_inqueue_init() */ + queue->malloced = 0; +} /* Create an initialized SCTP_inqueue. */ -sctp_inqueue_t * -sctp_inqueue_new() +sctp_inqueue_t *sctp_inqueue_new(void) { - sctp_inqueue_t *retval; - - retval = t_new(sctp_inqueue_t, GFP_ATOMIC); - if (NULL == retval) { return(NULL); } - - sctp_inqueue_init(retval); - retval->malloced = 1; - - return(retval); + sctp_inqueue_t *retval; -} /* sctp_inqueue_new() */ + retval = t_new(sctp_inqueue_t, GFP_ATOMIC); + if (retval) { + sctp_inqueue_init(retval); + retval->malloced = 1; + } + return retval; +} /* Release the memory associated with an SCTP inqueue. */ -void -sctp_inqueue_free(sctp_inqueue_t *queue) +void sctp_inqueue_free(sctp_inqueue_t *queue) { sctp_chunk_t *chunk; - /* Empty the queue. */ - while ((chunk=(sctp_chunk_t *)skb_dequeue(&queue->in))!=NULL) { + /* Empty the queue. */ + while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL) sctp_free_chunk(chunk); - } - /* If there is a packet which is currently being worked on, + + /* If there is a packet which is currently being worked on, * free it as well. */ - if (queue->in_progress) { + if (queue->in_progress) sctp_free_chunk(queue->in_progress); - } - - if (queue->malloced) { - /* Dump the master memory segment. */ - kfree(queue); - } - -} /* sctp_inqueue_free() */ - + if (queue->malloced) { + /* Dump the master memory segment. */ + kfree(queue); + } +} -/* Put a new packet in an SCTP inqueue. - * We assume that packet->sctp_hdr is set and in host byte order. +/* Put a new packet in an SCTP inqueue. + * We assume that packet->sctp_hdr is set and in host byte order. */ -void -sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) +void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) { /* Directly call the packet handling routine. */ + /* We are now calling this either from the soft interrupt * or from the backlog processing. * Eventually, we should clean up inqueue to not rely * on the BH related data structures. */ - skb_queue_tail(&(q->in), (struct sk_buff *)packet); + skb_queue_tail(&(q->in), (struct sk_buff *) packet); q->immediate.routine(q->immediate.data); - -} /* sctp_push_inqueue() */ +} /* Extract a chunk from an SCTP inqueue. - * - * WARNING: If you need to put the chunk on another queue, you need to + * + * WARNING: If you need to put the chunk on another queue, you need to * make a shallow copy (clone) of it. */ -sctp_chunk_t * -sctp_pop_inqueue(sctp_inqueue_t *queue) +sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue) { - sctp_chunk_t *chunk; - sctp_chunkhdr_t *ch = NULL; + sctp_chunk_t *chunk; + sctp_chunkhdr_t *ch = NULL; /* The assumption is that we are safe to process the chunks - * at this time. + * at this time. */ - if (NULL != (chunk = queue->in_progress)) { + if ((chunk = queue->in_progress) != NULL) { /* There is a packet that we have been working on. - * Any post processing work to do before we move on? - */ - if (chunk->singleton || chunk->end_of_packet - || chunk->pdiscard) { + * Any post processing work to do before we move on? + */ + if (chunk->singleton || + chunk->end_of_packet || + chunk->pdiscard) { sctp_free_chunk(chunk); chunk = queue->in_progress = NULL; - } else { - /* Nothing to do. Next chunk in the packet, please. */ - ch = (sctp_chunkhdr_t *)chunk->chunk_end; + } else { + /* Nothing to do. Next chunk in the packet, please. */ + ch = (sctp_chunkhdr_t *) chunk->chunk_end; /* Force chunk->skb->data to chunk->chunk_end. */ - skb_pull(chunk->skb, + skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); - } - } + } + } /* Do we need to take the next packet out of the queue to process? */ - if (NULL == chunk) { - - /* Is the queue empty? */ - if (skb_queue_empty(&queue->in)) { - return(NULL); - } + if (!chunk) { + /* Is the queue empty? */ + if (skb_queue_empty(&queue->in)) + return NULL; - chunk = queue->in_progress = - (sctp_chunk_t *)skb_dequeue(&queue->in); + chunk = queue->in_progress = + (sctp_chunk_t *) skb_dequeue(&queue->in); - /* This is the first chunk in the packet. */ - chunk->singleton = 1; - ch = (sctp_chunkhdr_t *) chunk->skb->data; + /* This is the first chunk in the packet. */ + chunk->singleton = 1; + ch = (sctp_chunkhdr_t *) chunk->skb->data; } chunk->chunk_hdr = ch; - chunk->chunk_end = ((uint8_t *)ch) + chunk->chunk_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length)); - skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); - chunk->subh.v = NULL; /* Subheader is no longer valid. */ + skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + chunk->subh.v = NULL; /* Subheader is no longer valid. */ - if (chunk->chunk_end < chunk->skb->tail) { + if (chunk->chunk_end < chunk->skb->tail) { /* This is not a singleton */ - chunk->singleton = 0; - } else { - /* We are at the end of the packet, so mark the chunk - * in case we need to send a SACK. - */ - chunk->end_of_packet = 1; - } - + chunk->singleton = 0; + } else { + /* We are at the end of the packet, so mark the chunk + * in case we need to send a SACK. + */ + chunk->end_of_packet = 1; + } SCTP_DEBUG_PRINTK("+++sctp_pop_inqueue+++ chunk %p[%s]," - " length %d, skb->len %d\n",chunk, + " length %d, skb->len %d\n",chunk, sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), ntohs(chunk->chunk_hdr->length), chunk->skb->len); - return(chunk); - -} /* sctp_pop_inqueue() */ + return chunk; +} /* Set a top-half handler. - * + * * Originally, we the top-half handler was scheduled as a BH. We now - * call the handler directly in sctp_push_inqueue() at a time that - * we know we are lock safe. - * The intent is that this routine will pull stuff out of the + * call the handler directly in sctp_push_inqueue() at a time that + * we know we are lock safe. + * The intent is that this routine will pull stuff out of the * inqueue and process it. */ -void -sctp_inqueue_set_th_handler(sctp_inqueue_t *q, - void (*callback)(void *), void *arg) +void sctp_inqueue_set_th_handler(sctp_inqueue_t *q, + void (*callback)(void *), void *arg) { - q->immediate.routine = callback; - q->immediate.data = arg; - -} /* sctp_inqueue_set_th_handler() */ + q->immediate.routine = callback; + q->immediate.data = arg; +} diff --git a/net/sctp/sctp_ipv6.c b/net/sctp/sctp_ipv6.c index e2c382e89823..f76777e14469 100644 --- a/net/sctp/sctp_ipv6.c +++ b/net/sctp/sctp_ipv6.c @@ -50,7 +50,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ipv6.c,v 1.12 2002/08/ #define __NO_VERSION__ #include -#include #include #include #include @@ -81,7 +80,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ipv6.c,v 1.12 2002/08/ #include - /* FIXME: Cleanup so we don't need TEST_FRAME here. */ #ifndef TEST_FRAME /* FIXME: Comments. */ @@ -89,12 +87,11 @@ static inline void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info) { - /* BUG. WRITE ME. */ -}/* sctp_v6_err */ + /* BUG. WRITE ME. */ +} /* 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 sock *sk = skb->sk; struct ipv6_pinfo *np = inet6_sk(sk); @@ -104,7 +101,7 @@ sctp_v6_xmit(struct sk_buff *skb) int err = 0; fl.proto = sk->protocol; - fl.fl6_dst = &np->daddr; + fl.fl6_dst = &np->daddr; fl.fl6_src = NULL; fl.fl6_flowlabel = np->flow_label; @@ -119,7 +116,7 @@ sctp_v6_xmit(struct sk_buff *skb) } dst = __sk_dst_check(sk, np->dst_cookie); - + if (dst == NULL) { dst = ip6_route_output(sk, &fl); @@ -134,54 +131,44 @@ sctp_v6_xmit(struct sk_buff *skb) skb->dst = dst_clone(dst); /* FIXME: This is all temporary until real source address - * selection is done. + * selection is done. */ if (ipv6_addr_any(&np->saddr)) { err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); - if (err) { + if (err) printk(KERN_ERR "sctp_v6_xmit: no saddr available\n"); - } - /* FIXME: This is a workaround until we get + /* FIXME: This is a workaround until we get * real source address selection done. This is here - * to disallow loopback when the scoping rules have - * not bound loopback to the endpoint. + * to disallow loopback when the scoping rules have + * not bound loopback to the endpoint. */ - if (sctp_ipv6_addr_type(&saddr) - & IPV6_ADDR_LOOPBACK) { + if (sctp_ipv6_addr_type(&saddr) & IPV6_ADDR_LOOPBACK) { if (!(sctp_ipv6_addr_type(&np->daddr) & IPV6_ADDR_LOOPBACK)) { - ipv6_addr_copy(&saddr, &np->daddr); } } - fl.fl6_src = &saddr; } else { fl.fl6_src = &np->saddr; } /* Restore final destination back after routing done */ - fl.nl_u.ip6_u.daddr = &np->daddr; - - + fl.nl_u.ip6_u.daddr = &np->daddr; return ip6_xmit(sk, skb, &fl, np->opt); - -} /* sctp_v6_xmit */ +} #endif /* TEST_FRAME */ /* Returns the mtu for the given v6 destination address. */ -int -sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) +int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) { + struct dst_entry *dst; + struct flowi fl; int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; - - struct flowi fl; - struct dst_entry *dst; - fl.proto = 0; fl.fl6_dst = (struct in6_addr *)&address->v6.sin6_addr; fl.fl6_src = NULL; @@ -189,7 +176,7 @@ sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) fl.oif = 0; fl.uli_u.ports.sport = 0; fl.uli_u.ports.dport = 0; - + dst = ip6_route_output(NULL, &fl); if (dst) { dst_mtu = dst->pmtu; @@ -203,33 +190,30 @@ sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) "%d as dst_mtu\n", dst_mtu); } - return (dst_mtu); - -} /* sctp_v6_get_dst_mtu() */ - + return dst_mtu; +} static struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, .release = inet6_release, .bind = inet6_bind, - .connect = inet_dgram_connect, - .socketpair = sock_no_socketpair, - .accept = inet_accept, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = inet_accept, .getname = inet6_getname, - .poll = sctp_poll, + .poll = sctp_poll, .ioctl = inet6_ioctl, - .listen = sctp_inet_listen, + .listen = sctp_inet_listen, .shutdown = inet_shutdown, .setsockopt = inet_setsockopt, - .getsockopt = inet_getsockopt, - .sendmsg = inet_sendmsg, - .recvmsg = inet_recvmsg, + .getsockopt = inet_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, }; -static struct inet_protosw sctpv6_protosw = -{ - .type = SOCK_SEQPACKET, +static struct inet_protosw sctpv6_protosw = { + .type = SOCK_SEQPACKET, .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet6_seqpacket_ops, @@ -238,45 +222,41 @@ static struct inet_protosw sctpv6_protosw = .flags = SCTP_PROTOSW_FLAG }; -static struct inet6_protocol sctpv6_protocol = -{ - .handler = sctp_rcv, - .err_handler = sctp_v6_err, - .next = NULL, - .protocol = IPPROTO_SCTP, - .copy = 0, - .data = NULL, - .name = "SCTPv6" -}; +static struct inet6_protocol sctpv6_protocol = { + .handler = sctp_rcv, + .err_handler = sctp_v6_err, + .next = NULL, + .protocol = IPPROTO_SCTP, + .copy = 0, + .data = NULL, + .name = "SCTPv6" +}; static sctp_func_t sctp_ipv6_specific = { - .queue_xmit = sctp_v6_xmit, - .setsockopt = ipv6_setsockopt, - .getsockopt = ipv6_getsockopt, + .queue_xmit = sctp_v6_xmit, + .setsockopt = ipv6_setsockopt, + .getsockopt = ipv6_getsockopt, .get_dst_mtu = sctp_v6_get_dst_mtu, .net_header_len = sizeof(struct ipv6hdr), - .sockaddr_len = sizeof(struct sockaddr_in6), + .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, -}; - +}; -/* Initialize IPv6 support and register with inet6 stack. */ +/* Initialize IPv6 support and register with inet6 stack. */ int sctp_v6_init(void) -{ - - /* Add SCTPv6 to inetsw6 linked list. */ +{ + /* Add SCTPv6 to inetsw6 linked list. */ inet6_register_protosw(&sctpv6_protosw); - - /* Register inet6 protocol. */ - inet6_add_protocol(&sctpv6_protocol); - /* Fill in address family info. */ + /* Register inet6 protocol. */ + inet6_add_protocol(&sctpv6_protocol); + + /* Fill in address family info. */ INIT_LIST_HEAD(&sctp_ipv6_specific.list); list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); return 0; - -} /* sctp_v6_init() */ +} /* IPv6 specific exit support. */ void sctp_v6_exit(void) @@ -284,5 +264,4 @@ void sctp_v6_exit(void) list_del(&sctp_ipv6_specific.list); inet6_del_protocol(&sctpv6_protocol); inet6_unregister_protosw(&sctpv6_protosw); - -} /* sctp_v6_exit() */ +} diff --git a/net/sctp/sctp_objcnt.c b/net/sctp/sctp_objcnt.c index d3e9e6d2b2c2..c4f3f1774c43 100644 --- a/net/sctp/sctp_objcnt.c +++ b/net/sctp/sctp_objcnt.c @@ -43,11 +43,11 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_objcnt.c,v 1.5 2002/07 #include -/* - * Global counters to count raw object allocation counts. +/* + * Global counters to count raw object allocation counts. * To add new counters, choose a unique suffix for the variable * name as the helper macros key off this suffix to make - * life easier for the programmer. + * life easier for the programmer. */ SCTP_DBG_OBJCNT(sock); @@ -59,7 +59,7 @@ SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(addr); /* An array to make it easy to pretty print the debug information - * to the proc fs. + * to the proc fs. */ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { SCTP_DBG_OBJCNT_ENTRY(sock), @@ -71,15 +71,14 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { SCTP_DBG_OBJCNT_ENTRY(addr), }; -/* Callback from procfs to read out objcount information. +/* Callback from procfs to read out objcount information. * Walk through the entries in the sctp_dbg_objcnt array, dumping * the raw object counts for each monitored type. - * + * * This code was modified from similar code in route.c */ -static int -sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) +static int sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) { int len = 0; off_t pos = 0; @@ -90,10 +89,10 @@ sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, /* How many entries? */ entries = sizeof(sctp_dbg_objcnt)/sizeof(sctp_dbg_objcnt[0]); - /* Walk the entries and print out the debug information + /* Walk the entries and print out the debug information * for proc fs. */ - for(i = 0; i < entries; i++) { + for (i = 0; i < entries; i++) { pos += 128; /* Skip ahead. */ @@ -102,41 +101,36 @@ sctp_dbg_objcnt_read(char *buffer, char **start, off_t offset, continue; } /* Print out each entry. */ - sprintf(temp, "%s: %d", + sprintf(temp, "%s: %d", sctp_dbg_objcnt[i].label, atomic_read(sctp_dbg_objcnt[i].counter)); sprintf(buffer + len, "%-127s\n", temp); len += 128; - if (pos >= offset+length) { + if (pos >= offset+length) goto done; - } - } done: - *start = buffer + len - (pos - offset); - len = pos - offset; - if (len > length) - len = length; + *start = buffer + len - (pos - offset); + len = pos - offset; + if (len > length) + len = length; - return len; + return len; +} -} /* sctp_dbg_objcnt_read() */ - -/* Initialize the objcount in the proc filesystem. */ +/* Initialize the objcount in the proc filesystem. */ void sctp_dbg_objcnt_init(void) { create_proc_read_entry("sctp_dbg_objcnt", 0, proc_net_sctp, sctp_dbg_objcnt_read, NULL); +} -} /* sctp_dbg_objcnt_init() */ - -/* Cleanup the objcount entry in the proc filesystem. */ +/* Cleanup the objcount entry in the proc filesystem. */ void sctp_dbg_objcnt_exit(void) { remove_proc_entry("sctp_dbg_objcount", proc_net_sctp); - -} /* sctp_dbg_objcnt_exit() */ +} diff --git a/net/sctp/sctp_output.c b/net/sctp/sctp_output.c index 0d3ae24fd50f..3a976d544a3b 100644 --- a/net/sctp/sctp_output.c +++ b/net/sctp/sctp_output.c @@ -44,7 +44,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_output.c,v 1.22 2002/07/12 14:39:05 jgrimm Exp $"; -#include #include #include #include @@ -52,9 +51,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_output.c,v 1.22 2002/0 #include #include #include -#ifndef CONFIG_INET_ECN -#define CONFIG_INET_ECN -#endif /* CONFIG_INET_ECN */ #include #include @@ -69,43 +65,38 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_output.c,v 1.22 2002/0 #include #include - /* Forward declarations for private helpers. */ -uint32_t count_crc(uint8_t *ptr, uint16_t count); +__u32 count_crc(__u8 *ptr, __u16 count); static void sctp_packet_reset(sctp_packet_t *packet); -static inline sctp_xmit_t -sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk); +static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, + sctp_chunk_t *chunk); -/* Config a packet. +/* Config a packet. * This appears to be a followup set of initializations.) */ -sctp_packet_t * -sctp_packet_config(sctp_packet_t *packet, - uint32_t vtag, - int ecn_capable, - sctp_packet_phandler_t *prepend_handler) +sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, + __u32 vtag, + int ecn_capable, + sctp_packet_phandler_t *prepend_handler) { int packet_empty = (packet->size == SCTP_IP_OVERHEAD); - packet->vtag = vtag; + packet->vtag = vtag; packet->ecn_capable = ecn_capable; packet->get_prepend_chunk = prepend_handler; packet->has_cookie_echo = 0; /* We might need to call the prepend_handler right away. */ - if (packet_empty) { + if (packet_empty) sctp_packet_reset(packet); - } - return(packet); - -} /* sctp_packet_config() */ + return packet; +} /* Initialize the packet structure. */ -sctp_packet_t * -sctp_packet_init(sctp_packet_t *packet, - sctp_transport_t *transport, - uint16_t sport, - uint16_t dport) +sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, + sctp_transport_t *transport, + __u16 sport, + __u16 dport) { packet->transport = transport; packet->source_port = sport; @@ -115,31 +106,24 @@ sctp_packet_init(sctp_packet_t *packet, packet->ecn_capable = 0; packet->get_prepend_chunk = NULL; packet->has_cookie_echo = 0; - packet->malloced = 0; - sctp_packet_reset(packet); - return packet; - -} /* sctp_packet_init() */ - + return packet; +} /* Free a packet. */ -void -sctp_packet_free(sctp_packet_t *packet) +void sctp_packet_free(sctp_packet_t *packet) { - sctp_chunk_t *chunk; + sctp_chunk_t *chunk; while (NULL != - (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) { - sctp_free_chunk(chunk); - } - - if (packet->malloced) { - kfree(packet); + (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) { + sctp_free_chunk(chunk); } -} /* sctp_packet_free() */ + if (packet->malloced) + kfree(packet); +} /* This routine tries to append the chunk to the offered packet. If adding * the chunk causes the packet to exceed the path MTU and COOKIE_ECHO chunk @@ -148,165 +132,154 @@ sctp_packet_free(sctp_packet_t *packet) * as it can fit in the packet, but any more data that does not fit in this * packet can be sent only after receiving the COOKIE_ACK. */ -sctp_xmit_t -sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) { - sctp_xmit_t retval; - int error = 0; + sctp_xmit_t retval; + int error = 0; - switch (retval = (sctp_packet_append_chunk(packet, chunk))) { - case SCTP_XMIT_PMTU_FULL: + switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { + case SCTP_XMIT_PMTU_FULL: if (!packet->has_cookie_echo) { error = sctp_packet_transmit(packet); - if (error < 0) { + if (error < 0) chunk->skb->sk->err = -error; - } + /* If we have an empty packet, then we can NOT ever * return PMTU_FULL. */ retval = sctp_packet_append_chunk(packet, chunk); } - break; - case SCTP_XMIT_MUST_FRAG: - case SCTP_XMIT_RWND_FULL: - case SCTP_XMIT_OK: - break; - } + break; - return(retval); - -} /* sctp_packet_transmit_chunk() */ + case SCTP_XMIT_MUST_FRAG: + case SCTP_XMIT_RWND_FULL: + case SCTP_XMIT_OK: + break; + }; + return retval; +} /* Append a chunk to the offered packet reporting back any inability to do - * so. + * so. */ -sctp_xmit_t -sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) { - sctp_xmit_t retval = SCTP_XMIT_OK; - uint16_t chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); - size_t psize = packet->size; - size_t pmtu; - int too_big; + sctp_xmit_t retval = SCTP_XMIT_OK; + __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); + size_t psize = packet->size; + size_t pmtu; + int too_big; - pmtu = ((packet->transport->asoc) ? + pmtu = ((packet->transport->asoc) ? (packet->transport->asoc->pmtu) : (packet->transport->pmtu)); too_big = (psize + chunk_len > pmtu); - /* Decide if we need to fragment or resubmit later. */ - if (too_big) { - int packet_empty = (packet->size == SCTP_IP_OVERHEAD); - + /* Decide if we need to fragment or resubmit later. */ + if (too_big) { + int packet_empty = (packet->size == SCTP_IP_OVERHEAD); + /* Both control chunks and data chunks with TSNs are - * non-fragmentable. - */ - int fragmentable = sctp_chunk_is_data(chunk) + * non-fragmentable. + */ + int fragmentable = sctp_chunk_is_data(chunk) && (!chunk->has_tsn); - if (packet_empty) { - if (fragmentable) { - retval = SCTP_XMIT_MUST_FRAG; - goto finish; - } else { - /* The packet is too big but we can - * not fragment it--we have to just - * transmit and rely on IP - * fragmentation. - */ - goto append; - } - - } else { /* !packet_empty */ - retval = SCTP_XMIT_PMTU_FULL; - goto finish; - } - + if (packet_empty) { + if (fragmentable) { + retval = SCTP_XMIT_MUST_FRAG; + goto finish; + } else { + /* The packet is too big but we can + * not fragment it--we have to just + * transmit and rely on IP + * fragmentation. + */ + goto append; + } + } else { /* !packet_empty */ + retval = SCTP_XMIT_PMTU_FULL; + goto finish; + } } else { /* The chunk fits in the packet. */ goto append; } append: - /* We believe that this chunk is OK to add to the packet (as - * long as we have the cwnd for it). - */ + /* We believe that this chunk is OK to add to the packet (as + * long as we have the cwnd for it). + */ /* DATA is a special case since we must examine both rwnd and cwnd * before we send DATA. */ if (sctp_chunk_is_data(chunk)) { retval = sctp_packet_append_data(packet, chunk); - if (SCTP_XMIT_OK != retval) { + if (SCTP_XMIT_OK != retval) goto finish; - } - } - else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) { + } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) { packet->has_cookie_echo = 1; } - - /* It is OK to send this chunk. */ - skb_queue_tail(&packet->chunks, + skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); packet->size += chunk_len; - finish: - return(retval); - -} /* sctp_packet_append_chunk() */ + return retval; +} /* All packets are sent to the network through this function from * sctp_push_outqueue(). * * 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; sctp_association_t *asoc = transport->asoc; - struct sctphdr *sh; - uint32_t crc32; + struct sctphdr *sh; + __u32 crc32; struct sk_buff *nskb; sctp_chunk_t *chunk; - struct sock *sk; - int err = 0; + struct sock *sk; + int err = 0; int padding; /* How much padding do we need? */ - uint8_t packet_has_data = 0; + __u8 packet_has_data = 0; - /* Do NOT generate a chunkless packet... */ - if (skb_queue_empty(&packet->chunks)) { - return(err); - } + /* Do NOT generate a chunkless packet... */ + if (skb_queue_empty(&packet->chunks)) + return err; + + /* Set up convenience variables... */ + chunk = (sctp_chunk_t *) (packet->chunks.next); + sk = chunk->skb->sk; - /* Set up convenience variables... */ - chunk = (sctp_chunk_t *)(packet->chunks.next); - sk = chunk->skb->sk; - /* Allocate the new skb. */ nskb = dev_alloc_skb(packet->size); - if (NULL == nskb) { + if (!nskb) { err = -ENOMEM; goto out; } - /* Make sure the outbound skb has enough header room reserved. */ - skb_reserve(nskb, SCTP_IP_OVERHEAD); - /* Set the owning socket so that we know where to get the - * destination IP address. - */ + /* Make sure the outbound skb has enough header room reserved. */ + skb_reserve(nskb, SCTP_IP_OVERHEAD); + + /* Set the owning socket so that we know where to get the + * destination IP address. + */ skb_set_owner_w(nskb, sk); /** * 6.10 Bundling - * + * * An endpoint bundles chunks by simply including multiple * chunks in one outbound SCTP packet. ... */ + /** * 3.2 Chunk Field Descriptions * @@ -316,7 +289,7 @@ sctp_packet_transmit(sctp_packet_t *packet) * pad the chunk with all zero bytes and this padding is not * included in the chunk length field. The sender should * never pad with more than 3 bytes. - * + * * [This whole comment explains WORD_ROUND() below.] */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); @@ -324,25 +297,24 @@ sctp_packet_transmit(sctp_packet_t *packet) skb_dequeue(&packet->chunks))) { chunk->num_times_sent++; chunk->sent_at = jiffies; - if (sctp_chunk_is_data(chunk)) { - - sctp_chunk_assign_tsn(chunk); + if (sctp_chunk_is_data(chunk)) { + sctp_chunk_assign_tsn(chunk); - /* 6.3.1 C4) When data is in flight and when allowed - * by rule C5, a new RTT measurement MUST be made each - * round trip. Furthermore, new RTT measurements + /* 6.3.1 C4) When data is in flight and when allowed + * by rule C5, a new RTT measurement MUST be made each + * round trip. Furthermore, new RTT measurements * SHOULD be made no more than once per round-trip * for a given destination transport address. */ - if ((1 == chunk->num_times_sent) - && (!transport->rto_pending)) { + if ((1 == chunk->num_times_sent) && + (!transport->rto_pending)) { chunk->rtt_in_progress = 1; transport->rto_pending = 1; } packet_has_data = 1; - } + } memcpy(skb_put(nskb, chunk->skb->len), - chunk->skb->data, chunk->skb->len); + chunk->skb->data, chunk->skb->len); padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; memset(skb_put(nskb, padding), 0, padding); SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " @@ -351,230 +323,220 @@ sctp_packet_transmit(sctp_packet_t *packet) sctp_cname(SCTP_ST_CHUNK( chunk->chunk_hdr->type)), chunk->has_tsn ? "TSN" : "No TSN", - chunk->has_tsn ? + chunk->has_tsn ? ntohl(chunk->subh.data_hdr->tsn) : 0, "length", ntohs(chunk->chunk_hdr->length), - "chunk->skb->len", chunk->skb->len, - "num_times_sent", chunk->num_times_sent, + "chunk->skb->len", chunk->skb->len, + "num_times_sent", chunk->num_times_sent, "rtt_in_progress", chunk->rtt_in_progress); - /* - * If this is a control chunk, this is our last - * reference. Free data chunks after they've been + /* + * If this is a control chunk, this is our last + * reference. Free data chunks after they've been * acknowledged or have failed. */ - if (!sctp_chunk_is_data(chunk)) { + if (!sctp_chunk_is_data(chunk)) sctp_free_chunk(chunk); - } } - /* Build the SCTP header. */ - sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); - sh->source = htons(packet->source_port); - sh->dest = htons(packet->destination_port); - - /* From 6.8 Adler-32 Checksum Calculation: - * After the packet is constructed (containing the SCTP common - * header and one or more control or DATA chunks), the - * transmitter shall: - * - * 1) Fill in the proper Verification Tag in the SCTP common - * header and initialize the checksum field to 0's. - */ - sh->vtag = htonl(packet->vtag); - sh->checksum = 0; - - /* 2) Calculate the Adler-32 checksum of the whole packet, - * including the SCTP common header and all the - * chunks. - * + /* Build the SCTP header. */ + sh = (struct sctphdr *) skb_push(nskb, sizeof(struct sctphdr)); + sh->source = htons(packet->source_port); + sh->dest = htons(packet->destination_port); + + /* From 6.8 Adler-32 Checksum Calculation: + * After the packet is constructed (containing the SCTP common + * header and one or more control or DATA chunks), the + * transmitter shall: + * + * 1) Fill in the proper Verification Tag in the SCTP common + * header and initialize the checksum field to 0's. + */ + sh->vtag = htonl(packet->vtag); + sh->checksum = 0; + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * * Note: Adler-32 is no longer applicable, as has been replaced - * by CRC32-C as described in . - */ - crc32 = count_crc((uint8_t *)sh, nskb->len); - - /* 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); - - switch (transport->ipaddr.sa.sa_family){ - case AF_INET: - inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr; - break; - case AF_INET6: - SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) - break; - default: - /* This is bogus address type, just bail. */ - break; - } - - /* IP layer ECN support + * by CRC32-C as described in . + */ + crc32 = count_crc((__u8 *)sh, nskb->len); + + /* 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); + + switch (transport->ipaddr.sa.sa_family) { + case AF_INET: + inet_sk(sk)->daddr = transport->ipaddr.v4.sin_addr.s_addr; + break; + + case AF_INET6: + SCTP_V6(inet6_sk(sk)->daddr = transport->ipaddr.v6.sin6_addr;) + break; + + default: + /* This is bogus address type, just bail. */ + break; + }; + + /* IP layer ECN support * From RFC 2481 - * "The ECN-Capable Transport (ECT) bit would be set by the - * data sender to indicate that the end-points of the + * "The ECN-Capable Transport (ECT) bit would be set by the + * data sender to indicate that the end-points of the * transport protocol are ECN-capable." * * If ECN capable && negotiated && it makes sense for * this packet to support it (e.g. post ECN negotiation) - * then lets set the ECT bit + * then lets set the ECT bit * * FIXME: Need to do something else for IPv6 */ - if (packet->ecn_capable) { INET_ECN_xmit(nskb->sk); } else { INET_ECN_dontxmit(nskb->sk); } + /* Set up the IP options. */ + /* BUG: not implemented + * For v4 this all lives somewhere in sk->opt... + */ - /* Set up the IP options. */ - /* BUG: not implemented - * For v4 this all lives somewhere in sk->opt... - */ - - /* Dump that on IP! */ - if ( asoc != NULL - && asoc->peer.last_sent_to != transport ) { - + /* Dump that on IP! */ + if (asoc && asoc->peer.last_sent_to != transport) { /* Considering the multiple CPU scenario, this is a * "correcter" place for last_sent_to. --xguo */ asoc->peer.last_sent_to = transport; - } + } /* Hey, before Linux changes, here's what we have to * do to force IP routing to recognize the change of * dest addr. --xguo */ - if ( sk->dst_cache != NULL ) { sk->dst_cache->obsolete = 1; } - + if (sk->dst_cache) + sk->dst_cache->obsolete = 1; + if (packet_has_data) { - struct timer_list *timer; - unsigned long timeout; + struct timer_list *timer; + unsigned long timeout; transport->last_time_used = jiffies; /* Restart the AUTOCLOSE timer when sending data. */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && + if ((SCTP_STATE_ESTABLISHED == asoc->state) && (asoc->autoclose)) { timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; - if (!mod_timer(timer, jiffies + timeout)) { + if (!mod_timer(timer, jiffies + timeout)) sctp_association_hold(asoc); - } } } - SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", + SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", nskb->len); (*transport->af_specific->queue_xmit)(nskb); out: - packet->size = SCTP_IP_OVERHEAD; - return err; - -} /* sctp_packet_transmit() */ + packet->size = SCTP_IP_OVERHEAD; + return err; +} /******************************************************************** * 2nd Level Abstractions ********************************************************************/ -/* +/* * This private function resets the packet to a fresh state. */ -static void -sctp_packet_reset(sctp_packet_t *packet) +static void sctp_packet_reset(sctp_packet_t *packet) { sctp_chunk_t *chunk = NULL; packet->size = SCTP_IP_OVERHEAD; - if ( NULL != packet->get_prepend_chunk ) { + if (packet->get_prepend_chunk) chunk = packet->get_prepend_chunk(packet->transport->asoc); - } - /* If there a is a prepend chunk stick it on the list before + /* If there a is a prepend chunk stick it on the list before * any other chunks get appended. */ - if (chunk) { + if (chunk) sctp_packet_append_chunk(packet, chunk); - } -} /* sctp_packet_reset() */ +} -/* This private function handles the specifics of appending DATA chunks. */ -static inline sctp_xmit_t -sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) +/* This private function handles the specifics of appending DATA chunks. */ +static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) { - sctp_xmit_t retval = SCTP_XMIT_OK; + sctp_xmit_t retval = SCTP_XMIT_OK; size_t datasize, rwnd, inflight; sctp_transport_t *transport = packet->transport; - uint32_t max_burst_bytes; - - /* RFC 2960 6.1 Transmission of DATA Chunks - * - * A) At any given time, the data sender MUST NOT transmit new data to - * any destination transport address if its peer's rwnd indicates - * that the peer has no buffer space (i.e. rwnd is 0, see Section - * 6.2.1). However, regardless of the value of rwnd (including if it - * is 0), the data sender can always have one DATA chunk in flight to - * the receiver if allowed by cwnd (see rule B below). This rule - * allows the sender to probe for a change in rwnd that the sender - * missed due to the SACK having been lost in transit from the data - * receiver to the data sender. - */ + __u32 max_burst_bytes; + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * A) At any given time, the data sender MUST NOT transmit new data to + * any destination transport address if its peer's rwnd indicates + * that the peer has no buffer space (i.e. rwnd is 0, see Section + * 6.2.1). However, regardless of the value of rwnd (including if it + * is 0), the data sender can always have one DATA chunk in flight to + * the receiver if allowed by cwnd (see rule B below). This rule + * allows the sender to probe for a change in rwnd that the sender + * missed due to the SACK having been lost in transit from the data + * receiver to the data sender. + */ rwnd = transport->asoc->peer.rwnd; inflight = transport->asoc->outqueue.outstanding_bytes; datasize = sctp_data_size(chunk); - + if (datasize > rwnd) { - if (inflight > 0){ - /* We have (at least) one data chunk in flight, - * so we can't fall back to rule 6.1 B). - */ + if (inflight > 0) { + /* We have (at least) one data chunk in flight, + * so we can't fall back to rule 6.1 B). + */ retval = SCTP_XMIT_RWND_FULL; goto finish; } } - - /* sctpimpguide-05 2.14.2 D) When the time comes for the sender to - * transmit new DATA chunks, the protocol parameter Max.Burst MUST - * first be applied to limit how many new DATA chunks may be sent. + /* sctpimpguide-05 2.14.2 D) When the time comes for the sender to + * transmit new DATA chunks, the protocol parameter Max.Burst MUST + * first be applied to limit how many new DATA chunks may be sent. * The limit is applied by adjusting cwnd as follows: * if((flightsize + Max.Burst*MTU) < cwnd) * cwnd = flightsize + Max.Burst*MTU - */ + */ max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu; if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { transport->cwnd = transport->flight_size + max_burst_bytes; SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " - "transport: %p, cwnd: %d, " + "transport: %p, cwnd: %d, " "ssthresh: %d, flight_size: %d, " "pba: %d\n", - __FUNCTION__, transport, - transport->cwnd, - transport->ssthresh, - transport->flight_size, + __FUNCTION__, transport, + transport->cwnd, + transport->ssthresh, + transport->flight_size, transport->partial_bytes_acked); - } - - /* RFC 2960 6.1 Transmission of DATA Chunks - * - * B) At any given time, the sender MUST NOT transmit new data - * to a given transport address if it has cwnd or more bytes - * of data outstanding to that transport address. - */ + } + + /* RFC 2960 6.1 Transmission of DATA Chunks + * + * B) At any given time, the sender MUST NOT transmit new data + * to a given transport address if it has cwnd or more bytes + * of data outstanding to that transport address. + */ if (transport->flight_size >= transport->cwnd) { retval = SCTP_XMIT_RWND_FULL; goto finish; } - + /* Keep track of how many bytes are in flight over this transport. */ transport->flight_size += datasize; @@ -591,9 +553,8 @@ sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) transport->asoc->peer.rwnd = rwnd; finish: - return(retval); - -} /* sctp_packet_append_data() */ + return retval; +} diff --git a/net/sctp/sctp_outqueue.c b/net/sctp/sctp_outqueue.c index 8fafc30cff32..62fbf282ceb5 100644 --- a/net/sctp/sctp_outqueue.c +++ b/net/sctp/sctp_outqueue.c @@ -49,7 +49,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_outqueue.c,v 1.35 2002/08/05 02:58:05 jgrimm Exp $"; -#include #include #include /* For struct list_head */ #include @@ -59,169 +58,152 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_outqueue.c,v 1.35 2002 #include /* Declare internal functions here. */ -static int sctp_acked(sctp_sackhdr_t *sack, uint32_t tsn); +static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); static void sctp_check_transmitted(sctp_outqueue_t *q, struct list_head *transmitted_queue, sctp_transport_t *transport, sctp_sackhdr_t *sack); - /* Generate a new outqueue. */ -sctp_outqueue_t * -sctp_outqueue_new(sctp_association_t *asoc) +sctp_outqueue_t *sctp_outqueue_new(sctp_association_t *asoc) { - sctp_outqueue_t *q; - - q = t_new(sctp_outqueue_t, GFP_KERNEL); - if (q) { - sctp_outqueue_init(asoc, q); - q->malloced = 1; - } - return q; - -} /* sctp_outqueue_new() */ + sctp_outqueue_t *q; + q = t_new(sctp_outqueue_t, GFP_KERNEL); + if (q) { + sctp_outqueue_init(asoc, q); + q->malloced = 1; + } + return q; +} /* Initialize an existing SCTP_outqueue. This does the boring stuff. * You still need to define handlers if you really want to DO * something with this structure... */ -void -sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q) +void sctp_outqueue_init(sctp_association_t *asoc, sctp_outqueue_t *q) { - q->asoc = asoc; - skb_queue_head_init(&q->out); - skb_queue_head_init(&q->control); - INIT_LIST_HEAD(&q->retransmit); - INIT_LIST_HEAD(&q->sacked); - - q->init_output = NULL; - q->config_output = NULL; - q->append_output = NULL; - q->build_output = NULL; - q->force_output = NULL; - - q->outstanding_bytes = 0; - q->empty = 1; - - q->malloced = 0; - -} /* sctp_outqueue_init() */ - - -/* Free the outqueue structure and any related pending chunks. - * FIXME: Add SEND_FAILED support. - */ -void -sctp_outqueue_teardown(sctp_outqueue_t *q) + q->asoc = asoc; + skb_queue_head_init(&q->out); + skb_queue_head_init(&q->control); + INIT_LIST_HEAD(&q->retransmit); + INIT_LIST_HEAD(&q->sacked); + + q->init_output = NULL; + q->config_output = NULL; + q->append_output = NULL; + q->build_output = NULL; + q->force_output = NULL; + + q->outstanding_bytes = 0; + q->empty = 1; + + q->malloced = 0; +} + +/* Free the outqueue structure and any related pending chunks. + * FIXME: Add SEND_FAILED support. + */ +void sctp_outqueue_teardown(sctp_outqueue_t *q) { sctp_transport_t *transport; - list_t *lchunk, *pos; - sctp_chunk_t *chunk; + list_t *lchunk, *pos; + sctp_chunk_t *chunk; /* Throw away unacknowledged chunks. */ - list_for_each(pos, &q->asoc->peer.transport_addr_list) { + list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, sctp_transport_t, transports); while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); - } - } /* For all transports. */ + sctp_free_chunk(chunk); + } + } /* Throw away any leftover chunks. */ - while((chunk = (sctp_chunk_t *)skb_dequeue(&q->out))) { + while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out))) sctp_free_chunk(chunk); - } - -} /* sctp_outqueue_teardown() */ +} -/* Free the outqueue structure and any related pending chunks. */ -void -sctp_outqueue_free(sctp_outqueue_t *q) +/* Free the outqueue structure and any related pending chunks. */ +void sctp_outqueue_free(sctp_outqueue_t *q) { /* Throw away leftover chunks. */ sctp_outqueue_teardown(q); - /* If we were kmalloc()'d, free the memory. */ - if (q->malloced) { - kfree(q); - } - -} /* sctp_outqueue_free() */ + /* If we were kmalloc()'d, free the memory. */ + if (q->malloced) + kfree(q); +} /* Transmit any pending partial chunks. */ -void -sctp_force_outqueue(sctp_outqueue_t *q) +void sctp_force_outqueue(sctp_outqueue_t *q) { /* Do we really need this? */ - /* BUG */ -} /* sctp_force_outqueue() */ + /* BUG */ +} -/* Put a new chunk in an SCTP_outqueue. */ -int -sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) +/* Put a new chunk in an SCTP_outqueue. */ +int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) { - int error = 0; + int error = 0; SCTP_DEBUG_PRINTK("sctp_push_outqueue(%p, %p[%s])\n", q, chunk, chunk && chunk->chunk_hdr ? sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) - : "Illegal Chunk"); - - /* If it is data, queue it up, otherwise, send it - * immediately. - */ - if (SCTP_CID_DATA == chunk->chunk_hdr->type) { - /* Is it OK to queue data chunks? */ - /* From 9. Termination of Association - * - * When either endpoint performs a shutdown, the - * association on each peer will stop accepting new - * data from its user and only deliver data in queue - * at the time of sending or receiving the SHUTDOWN - * chunk. - */ - switch(q->asoc->state) { - case SCTP_STATE_EMPTY: - case SCTP_STATE_CLOSED: - case SCTP_STATE_SHUTDOWN_PENDING: - case SCTP_STATE_SHUTDOWN_SENT: - case SCTP_STATE_SHUTDOWN_RECEIVED: - case SCTP_STATE_SHUTDOWN_ACK_SENT: - /* Cannot send after transport endpoint shutdown */ - error = -ESHUTDOWN; - break; - default: + : "Illegal Chunk"); + + /* If it is data, queue it up, otherwise, send it + * immediately. + */ + if (SCTP_CID_DATA == chunk->chunk_hdr->type) { + /* Is it OK to queue data chunks? */ + /* From 9. Termination of Association + * + * When either endpoint performs a shutdown, the + * association on each peer will stop accepting new + * data from its user and only deliver data in queue + * at the time of sending or receiving the SHUTDOWN + * chunk. + */ + switch (q->asoc->state) { + case SCTP_STATE_EMPTY: + case SCTP_STATE_CLOSED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_SENT: + case SCTP_STATE_SHUTDOWN_RECEIVED: + case SCTP_STATE_SHUTDOWN_ACK_SENT: + /* Cannot send after transport endpoint shutdown */ + error = -ESHUTDOWN; + break; + + default: SCTP_DEBUG_PRINTK("outqueueing (%p, %p[%s])\n", - q, chunk, - chunk && chunk->chunk_hdr ? - sctp_cname(SCTP_ST_CHUNK( - chunk->chunk_hdr->type)) - : "Illegal Chunk"); + q, chunk, + chunk && chunk->chunk_hdr ? + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) + : "Illegal Chunk"); - skb_queue_tail(&q->out, - (struct sk_buff *)chunk); - q->empty = 0; - break; - } /* switch() (case It is OK to queue data chunks) */ - } else { - skb_queue_tail(&q->control, (struct sk_buff *)chunk); - } - if (error < 0) { return error; } + skb_queue_tail(&q->out, (struct sk_buff *) chunk); + q->empty = 0; + break; + }; + } else { + skb_queue_tail(&q->control, (struct sk_buff *) chunk); + } + if (error < 0) + return error; error = sctp_flush_outqueue(q, 0); - return error; - -} /* sctp_push_outqueue() */ + return error; +} -/* Mark all the eligible packets on a transport for retransmission and force +/* Mark all the eligible packets on a transport for retransmission and force * one packet out. */ -void -sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, - uint8_t fast_retransmit) +void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, + __u8 fast_retransmit) { struct list_head *lchunk; sctp_chunk_t *chunk; @@ -236,80 +218,72 @@ sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, INIT_LIST_HEAD(&tlist); - while( !list_empty(&transport->transmitted)) { + while (!list_empty(&transport->transmitted)) { lchunk = sctp_list_dequeue(&transport->transmitted); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - /* If we are doing retransmission due to a fast retransmit, - * only the chunk's that are marked for fast retransmit - * should be added to the retransmit queue. If we are doing - * retransmission due to a timeout, only the chunks that are + /* If we are doing retransmission due to a fast retransmit, + * only the chunk's that are marked for fast retransmit + * should be added to the retransmit queue. If we are doing + * retransmission due to a timeout, only the chunks that are * not yet acked should be added to the retransmit queue. */ - - if ((fast_retransmit && !chunk->fast_retransmit) - || (!fast_retransmit && chunk->tsn_gap_acked)) { + if ((fast_retransmit && !chunk->fast_retransmit) || + (!fast_retransmit && chunk->tsn_gap_acked)) { list_add_tail(lchunk, &tlist); } else { /* RFC 2960 6.2.1 Processing a Received SACK - * - * C) Any time a DATA chunk is marked for - * retransmission (via either T3-rtx timer expiration - * (Section 6.3.3) or via fast retransmit - * (Section 7.2.4)), add the data size of those - * chunks to the rwnd. - */ + * + * C) Any time a DATA chunk is marked for + * retransmission (via either T3-rtx timer expiration + * (Section 6.3.3) or via fast retransmit + * (Section 7.2.4)), add the data size of those + * chunks to the rwnd. + */ q->asoc->peer.rwnd += sctp_data_size(chunk); - q->outstanding_bytes -= sctp_data_size(chunk); + q->outstanding_bytes -= sctp_data_size(chunk); transport->flight_size -= sctp_data_size(chunk); - /* sctpimpguide-05 Section 2.8.2 - * M5) If a T3-rtx timer expires, the - * 'TSN.Missing.Report' of all affected TSNs is set + /* sctpimpguide-05 Section 2.8.2 + * M5) If a T3-rtx timer expires, the + * 'TSN.Missing.Report' of all affected TSNs is set * to 0. */ chunk->tsn_missing_report = 0; /* If a chunk that is being used for RTT measurement * has to be retransmitted, we cannot use this chunk - * anymore for RTT measurements. Reset rto_pending so - * that a new RTT measurement is started when a new + * anymore for RTT measurements. Reset rto_pending so + * that a new RTT measurement is started when a new * data chunk is sent. */ if (chunk->rtt_in_progress) { chunk->rtt_in_progress = 0; transport->rto_pending = 0; - } - + } list_add_tail(lchunk, &q->retransmit); } + } - } /* while (we have stuff left on transport->transmitted) */ - - /* Reconstruct the transmitted queue with chunks that are not - * eligible for retransmission. + /* Reconstruct the transmitted queue with chunks that are not + * eligible for retransmission. */ - while( NULL != (lchunk = sctp_list_dequeue(&tlist))) { + while (NULL != (lchunk = sctp_list_dequeue(&tlist))) list_add_tail(lchunk, &transport->transmitted); - } - + SCTP_DEBUG_PRINTK(__FUNCTION__": transport: %p, fast_retransmit: %d, " "cwnd: %d, ssthresh: %d, flight_size: %d, " - "pba: %d\n",transport, fast_retransmit, - transport->cwnd, transport->ssthresh, - transport->flight_size, + "pba: %d\n",transport, fast_retransmit, + transport->cwnd, transport->ssthresh, + transport->flight_size, transport->partial_bytes_acked); - error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); - - if (error) { - q->asoc->base.sk->err = -error; - } - -} /* sctp_retransmit() */ + error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); + if (error) + q->asoc->base.sk->err = -error; +} -/* +/* * Transmit DATA chunks on the retransmit queue. Upon return from * sctp_flush_retran_queue() the packet 'pkt' may contain chunks which * need to be transmitted by the caller. @@ -317,11 +291,9 @@ sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, * * The return value is a normal kernel error return value. */ -static int -sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, - int rtx_timeout, int *start_timer) +static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, + int rtx_timeout, int *start_timer) { - struct list_head *lqueue; struct list_head *lchunk; sctp_transport_t *transport = pkt->transport; @@ -332,7 +304,7 @@ sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, asoc = q->asoc; lqueue = &q->retransmit; - + /* RFC 2960 6.3.3 Handle T3-rtx Expiration * * E3) Determine how many of the earliest (i.e., lowest TSN) @@ -349,36 +321,29 @@ sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, * because a timeout just happened, we should send only ONE * packet of retransmitted data.] */ - - lchunk = sctp_list_dequeue(lqueue); - while (NULL != lchunk) { - + while (lchunk) { chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - #if 0 /* If a chunk has been tried for more than SCTP_DEF_MAX_SEND * times, discard it, and check the empty flag of the outqueue. * * --xguo */ - - if ( chunk->snd_count > SCTP_DEF_MAX_SEND ) { + if (chunk->snd_count > SCTP_DEF_MAX_SEND) { sctp_free_chunk(chunk); continue; } #endif /* Attempt to append this chunk to the packet. */ status = (*q->append_output)(pkt, chunk); - + switch (status) { case SCTP_XMIT_PMTU_FULL: - /* Send this packet. */ - if ( (error = (*q->force_output)(pkt)) == 0 ) { + if ((error = (*q->force_output)(pkt)) == 0) *start_timer = 1; - } /* If we are retransmitting, we should only * send a single packet. @@ -387,15 +352,14 @@ sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, list_add(lchunk, lqueue); lchunk = NULL; } - + /* Bundle lchunk in the next round. */ break; - case SCTP_XMIT_RWND_FULL: + case SCTP_XMIT_RWND_FULL: /* Send this packet. */ - if ( (error = (*q->force_output)(pkt)) == 0 ) { + if ((error = (*q->force_output)(pkt)) == 0) *start_timer = 1; - } /* Stop sending DATA as there is no more room * at the reciever. @@ -403,6 +367,7 @@ sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, list_add(lchunk, lqueue); lchunk = NULL; break; + default: /* The append was successful, so add this chunk to * the transmitted list. @@ -412,27 +377,24 @@ sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, *start_timer = 1; q->empty = 0; - /* Retrieve a new chunk to bundle. */ + /* Retrieve a new chunk to bundle. */ lchunk = sctp_list_dequeue(lqueue); break; - } - - - } /* while (more retransmit chunks) */ - - return(error); + }; + } -} /* sctp_flush_retran_queue() */ + return error; +} -/* This routine either transmits the fragment or puts it on the output +/* This routine either transmits the fragment or puts it on the output * queue. 'pos' points to the next chunk in the output queue after the * chunk that is currently in the process of fragmentation. */ -void -sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, sctp_packet_t *packet, - sctp_chunk_t *frag, uint32_t tsn) +void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, + sctp_packet_t *packet, + sctp_chunk_t *frag, __u32 tsn) { - sctp_transport_t *transport = packet->transport; + sctp_transport_t *transport = packet->transport; struct sk_buff_head *queue = &q->out; sctp_xmit_t status; int error; @@ -440,18 +402,18 @@ sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, sctp_packet_t *packet, frag->subh.data_hdr->tsn = htonl(tsn); frag->has_tsn = 1; - /* An inner fragment may be smaller than the earlier one and may get - * in if we call q->build_output. This ensures that all the fragments - * are sent in order. + /* An inner fragment may be smaller than the earlier one and may get + * in if we call q->build_output. This ensures that all the fragments + * are sent in order. */ - if (!skb_queue_empty(queue)) { + if (!skb_queue_empty(queue)) { SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " - "adding 0x%x to outqueue\n", + "adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); if (pos) { - skb_insert(pos, (struct sk_buff *)frag); + skb_insert(pos, (struct sk_buff *) frag); } else { - skb_queue_tail(queue, (struct sk_buff *)frag); + skb_queue_tail(queue, (struct sk_buff *) frag); } return; } @@ -462,55 +424,55 @@ sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, sctp_packet_t *packet, case SCTP_XMIT_RWND_FULL: /* RWND is full, so put the chunk in the output queue. */ SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " - "adding 0x%x to outqueue\n", + "adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); if (pos) { - skb_insert(pos, (struct sk_buff *)frag); + skb_insert(pos, (struct sk_buff *) frag); } else { - skb_queue_tail(queue, (struct sk_buff *)frag); + skb_queue_tail(queue, (struct sk_buff *) frag); } - break; + break; + case SCTP_XMIT_OK: error = (*q->force_output)(packet); if (error < 0) { - /* Packet could not be transmitted, put the chunk in - * the output queue - */ + /* Packet could not be transmitted, put the chunk in + * the output queue + */ SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "failed. adding 0x%x to outqueue\n", + "failed. adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); if (pos) { - skb_insert(pos, (struct sk_buff *)frag); + skb_insert(pos, (struct sk_buff *) frag); } else { - skb_queue_tail(queue, (struct sk_buff *)frag); + skb_queue_tail(queue, (struct sk_buff *) frag); } } else { SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "success. 0x%x sent\n", + "success. 0x%x sent\n", ntohl(frag->subh.data_hdr->tsn)); list_add_tail(&frag->transmitted_list, - &transport->transmitted); + &transport->transmitted); sctp_transport_reset_timers(transport); - } + } break; + default: BUG(); - } - -} /* sctp_xmit_frag() */ + }; +} -/* This routine calls sctp_xmit_frag() for all the fragments of a message. - * The argument 'frag' point to the first fragment and it holds the list +/* This routine calls sctp_xmit_frag() for all the fragments of a message. + * The argument 'frag' point to the first fragment and it holds the list * of all the other fragments in the 'frag_list' field. - */ -void -sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, - sctp_chunk_t *frag) + */ +void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, + sctp_chunk_t *frag) { sctp_association_t *asoc = frag->asoc; struct list_head *lfrag, *frag_list; - uint32_t tsn; + __u32 tsn; int nfrags = 1; struct sk_buff *pos; @@ -520,50 +482,49 @@ sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, nfrags++; } - /* Get a TSN block of nfrags TSNs. */ + /* Get a TSN block of nfrags TSNs. */ tsn = __sctp_association_get_tsn_block(asoc, nfrags); pos = skb_peek(&q->out); - /* Transmit the first fragment. */ + /* Transmit the first fragment. */ sctp_xmit_frag(q, pos, packet, frag, tsn++); - /* Transmit the rest of fragments. */ + /* Transmit the rest of fragments. */ frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { + list_for_each(lfrag, frag_list) { frag = list_entry(lfrag, sctp_chunk_t, frag_list); sctp_xmit_frag(q, pos, packet, frag, tsn++); } - -} /* sctp_xmit_fragmented_chunks() */ - -/* This routine breaks the given chunk into 'max_frag_data_len' size - * fragments. It returns the first fragment with the frag_list field holding - * the remaining fragments. - */ -sctp_chunk_t * -sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) +} + +/* This routine breaks the given chunk into 'max_frag_data_len' size + * fragments. It returns the first fragment with the frag_list field holding + * the remaining fragments. + */ +sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) { sctp_association_t *asoc = chunk->asoc; void *data_ptr = chunk->subh.data_hdr; struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; - uint16_t chunk_data_len = sctp_data_size(chunk); - uint16_t ssn = ntohs(chunk->subh.data_hdr->ssn); + __u16 chunk_data_len = sctp_data_size(chunk); + __u16 ssn = ntohs(chunk->subh.data_hdr->ssn); sctp_chunk_t *first_frag, *frag; struct list_head *frag_list; - int nfrags; + int nfrags; /* nfrags = no. of max size fragments + any smaller last fragment. */ - nfrags = ((chunk_data_len / max_frag_data_len) + - ((chunk_data_len % max_frag_data_len) ? 1 : 0)); + nfrags = ((chunk_data_len / max_frag_data_len) + + ((chunk_data_len % max_frag_data_len) ? 1 : 0)); /* Start of the data in the chunk. */ data_ptr += sizeof(sctp_datahdr_t); /* Make the first fragment. */ - first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, data_ptr, SCTP_DATA_FIRST_FRAG, ssn); - if (!first_frag) { goto err; } + if (!first_frag) + goto err; /* All the fragments are added to the frag_list of the first chunk. */ frag_list = &first_frag->frag_list; @@ -573,37 +534,38 @@ sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) /* Make the middle fragments. */ while (chunk_data_len > max_frag_data_len) { + frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, + data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); + if (!frag) + goto err; - frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); - if (!frag) { goto err; } - - /* Add the middle fragment to the first fragment's frag_list.*/ - list_add_tail(&frag->frag_list, frag_list); + /* Add the middle fragment to the first fragment's frag_list. */ + list_add_tail(&frag->frag_list, frag_list); chunk_data_len -= max_frag_data_len; data_ptr += max_frag_data_len; } /* Make the last fragment. */ - frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, - SCTP_DATA_LAST_FRAG, ssn); - if (!frag) { goto err; } + frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, + SCTP_DATA_LAST_FRAG, ssn); + if (!frag) + goto err; /* Add the last fragment to the first fragment's frag_list. */ - list_add_tail(&frag->frag_list, frag_list); + list_add_tail(&frag->frag_list, frag_list); /* Free the original chunk. */ - sctp_free_chunk(chunk); + sctp_free_chunk(chunk); - return (first_frag); + return first_frag; err: - /* Free any fragments that are created before the failure. */ + /* Free any fragments that are created before the failure. */ if (first_frag) { struct list_head *flist, *lfrag; - - /* Free all the fragments off the first one. */ + + /* Free all the fragments off the first one. */ flist = &first_frag->frag_list; while (NULL != (lfrag = sctp_list_dequeue(flist))) { frag = list_entry(lfrag, sctp_chunk_t, frag_list); @@ -613,32 +575,29 @@ err: /* Free the first fragment. */ sctp_free_chunk(first_frag); } - - return(NULL); - -} /* sctp_fragment_chunk() */ + return NULL; +} /* * sctp_flush_outqueue - Try to flush an outqueue. - * + * * Description: Send everything in q which we legally can, subject to * congestion limitations. - * + * * Note: This function can be called from multiple contexts so appropriate * locking concerns must be made. Today we use the sock lock to protect - * this function. + * this function. */ -int -sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) +int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) { sctp_packet_t *packet; sctp_packet_t singleton; sctp_association_t *asoc = q->asoc; int ecn_capable = asoc->peer.ecn_capable; - uint16_t sport = asoc->base.bind_addr.port; - uint16_t dport = asoc->peer.port; - uint32_t vtag = asoc->peer.i.init_tag; + __u16 sport = asoc->base.bind_addr.port; + __u16 dport = asoc->peer.port; + __u32 vtag = asoc->peer.i.init_tag; /* This is the ECNE handler for singleton packets. */ sctp_packet_phandler_t *s_ecne_handler = NULL; sctp_packet_phandler_t *ecne_handler = NULL; @@ -648,15 +607,13 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) sctp_chunk_t *chunk; sctp_xmit_t status; int error = 0; - int start_timer = 0; + int start_timer = 0; sctp_ulpevent_t *event; - /* These transports have chunks to send. */ struct list_head transport_list; struct list_head *ltransport; - INIT_LIST_HEAD(&transport_list); packet = NULL; @@ -669,38 +626,32 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) * within a SCTP packet in increasing order of TSN. * ... */ - - if ( ecn_capable ) { + if (ecn_capable) { s_ecne_handler = &sctp_get_no_prepend; ecne_handler = &sctp_get_ecne_prepend; } queue = &q->control; while (NULL != (chunk = (sctp_chunk_t *)skb_dequeue(queue))) { - /* Pick the right transport to use. */ new_transport = chunk->transport; - if (new_transport == NULL ) { + if (!new_transport) { new_transport = asoc->peer.active_path; } else if (!new_transport->state.active) { - /* If the chunk is Heartbeat, send it to * chunk->transport, even it's inactive. - */ - if ( chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) { + */ + if (chunk->chunk_hdr->type != SCTP_CID_HEARTBEAT) new_transport = asoc->peer.active_path; - } } /* Are we switching transports? * Take care of transport locks. */ - if ( new_transport != transport ) { - + if (new_transport != transport) { transport = new_transport; - - if ( list_empty(&transport->send_ready) ) { + if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); } @@ -709,7 +660,7 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ecn_capable, ecne_handler); } - switch(chunk->chunk_hdr->type) { + switch (chunk->chunk_hdr->type) { /* * 6.10 Bundling * ... @@ -722,10 +673,12 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) (*q->init_output)(&singleton, transport, sport, dport); (*q->config_output)(&singleton, vtag, ecn_capable, s_ecne_handler); - (void) (*q->build_output)(&singleton, chunk); + (void) (*q->build_output)(&singleton, chunk); error = (*q->force_output)(&singleton); - if (error < 0) {return(error);} + if (error < 0) + return(error); break; + case SCTP_CID_ABORT: case SCTP_CID_SACK: case SCTP_CID_HEARTBEAT: @@ -736,33 +689,34 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) case SCTP_CID_COOKIE_ECHO: case SCTP_CID_COOKIE_ACK: case SCTP_CID_ECN_ECNE: - case SCTP_CID_ECN_CWR: - (void) (*q->build_output)(packet, chunk); + case SCTP_CID_ECN_CWR: + (void) (*q->build_output)(packet, chunk); break; + case SCTP_CID_ASCONF: case SCTP_CID_ASCONF_ACK: - (void) (*q->build_output)(packet, chunk); + (void) (*q->build_output)(packet, chunk); break; + default: /* We built a chunk with an illegal type! */ BUG(); - } /* switch(type) */ - } /* while (more chunks in control queue) */ - - /* Is it OK to send data chunks? */ - switch (asoc->state) { + }; + } - case SCTP_STATE_COOKIE_ECHOED: + /* Is it OK to send data chunks? */ + switch (asoc->state) { + case SCTP_STATE_COOKIE_ECHOED: /* Only allow bundling, if this packet has a COOKIE-ECHO * chunk. */ - if (packet && !packet->has_cookie_echo) { + if (packet && !packet->has_cookie_echo) break; - } - case SCTP_STATE_ESTABLISHED: - case SCTP_STATE_SHUTDOWN_PENDING: - case SCTP_STATE_SHUTDOWN_RECEIVED: + /* fallthru */ + case SCTP_STATE_ESTABLISHED: + case SCTP_STATE_SHUTDOWN_PENDING: + case SCTP_STATE_SHUTDOWN_RECEIVED: /* * RFC 2960 6.1 Transmission of DATA Chunks * @@ -772,21 +726,19 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) * are marked for retransmission (limited by the * current cwnd). */ - - if ( !list_empty(&q->retransmit) ) { - if ( transport == asoc->peer.retran_path ) { + if (!list_empty(&q->retransmit)) { + if (transport == asoc->peer.retran_path) goto retran; - } - + /* Switch transports & prepare the packet. */ transport = asoc->peer.retran_path; - if ( list_empty(&transport->send_ready) ) { + if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); } - + packet = &transport->packet; (*q->config_output)(packet, vtag, ecn_capable, ecne_handler); @@ -796,60 +748,52 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) rtx_timeout, &start_timer); - if (start_timer) { + if (start_timer) sctp_transport_reset_timers(transport); - } - - } /* if (we have chunks for retransmission) */ + } /* Finally, transmit new packets. */ - start_timer = 0; - queue = &q->out; - while (NULL != (chunk = (sctp_chunk_t *) - skb_dequeue(queue))) { - + start_timer = 0; + queue = &q->out; + while (NULL != (chunk = (sctp_chunk_t *) skb_dequeue(queue))) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid - * stream identifier. + * stream identifier. */ - if (chunk->sinfo.sinfo_stream >= - asoc->c.sinit_num_ostreams) { - + if (chunk->sinfo.sinfo_stream >= + asoc->c.sinit_num_ostreams) { /* Generate a SEND FAILED event. */ event = sctp_ulpevent_make_send_failed(asoc, - chunk, SCTP_DATA_UNSENT, - SCTP_ERROR_INV_STRM, + chunk, SCTP_DATA_UNSENT, + SCTP_ERROR_INV_STRM, GFP_ATOMIC); if (event) { - sctp_ulpqueue_tail_event(&asoc->ulpq, - event); + sctp_ulpqueue_tail_event(&asoc->ulpq, + event); } - /* Free the chunk. This chunk is not on any - * list yet, just free it. */ + /* Free the chunk. This chunk is not on any + * list yet, just free it. + */ sctp_free_chunk(chunk); - continue; - } + /* If there is a specified transport, use it. * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - - if ( new_transport == NULL - || !new_transport->state.active ) { + if (new_transport == NULL || + !new_transport->state.active) new_transport = asoc->peer.active_path; - } /* Change packets if necessary. */ - if ( new_transport != transport ) { - + if (new_transport != transport) { transport = new_transport; /* Schedule to have this transport's * packet flushed. */ - if ( list_empty(&transport->send_ready) ) { + if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); } @@ -858,10 +802,10 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) (*q->config_output)(packet, vtag, ecn_capable, ecne_handler); } - + SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ", - q, chunk, - chunk && chunk->chunk_hdr ? + q, chunk, + chunk && chunk->chunk_hdr ? sctp_cname(SCTP_ST_CHUNK( chunk->chunk_hdr->type)) : "Illegal Chunk"); @@ -869,10 +813,10 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) SCTP_DEBUG_PRINTK("TX TSN 0x%x skb->head " "%p skb->users %d.\n", ntohl(chunk->subh.data_hdr->tsn), - chunk->skb?chunk->skb->head:0, - chunk->skb? - (int)atomic_read(&chunk->skb->users) - :-1); + chunk->skb ?chunk->skb->head : 0, + chunk->skb ? + atomic_read(&chunk->skb->users) : + -1); /* Add the chunk to the packet. */ status = (*q->build_output)(packet, chunk); @@ -889,37 +833,39 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) skb_queue_head(queue, (struct sk_buff *)chunk); goto sctp_flush_out; break; - case SCTP_XMIT_MUST_FRAG: - { + + case SCTP_XMIT_MUST_FRAG: { sctp_chunk_t *frag; - frag = sctp_fragment_chunk(chunk, + frag = sctp_fragment_chunk(chunk, packet->transport->asoc->frag_point); if (!frag) { /* We could not fragment due to out of - * memory condition. Free the original - * chunk and return ENOMEM. + * memory condition. Free the original + * chunk and return ENOMEM. */ sctp_free_chunk(chunk); error = -ENOMEM; - return (error); + return error; } sctp_xmit_fragmented_chunks(q, packet, frag); goto sctp_flush_out; break; } + case SCTP_XMIT_OK: break; + default: BUG(); - } - + }; + /* BUG: We assume that the (*q->force_output()) - * call below will succeed all the time and add the - * chunk to the transmitted list and restart the - * timers. - * It is possible that the call can fail under OOM + * call below will succeed all the time and add the + * chunk to the transmitted list and restart the + * timers. + * It is possible that the call can fail under OOM * conditions. * * Is this really a problem? Won't this behave @@ -931,70 +877,65 @@ sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) sctp_transport_reset_timers(transport); q->empty = 0; - } - break; - default: - /* Do nothing. */ - break; - } /* switch ()(case It is OK to send data chunks:) */ - - sctp_flush_out: + } + break; + + default: + /* Do nothing. */ + break; + }; + +sctp_flush_out: /* Before returning, examine all the transports touched in * this call. Right now, we bluntly force clear all the * transports. Things might change after we implement Nagle. * But such an examination is still required. - * + * * --xguo */ - while ( (ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { + while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { sctp_transport_t *t = list_entry(ltransport, sctp_transport_t, send_ready); - if ( t != transport ) { + if (t != transport) transport = t; - } packet = &transport->packet; - if ( packet->size != SCTP_IP_OVERHEAD ) { + if (packet->size != SCTP_IP_OVERHEAD) error = (*q->force_output)(packet); - } - } - - return(error); + } -} /* sctp_flush_outqueue() */ + return error; +} -/* Set the various output handling callbacks. */ -int -sctp_outqueue_set_output_handlers(sctp_outqueue_t *q, - sctp_outqueue_ohandler_init_t init, - sctp_outqueue_ohandler_config_t config, - sctp_outqueue_ohandler_t append, - sctp_outqueue_ohandler_t build, - sctp_outqueue_ohandler_force_t force) +/* Set the various output handling callbacks. */ +int sctp_outqueue_set_output_handlers(sctp_outqueue_t *q, + sctp_outqueue_ohandler_init_t init, + sctp_outqueue_ohandler_config_t config, + sctp_outqueue_ohandler_t append, + sctp_outqueue_ohandler_t build, + sctp_outqueue_ohandler_force_t force) { - q->init_output = init; - q->config_output = config; - q->append_output = append; - q->build_output = build; - q->force_output = force; + q->init_output = init; + q->config_output = config; + q->append_output = append; + q->build_output = build; + q->force_output = force; return 0; - -} /* sctp_outqueue_set_out_handler() */ - +} /* Update unack_data based on the incoming SACK chunk */ -static void -sctp_sack_update_unack_data(sctp_association_t *assoc, sctp_sackhdr_t *sack) +static void sctp_sack_update_unack_data(sctp_association_t *assoc, + sctp_sackhdr_t *sack) { sctp_sack_variable_t *frags; - uint16_t unack_data; + __u16 unack_data; int i; unack_data = assoc->next_tsn - assoc->ctsn_ack_point - 1; frags = sack->variable; for (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) { - unack_data -= ((ntohs(frags[i].gab.end) - + unack_data -= ((ntohs(frags[i].gab.end) - ntohs(frags[i].gab.start) + 1)); } @@ -1006,72 +947,70 @@ sctp_sack_update_unack_data(sctp_association_t *assoc, sctp_sackhdr_t *sack) * Process the sack against the outqueue. Mostly, this just frees * things off the transmitted queue. */ -int -sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) +int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) { - sctp_chunk_t *tchunk; - list_t *lchunk, *transport_list, *pos; - uint32_t tsn; - uint32_t sack_ctsn; - uint32_t ctsn; + sctp_chunk_t *tchunk; + list_t *lchunk, *transport_list, *pos; + __u32 tsn; + __u32 sack_ctsn; + __u32 ctsn; sctp_transport_t *transport; int outstanding; - uint32_t sack_a_rwnd; + __u32 sack_a_rwnd; /* Grab the association's destination address list. */ transport_list = &q->asoc->peer.transport_addr_list; - + /* Run through the retransmit queue. Credit bytes received - * and free those chunks that we can. + * and free those chunks that we can. */ sctp_check_transmitted(q, &q->retransmit, NULL, sack); - /* Run through the transmitted queue. - * Credit bytes received and free those chunks which we can. - * - * This is a MASSIVE candidate for optimization. - */ - list_for_each(pos, transport_list) { - transport = list_entry(pos, sctp_transport_t, transports); - sctp_check_transmitted(q, &transport->transmitted, - transport, sack); - } - - /* Move the Cumulative TSN Ack Point if appropriate. */ - sack_ctsn = ntohl(sack->cum_tsn_ack); - if (TSN_lt(q->asoc->ctsn_ack_point, sack_ctsn)) { - q->asoc->ctsn_ack_point = sack_ctsn; - } + /* Run through the transmitted queue. + * Credit bytes received and free those chunks which we can. + * + * This is a MASSIVE candidate for optimization. + */ + list_for_each(pos, transport_list) { + transport = list_entry(pos, sctp_transport_t, transports); + sctp_check_transmitted(q, &transport->transmitted, + transport, sack); + } + + /* Move the Cumulative TSN Ack Point if appropriate. */ + sack_ctsn = ntohl(sack->cum_tsn_ack); + if (TSN_lt(q->asoc->ctsn_ack_point, sack_ctsn)) + q->asoc->ctsn_ack_point = sack_ctsn; /* Update unack_data field in the assoc. */ sctp_sack_update_unack_data(q->asoc, sack); - ctsn = q->asoc->ctsn_ack_point; + ctsn = q->asoc->ctsn_ack_point; SCTP_DEBUG_PRINTK(__FUNCTION__ ": sack Cumulative TSN Ack is 0x%x.\n", sack_ctsn); SCTP_DEBUG_PRINTK(__FUNCTION__ ": Cumulative TSN Ack of association " - "%p is 0x%x.\n",q->asoc, ctsn); - - /* Throw away stuff rotting on the sack queue. */ - list_for_each(lchunk, &q->sacked) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - tsn = ntohl(tchunk->subh.data_hdr->tsn); - if (TSN_lte(tsn, ctsn)){ - lchunk = lchunk->prev; - sctp_free_chunk(tchunk); - } - } - - /* ii) Set rwnd equal to the newly received a_rwnd minus the - * number of bytes still outstanding after processing the - * Cumulative TSN Ack and the Gap Ack Blocks. - */ - - sack_a_rwnd = ntohl(sack->a_rwnd); + "%p is 0x%x.\n",q->asoc, ctsn); + + /* Throw away stuff rotting on the sack queue. */ + list_for_each(lchunk, &q->sacked) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + if (TSN_lte(tsn, ctsn)) { + lchunk = lchunk->prev; + sctp_free_chunk(tchunk); + } + } + + /* ii) Set rwnd equal to the newly received a_rwnd minus the + * number of bytes still outstanding after processing the + * Cumulative TSN Ack and the Gap Ack Blocks. + */ + + sack_a_rwnd = ntohl(sack->a_rwnd); outstanding = q->outstanding_bytes; - - if (outstanding < sack_a_rwnd) { + + if (outstanding < sack_a_rwnd) { sack_a_rwnd -= outstanding; } else { sack_a_rwnd = 0; @@ -1079,34 +1018,30 @@ sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) q->asoc->peer.rwnd = sack_a_rwnd; - - /* See if all chunks are acked. - * Make sure the empty queue handler will get run later. - */ - - q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit); - if (!q->empty) { goto finish; } + /* See if all chunks are acked. + * Make sure the empty queue handler will get run later. + */ + q->empty = skb_queue_empty(&q->out) && list_empty(&q->retransmit); + if (!q->empty) + goto finish; list_for_each(pos, transport_list) { transport = list_entry(pos, sctp_transport_t, transports); q->empty = q->empty && list_empty(&transport->transmitted); - if (!q->empty) { goto finish; } + if (!q->empty) + goto finish; } SCTP_DEBUG_PRINTK("sack queue is empty.\n"); - - finish: - return(q->empty); - -} /* sctp_sack_outqueue() */ +finish: + return q->empty; +} /* Is the outqueue empty? */ -int -sctp_outqueue_is_empty(const sctp_outqueue_t *q) +int sctp_outqueue_is_empty(const sctp_outqueue_t *q) { - return(q->empty); - -} /* sctp_outqueue_is_empty() */ + return q->empty; +} /******************************************************************** * 2nd Level Abstractions @@ -1115,9 +1050,9 @@ sctp_outqueue_is_empty(const sctp_outqueue_t *q) /* Go through a transport's transmitted list or the assocication's retransmit * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. * The retransmit list will not have an associated transport. In case of a - * transmitted list with a transport, the transport's congestion, rto and fast + * transmitted list with a transport, the transport's congestion, rto and fast * retransmit parameters are also updated and if needed a fast retransmit - * process is started. + * process is started. * * I added coherent debug information output. --xguo * @@ -1125,30 +1060,29 @@ sctp_outqueue_is_empty(const sctp_outqueue_t *q) * transmitted_queue, we print a range: SACKED: TSN1-TSN2, TSN3, TSN4-TSN5. * KEPT TSN6-TSN7, etc. */ -static void -sctp_check_transmitted(sctp_outqueue_t *q, - struct list_head *transmitted_queue, - sctp_transport_t *transport, - sctp_sackhdr_t *sack) +static void sctp_check_transmitted(sctp_outqueue_t *q, + struct list_head *transmitted_queue, + sctp_transport_t *transport, + sctp_sackhdr_t *sack) { - struct list_head *lchunk; - sctp_chunk_t *tchunk; - struct list_head tlist; - uint32_t tsn; - uint32_t sack_ctsn; - uint32_t rtt; - uint32_t highest_new_tsn_in_sack; - uint8_t restart_timer = 0; - uint8_t do_fast_retransmit = 0; + struct list_head *lchunk; + sctp_chunk_t *tchunk; + struct list_head tlist; + __u32 tsn; + __u32 sack_ctsn; + __u32 rtt; + __u32 highest_new_tsn_in_sack; + __u8 restart_timer = 0; + __u8 do_fast_retransmit = 0; int bytes_acked = 0; /* These state variables are for coherent debug output. --xguo */ #if SCTP_DEBUG - uint32_t dbg_ack_tsn = 0; /* An ACKed TSN range starts here... */ - uint32_t dbg_last_ack_tsn = 0; /* ...and finishes here. */ - uint32_t dbg_kept_tsn = 0; /* An un-ACKed range starts here... */ - uint32_t dbg_last_kept_tsn = 0; /* ...and finishes here. */ + __u32 dbg_ack_tsn = 0; /* An ACKed TSN range starts here... */ + __u32 dbg_last_ack_tsn = 0; /* ...and finishes here. */ + __u32 dbg_kept_tsn = 0; /* An un-ACKed range starts here... */ + __u32 dbg_last_kept_tsn = 0; /* ...and finishes here. */ /* 0 : The last TSN was ACKed. * 1 : The last TSN was NOT ACKed (i.e. KEPT). @@ -1160,115 +1094,109 @@ sctp_check_transmitted(sctp_outqueue_t *q, sack_ctsn = ntohl(sack->cum_tsn_ack); highest_new_tsn_in_sack = sack_ctsn; - INIT_LIST_HEAD(&tlist); - - /* The while loop will skip empty transmitted queues. */ - while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { - - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - - tsn = ntohl(tchunk->subh.data_hdr->tsn); + INIT_LIST_HEAD(&tlist); - if (sctp_acked(sack, tsn)) { + /* The while loop will skip empty transmitted queues. */ + while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); + if (sctp_acked(sack, tsn)) { /* If this queue is the retransmit queue, the * retransmit timer has already reclaimed * the outstanding bytes for this chunk, so only * count bytes associated with a transport. */ if (transport) { - - /* If this chunk is being used for RTT - * measurement, calculate the RTT and update - * the RTO using this value. - * - * 6.3.1 C5) Karn's algorithm: RTT measurements - * MUST NOT be made using packets that were - * retransmitted (and thus for which it is - * ambiguous whether the reply was for the first - * instance of the packet or a later instance). - */ + /* If this chunk is being used for RTT + * measurement, calculate the RTT and update + * the RTO using this value. + * + * 6.3.1 C5) Karn's algorithm: RTT measurements + * MUST NOT be made using packets that were + * retransmitted (and thus for which it is + * ambiguous whether the reply was for the first + * instance of the packet or a later instance). + */ if ((!tchunk->tsn_gap_acked) && (1 == tchunk->num_times_sent) && (tchunk->rtt_in_progress)) { rtt = jiffies - tchunk->sent_at; - sctp_transport_update_rto(transport, + sctp_transport_update_rto(transport, rtt); } - } - + } if (TSN_lte(tsn, sack_ctsn)) { - /* RFC 2960 6.3.2 Retransmission Timer Rules - * - * R3) Whenever a SACK is received - * that acknowledges the DATA chunk - * with the earliest outstanding TSN - * for that address, restart T3-rtx - * timer for that address with its - * current RTO. - */ - restart_timer = 1; - + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R3) Whenever a SACK is received + * that acknowledges the DATA chunk + * with the earliest outstanding TSN + * for that address, restart T3-rtx + * timer for that address with its + * current RTO. + */ + restart_timer = 1; + if (!tchunk->tsn_gap_acked) { tchunk->tsn_gap_acked = 1; bytes_acked += sctp_data_size(tchunk); } - list_add_tail(&tchunk->transmitted_list, + list_add_tail(&tchunk->transmitted_list, &q->sacked); - } else { - /* RFC2960 7.2.4, sctpimpguide-05 2.8.2 - * M2) Each time a SACK arrives reporting - * 'Stray DATA chunk(s)' record the highest TSN - * reported as newly acknowledged, call this - * value 'HighestTSNinSack'. A newly - * acknowledged DATA chunk is one not previously - * acknowledged in a SACK. - * - * When the SCTP sender of data receives a SACK - * chunk that acknowledges, for the first time, - * the receipt of a DATA chunk, all the still - * unacknowledged DATA chunks whose TSN is older - * than that newly acknowledged DATA chunk, are - * qualified as 'Stray DATA chunks'. - */ + } else { + /* RFC2960 7.2.4, sctpimpguide-05 2.8.2 + * M2) Each time a SACK arrives reporting + * 'Stray DATA chunk(s)' record the highest TSN + * reported as newly acknowledged, call this + * value 'HighestTSNinSack'. A newly + * acknowledged DATA chunk is one not previously + * acknowledged in a SACK. + * + * When the SCTP sender of data receives a SACK + * chunk that acknowledges, for the first time, + * the receipt of a DATA chunk, all the still + * unacknowledged DATA chunks whose TSN is older + * than that newly acknowledged DATA chunk, are + * qualified as 'Stray DATA chunks'. + */ if (!tchunk->tsn_gap_acked) { tchunk->tsn_gap_acked = 1; bytes_acked += sctp_data_size(tchunk); - if (TSN_lt(highest_new_tsn_in_sack, + if (TSN_lt(highest_new_tsn_in_sack, tsn)) { highest_new_tsn_in_sack = tsn; } } - - list_add_tail(lchunk, &tlist); + list_add_tail(lchunk, &tlist); } - + #if SCTP_DEBUG - switch ( dbg_prt_state ) { + switch (dbg_prt_state) { case 0: /* last TSN was ACKed */ - if ( dbg_last_ack_tsn + 1 == tsn ) { + if (dbg_last_ack_tsn + 1 == tsn) { /* This TSN belongs to the * current ACK range. - */ + */ break; } - if ( dbg_last_ack_tsn != dbg_ack_tsn ) { + if (dbg_last_ack_tsn != dbg_ack_tsn) { /* Display the end of the * current range. - */ + */ SCTP_DEBUG_PRINTK("-%08x", dbg_last_ack_tsn); } /* Start a new range. */ - SCTP_DEBUG_PRINTK(",%08x",tsn); + SCTP_DEBUG_PRINTK(",%08x", tsn); dbg_ack_tsn = tsn; - break; + case 1: /* The last TSN was NOT ACKed. */ - if ( dbg_last_kept_tsn != dbg_kept_tsn ) { + if (dbg_last_kept_tsn != dbg_kept_tsn) { /* Display the end of current range. */ SCTP_DEBUG_PRINTK("-%08x", dbg_last_kept_tsn); @@ -1277,33 +1205,34 @@ sctp_check_transmitted(sctp_outqueue_t *q, SCTP_DEBUG_PRINTK("\n"); /* FALL THROUGH... */ - default: - /* This is the first-ever TSN we examined. */ - /* Start a new range of ACK-ed TSNs. */ - SCTP_DEBUG_PRINTK("ACKed: %08x",tsn); + default: + /* This is the first-ever TSN we examined. */ + /* Start a new range of ACK-ed TSNs. */ + SCTP_DEBUG_PRINTK("ACKed: %08x", tsn); dbg_prt_state = 0; dbg_ack_tsn = tsn; - } + }; + dbg_last_ack_tsn = tsn; -#endif /* SCTP_DEBUG */ +#endif /* SCTP_DEBUG */ - } else { + } else { if (tchunk->tsn_gap_acked) { - SCTP_DEBUG_PRINTK(__FUNCTION__ + SCTP_DEBUG_PRINTK(__FUNCTION__ ": Receiver reneged on data " "TSN: 0x%x\n", tsn); tchunk->tsn_gap_acked = 0; - - bytes_acked -= sctp_data_size(tchunk); - /* RFC 2960 6.3.2 Retransmission Timer Rules - * - * R4) Whenever a SACK is received missing a TSN - * that was previously acknowledged via a Gap Ack - * Block, start T3-rtx for the destination - * address to which the DATA chunk was originally - * transmitted if it is not already running. - */ + bytes_acked -= sctp_data_size(tchunk); + + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R4) Whenever a SACK is received missing a TSN + * that was previously acknowledged via a Gap Ack + * Block, start T3-rtx for the destination + * address to which the DATA chunk was originally + * transmitted if it is not already running. + */ restart_timer = 1; } @@ -1311,19 +1240,21 @@ sctp_check_transmitted(sctp_outqueue_t *q, #if SCTP_DEBUG /* See the above comments on ACK-ed TSNs. */ - switch ( dbg_prt_state ) { + switch (dbg_prt_state) { case 1: - if ( dbg_last_kept_tsn + 1 == tsn ) { break; } + if (dbg_last_kept_tsn + 1 == tsn) + break; - if ( dbg_last_kept_tsn != dbg_kept_tsn ) + if (dbg_last_kept_tsn != dbg_kept_tsn) SCTP_DEBUG_PRINTK("-%08x", dbg_last_kept_tsn); - SCTP_DEBUG_PRINTK(",%08x",tsn); + SCTP_DEBUG_PRINTK(",%08x", tsn); dbg_kept_tsn = tsn; break; + case 0: - if ( dbg_last_ack_tsn != dbg_ack_tsn ) + if (dbg_last_ack_tsn != dbg_ack_tsn) SCTP_DEBUG_PRINTK("-%08x", dbg_last_ack_tsn); SCTP_DEBUG_PRINTK("\n"); @@ -1333,48 +1264,52 @@ sctp_check_transmitted(sctp_outqueue_t *q, SCTP_DEBUG_PRINTK("KEPT: %08x",tsn); dbg_prt_state = 1; dbg_kept_tsn = tsn; - } + }; + dbg_last_kept_tsn = tsn; #endif /* SCTP_DEBUG */ - - } /* if (TSN has just been ACKd) */ - }; /* while (transmitted queue is not empty) */ + } + } #if SCTP_DEBUG - /* Finish off the last range, displaying its ending TSN. */ - switch ( dbg_prt_state ) { - case 0: if ( dbg_last_ack_tsn != dbg_ack_tsn ) { - SCTP_DEBUG_PRINTK("-%08x\n",dbg_last_ack_tsn); - } else { SCTP_DEBUG_PRINTK("\n"); } + /* Finish off the last range, displaying its ending TSN. */ + switch (dbg_prt_state) { + case 0: + if (dbg_last_ack_tsn != dbg_ack_tsn) { + SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_ack_tsn); + } else { + SCTP_DEBUG_PRINTK("\n"); + } break; - case 1: if ( dbg_last_kept_tsn != dbg_kept_tsn ) { - SCTP_DEBUG_PRINTK("-%08x\n",dbg_last_kept_tsn); - } else { SCTP_DEBUG_PRINTK("\n"); } - } + case 1: + if (dbg_last_kept_tsn != dbg_kept_tsn) { + SCTP_DEBUG_PRINTK("-%08x\n", dbg_last_kept_tsn); + } else { + SCTP_DEBUG_PRINTK("\n"); + } + }; #endif /* SCTP_DEBUG */ - if (transport) { if (bytes_acked) { - /* 8.2. When an outstanding TSN is acknowledged, - * the endpoint shall clear the error counter of - * the destination transport address to which the + /* 8.2. When an outstanding TSN is acknowledged, + * the endpoint shall clear the error counter of + * the destination transport address to which the * DATA chunk was last sent. - * The association's overall error counter is + * The association's overall error counter is * also cleared. - */ + */ transport->error_count = 0; transport->asoc->overall_error_count = 0; - /* Mark the destination transport address as + /* Mark the destination transport address as * active if it is not so marked. */ if (!transport->state.active) { - sctp_assoc_control_transport( - transport->asoc, - transport, - SCTP_TRANSPORT_UP, - SCTP_RECEIVED_SACK); + sctp_assoc_control_transport(transport->asoc, + transport, + SCTP_TRANSPORT_UP, + SCTP_RECEIVED_SACK); } sctp_transport_raise_cwnd(transport, sack_ctsn, @@ -1383,72 +1318,70 @@ sctp_check_transmitted(sctp_outqueue_t *q, transport->flight_size -= bytes_acked; q->outstanding_bytes -= bytes_acked; } else { - /* RFC 2960 6.1, sctpimpguide-06 2.15.2 - * When a sender is doing zero window probing, it - * should not timeout the association if it continues - * to receive new packets from the receiver. The - * reason is that the receiver MAY keep its window + /* RFC 2960 6.1, sctpimpguide-06 2.15.2 + * When a sender is doing zero window probing, it + * should not timeout the association if it continues + * to receive new packets from the receiver. The + * reason is that the receiver MAY keep its window * closed for an indefinite time. - * A sender is doing zero window probing when the + * A sender is doing zero window probing when the * receiver's advertised window is zero, and there is - * only one data chunk in flight to the receiver. - */ - if ((0 == q->asoc->peer.rwnd) - && (!list_empty(&tlist)) - && (sack_ctsn+2 == q->asoc->next_tsn)) { + * only one data chunk in flight to the receiver. + */ + if ((0 == q->asoc->peer.rwnd) && + (!list_empty(&tlist)) && + (sack_ctsn+2 == q->asoc->next_tsn)) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " - "window probe: %u\n", + "window probe: %u\n", __FUNCTION__, sack_ctsn); q->asoc->overall_error_count = 0; transport->error_count = 0; } } - /* RFC 2960 6.3.2 Retransmission Timer Rules - * - * R2) Whenever all outstanding data sent to an address have - * been acknowledged, turn off the T3-rtx timer of that - * address. - */ - if (!transport->flight_size) { + /* RFC 2960 6.3.2 Retransmission Timer Rules + * + * R2) Whenever all outstanding data sent to an address have + * been acknowledged, turn off the T3-rtx timer of that + * address. + */ + if (!transport->flight_size) { if (timer_pending(&transport->T3_rtx_timer) && del_timer(&transport->T3_rtx_timer)) { sctp_transport_put(transport); } } else if (restart_timer) { if (!mod_timer(&transport->T3_rtx_timer, - jiffies + transport->rto)) { + jiffies + transport->rto)) sctp_transport_hold(transport); - } } - } - /* Reconstruct the transmitted list with chunks that are not yet + /* Reconstruct the transmitted list with chunks that are not yet * acked by the Cumulative TSN Ack. */ - while( NULL != (lchunk = sctp_list_dequeue(&tlist))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - tsn = ntohl(tchunk->subh.data_hdr->tsn); + while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { + tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tsn = ntohl(tchunk->subh.data_hdr->tsn); - /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all - * 'Unacknowledged TSN's', if the TSN number of an + /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all + * 'Unacknowledged TSN's', if the TSN number of an * 'Unacknowledged TSN' is smaller than the 'HighestTSNinSack' - * value, increment the 'TSN.Missing.Report' count on that - * chunk if it has NOT been fast retransmitted or marked for + * value, increment the 'TSN.Missing.Report' count on that + * chunk if it has NOT been fast retransmitted or marked for * fast retransmit already. * - * M4) If any DATA chunk is found to have a - * 'TSN.Missing.Report' - * value larger than or equal to 4, mark that chunk for - * retransmission and start the fast retransmit procedure. + * M4) If any DATA chunk is found to have a + * 'TSN.Missing.Report' + * value larger than or equal to 4, mark that chunk for + * retransmission and start the fast retransmit procedure. */ - if ((!tchunk->fast_retransmit) - && (!tchunk->tsn_gap_acked) - && (TSN_lt(tsn, highest_new_tsn_in_sack))) { + if ((!tchunk->fast_retransmit) && + (!tchunk->tsn_gap_acked) && + (TSN_lt(tsn, highest_new_tsn_in_sack))) { tchunk->tsn_missing_report++; SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", - __FUNCTION__, tsn, + __FUNCTION__, tsn, tchunk->tsn_missing_report); } if (tchunk->tsn_missing_report >= 4) { @@ -1460,56 +1393,49 @@ sctp_check_transmitted(sctp_outqueue_t *q, } if (transport) { - if (do_fast_retransmit) { + if (do_fast_retransmit) sctp_retransmit(q, transport, do_fast_retransmit); - } + SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p, cwnd: %d, " - "ssthresh: %d, flight_size: %d, pba: %d\n", - transport, transport->cwnd, - transport->ssthresh, transport->flight_size, + "ssthresh: %d, flight_size: %d, pba: %d\n", + transport, transport->cwnd, + transport->ssthresh, transport->flight_size, transport->partial_bytes_acked); } - -} /* sctp_check_transmitted() */ +} /* Is the given TSN acked by this packet? */ -static int -sctp_acked(sctp_sackhdr_t *sack, uint32_t tsn) +static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) { - int i; - sctp_sack_variable_t *frags; - uint16_t gap; - uint32_t ctsn = ntohl(sack->cum_tsn_ack); + int i; + sctp_sack_variable_t *frags; + __u16 gap; + __u32 ctsn = ntohl(sack->cum_tsn_ack); - if (TSN_lte(tsn, ctsn)) { + if (TSN_lte(tsn, ctsn)) goto pass; - } - - /* 3.3.4 Selective Acknowledgement (SACK) (3): - * - * Gap Ack Blocks: - * These fields contain the Gap Ack Blocks. They are repeated - * for each Gap Ack Block up to the number of Gap Ack Blocks - * defined in the Number of Gap Ack Blocks field. All DATA - * chunks with TSNs greater than or equal to (Cumulative TSN - * Ack + Gap Ack Block Start) and less than or equal to - * (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack - * Block are assumed to have been received correctly. - */ - - frags = sack->variable; - gap = tsn - ctsn; - for (i = 0; i < ntohs(sack->num_gap_ack_blocks); ++i) { - if (TSN_lte(ntohs(frags[i].gab.start), gap) - && TSN_lte(gap, ntohs(frags[i].gab.end))) { - goto pass; - } - } - - return 0; -pass: - return 1; -} /* sctp_acked() */ + /* 3.3.4 Selective Acknowledgement (SACK) (3): + * + * Gap Ack Blocks: + * These fields contain the Gap Ack Blocks. They are repeated + * for each Gap Ack Block up to the number of Gap Ack Blocks + * defined in the Number of Gap Ack Blocks field. All DATA + * chunks with TSNs greater than or equal to (Cumulative TSN + * Ack + Gap Ack Block Start) and less than or equal to + * (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack + * Block are assumed to have been received correctly. + */ + frags = sack->variable; + gap = tsn - ctsn; + for (i = 0; i < ntohs(sack->num_gap_ack_blocks); ++i) { + if (TSN_lte(ntohs(frags[i].gab.start), gap) && + TSN_lte(gap, ntohs(frags[i].gab.end))) + goto pass; + } + return 0; +pass: + return 1; +} diff --git a/net/sctp/sctp_primitive.c b/net/sctp/sctp_primitive.c index f5d3168ad54c..71eeeaa93cf7 100644 --- a/net/sctp/sctp_primitive.c +++ b/net/sctp/sctp_primitive.c @@ -46,7 +46,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_primitive.c,v 1.6 2002/08/21 18:34:04 jgrimm Exp $"; -#include #include #include /* For struct list_head */ #include @@ -56,40 +55,39 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_primitive.c,v 1.6 2002 #include #include - #define DECLARE_PRIMITIVE(name) \ /* This is called in the code as sctp_primitive_ ## name. */ \ -int \ -sctp_primitive_ ## name(sctp_association_t *asoc, \ - void *arg) { \ - int error = 0; \ - sctp_event_t event_type; sctp_subtype_t subtype; \ +int sctp_primitive_ ## name(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; \ + sctp_endpoint_t *ep; \ + \ + event_type = SCTP_EVENT_T_PRIMITIVE; \ + subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ + state = asoc ? asoc->state : SCTP_STATE_CLOSED; \ + ep = asoc ? asoc->ep : NULL; \ \ - event_type = SCTP_EVENT_T_PRIMITIVE; \ - subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ - state = asoc ? asoc->state : SCTP_STATE_CLOSED; \ - ep = asoc ? asoc->ep : NULL; \ - \ - error = sctp_do_sm(event_type, subtype, state, ep, asoc, arg, GFP_KERNEL); \ - return error; \ -} /* sctp_primitive_ ## name() */ + error = sctp_do_sm(event_type, subtype, state, ep, asoc, \ + arg, GFP_KERNEL); \ + return error; \ +} /* 10.1 ULP-to-SCTP * B) Associate - * - * Format: ASSOCIATE(local SCTP instance name, destination transport addr, - * outbound stream count) + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) * -> association id [,destination transport addr list] [,outbound stream - * count] - * + * count] + * * This primitive allows the upper layer to initiate an association to a - * specific peer endpoint. + * specific peer endpoint. * * This version assumes that asoc is fully populated with the initial * parameters. We then return a traditional kernel indicator of - * success or failure. + * success or failure. */ /* This is called in the code as sctp_primitive_ASSOCIATE. */ @@ -98,10 +96,10 @@ DECLARE_PRIMITIVE(ASSOCIATE) /* 10.1 ULP-to-SCTP * C) Shutdown - * + * * Format: SHUTDOWN(association id) - * -> result - * + * -> result + * * Gracefully closes an association. Any locally queued user data * will be delivered to the peer. The association will be terminated only * after the peer acknowledges all the SCTP packets sent. A success code @@ -114,10 +112,10 @@ DECLARE_PRIMITIVE(SHUTDOWN); /* 10.1 ULP-to-SCTP * C) Abort - * + * * Format: Abort(association id [, cause code]) - * -> result - * + * -> result + * * Ungracefully closes an association. Any locally queued user data * will be discarded and an ABORT chunk is sent to the peer. A success * code will be returned on successful abortion of the association. If @@ -129,83 +127,79 @@ DECLARE_PRIMITIVE(ABORT); /* 10.1 ULP-to-SCTP * E) Send - * + * * Format: SEND(association id, buffer address, byte count [,context] - * [,stream id] [,life time] [,destination transport address] + * [,stream id] [,life time] [,destination transport address] * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) * -> result - * - * This is the main method to send user data via SCTP. - * + * + * This is the main method to send user data via SCTP. + * * Mandatory attributes: - * + * * o association id - local handle to the SCTP association - * + * * o buffer address - the location where the user message to be * transmitted is stored; - * + * * o byte count - The size of the user data in number of bytes; - * + * * Optional attributes: - * + * * o context - an optional 32 bit integer that will be carried in the * sending failure notification to the ULP if the transportation of * this User Message fails. - * + * * o stream id - to indicate which stream to send the data on. If not * specified, stream 0 will be used. - * + * * o life time - specifies the life time of the user data. The user data * will not be sent by SCTP after the life time expires. This * parameter can be used to avoid efforts to transmit stale * user messages. SCTP notifies the ULP if the data cannot be * initiated to transport (i.e. sent to the destination via SCTP's * send primitive) within the life time variable. However, the - * user data will be transmitted if SCTP has attempted to transmit a + * user data will be transmitted if SCTP has attempted to transmit a * chunk before the life time expired. - * + * * o destination transport address - specified as one of the destination * transport addresses of the peer endpoint to which this packet * should be sent. Whenever possible, SCTP should use this destination * transport address for sending the packets, instead of the current - * primary path. - * + * primary path. + * * o unorder flag - this flag, if present, indicates that the user - * would like the data delivered in an unordered fashion to the peer - * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this * message). - * + * * o no-bundle flag - instructs SCTP not to bundle this user data with - * other outbound DATA chunks. SCTP MAY still bundle even when + * other outbound DATA chunks. SCTP MAY still bundle even when * this flag is present, when faced with network congestion. - * - * o payload protocol-id - A 32 bit unsigned integer that is to be - * passed to the peer indicating the type of payload protocol data + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data * being transmitted. This value is passed as opaque data by SCTP. */ DECLARE_PRIMITIVE(SEND); - /* COMMENT BUG. Find out where this is mentioned in the spec. */ -int -sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) +int sctp_other_icmp_unreachfrag(sctp_association_t *asoc, void *arg) { - int error = 0; - sctp_event_t event_type; + 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); + sctp_endpoint_t *ep; - return error; + 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; -} /* sctp_other_icmp_unreachfrag() */ + error = sctp_do_sm(event_type, subtype, state, ep, + asoc, arg, GFP_ATOMIC); + return error; +} diff --git a/net/sctp/sctp_protocol.c b/net/sctp/sctp_protocol.c index c3cbdd5c9a5f..920af0ddf077 100644 --- a/net/sctp/sctp_protocol.c +++ b/net/sctp/sctp_protocol.c @@ -71,51 +71,42 @@ static struct socket *sctp_ctl_socket; extern struct net_proto_family inet_family_ops; - /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) { - return(sctp_ctl_socket->sk); - -} /* sctp_get_ctl_sock() */ + return sctp_ctl_socket->sk; +} /* Set up the proc fs entry for the SCTP protocol. */ -void -sctp_proc_init(void) -{ +void sctp_proc_init(void) +{ if (!proc_net_sctp) { struct proc_dir_entry *ent; ent = proc_mkdir("net/sctp", 0); if (ent) { ent->owner = THIS_MODULE; - proc_net_sctp= ent; + proc_net_sctp = ent; } } - -} /* sctp_proc_init() */ +} /* Clean up the proc fs entry for the SCTP protocol. */ -void -sctp_proc_exit(void) +void sctp_proc_exit(void) { if (proc_net_sctp) { proc_net_sctp= NULL; remove_proc_entry("net/sctp", 0); } - -} /* sctp_proc_exit() */ - - +} /* Private helper to extract ipv4 address and stash them in - * the protocol structure. + * the protocol structure. */ -static inline void -sctp_v4_get_local_addr_list(sctp_protocol_t *proto, - struct net_device *dev) +static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, + struct net_device *dev) { struct in_device *in_dev; - struct in_ifaddr *ifa; + struct in_ifaddr *ifa; struct sockaddr_storage_list *addr; read_lock(&inetdev_lock); @@ -128,6 +119,7 @@ sctp_v4_get_local_addr_list(sctp_protocol_t *proto, for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { /* Add the address to the local list. */ + /* XXX BUG: sleeping allocation with lock held -DaveM */ addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); if (addr) { INIT_LIST_HEAD(&addr->list); @@ -137,36 +129,34 @@ sctp_v4_get_local_addr_list(sctp_protocol_t *proto, list_add_tail(&addr->list, &proto->local_addr_list); } } - + read_unlock(&in_dev->lock); read_unlock(&inetdev_lock); - return; - -} /* sctp_v4_get_local_addr_list() */ +} /* Private helper to extract ipv6 address and stash them in * the protocol structure. - * FIXME: Make this an address family function. + * FIXME: Make this an address family function. */ -static inline void -sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) +static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) { #ifdef SCTP_V6_SUPPORT /* FIXME: The testframe doesn't support this function. */ -#ifndef TEST_FRAME +#ifndef TEST_FRAME struct inet6_dev *in6_dev; struct inet6_ifaddr *ifp; struct sockaddr_storage_list *addr; - - read_lock(&addrconf_lock); - if ((in6_dev = __in6_dev_get(dev)) == NULL) { + + read_lock(&addrconf_lock); + if ((in6_dev = __in6_dev_get(dev)) == NULL) { read_unlock(&addrconf_lock); return; } - + read_lock_bh(&in6_dev->lock); - for (ifp=in6_dev->addr_list; ifp; ifp=ifp->if_next) { + for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { /* Add the address to the local list. */ + /* XXX BUG: sleeping allocation with lock held -DaveM */ addr = t_new(struct sockaddr_storage_list, GFP_KERNEL); if (addr) { addr->a.v6.sin6_family = AF_INET6; @@ -174,127 +164,105 @@ sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) addr->a.v6.sin6_addr = ifp->addr; INIT_LIST_HEAD(&addr->list); list_add_tail(&addr->list, &proto->local_addr_list); - } + } } read_unlock_bh(&in6_dev->lock); read_unlock(&addrconf_lock); - #endif /* TEST_FRAME */ - return; #endif /* SCTP_V6_SUPPORT */ -} /* sctp_v6_get_local_addr_list() */ - +} /* Extract our IP addresses from the system and stash them in the * protocol structure. */ -static void -__sctp_get_local_addr_list(sctp_protocol_t *proto) +static void __sctp_get_local_addr_list(sctp_protocol_t *proto) { struct net_device *dev; - + read_lock(&dev_base_lock); - - for (dev=dev_base; dev; dev = dev->next) { + for (dev = dev_base; dev; dev = dev->next) { sctp_v4_get_local_addr_list(proto, dev); sctp_v6_get_local_addr_list(proto, dev); - } - + } read_unlock(&dev_base_lock); +} -} /* __sctp_get_local_addr_list() */ - - -static void -sctp_get_local_addr_list(sctp_protocol_t *proto) +static void sctp_get_local_addr_list(sctp_protocol_t *proto) { long flags __attribute__ ((unused)); - - sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); - __sctp_get_local_addr_list(&sctp_proto); - sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); - -} /* sctp_get_local_addr_list() */ + sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); + __sctp_get_local_addr_list(&sctp_proto); + sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); +} -/* Free the existing local addresses. */ -static void -__sctp_free_local_addr_list(sctp_protocol_t *proto) +/* Free the existing local addresses. */ +static void __sctp_free_local_addr_list(sctp_protocol_t *proto) { - struct sockaddr_storage_list *addr; - list_t *pos, *temp; - + astruct sockaddr_storage_list *addr; + list_t *pos, *temp; + list_for_each_safe(pos, temp, &proto->local_addr_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); - list_del(pos); - kfree(addr); - } - -} /* __sctp_free_local_addr_list() */ - -/* Free the existing local addresses. */ -static void -sctp_free_local_addr_list(sctp_protocol_t *proto) + addr = list_entry(pos, struct sockaddr_storage_list, list); + list_del(pos); + kfree(addr); + } +} + +/* Free the existing local addresses. */ +static void sctp_free_local_addr_list(sctp_protocol_t *proto) { - long flags __attribute__ ((unused)); - - sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); - __sctp_free_local_addr_list(proto); - sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); - -} /* sctp_free_local_addr_list() */ + long flags __attribute__ ((unused)); + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); + __sctp_free_local_addr_list(proto); + sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); +} /* Copy the local addresses which are valid for 'scope' into 'bp'. */ -int -sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, - sctp_scope_t scope, int priority, int copy_flags) +int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, + sctp_scope_t scope, int priority, int copy_flags) { - struct sockaddr_storage_list *addr; int error = 0; list_t *pos; long flags __attribute__ ((unused)); - + sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); list_for_each(pos, &proto->local_addr_list) { addr = list_entry(pos, struct sockaddr_storage_list, list); if (sctp_in_scope(&addr->a, scope)) { - /* Now that the address is in scope, check to see if + /* Now that the address is in scope, check to see if * the address type is really supported by the local * sock as well as the remote peer. */ - if ((((AF_INET == addr->a.sa.sa_family) - && (copy_flags & SCTP_ADDR4_PEERSUPP))) - || (((AF_INET6 == addr->a.sa.sa_family) - && (copy_flags & SCTP_ADDR6_ALLOWED) - && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { - - error = sctp_add_bind_addr(bp, - &addr->a, + if ((((AF_INET == addr->a.sa.sa_family) && + (copy_flags & SCTP_ADDR4_PEERSUPP))) || + (((AF_INET6 == addr->a.sa.sa_family) && + (copy_flags & SCTP_ADDR6_ALLOWED) && + (copy_flags & SCTP_ADDR6_PEERSUPP)))) { + error = sctp_add_bind_addr(bp, + &addr->a, priority); - if (0 != error) { goto end_copy; } + if (error) + goto end_copy; } - } - } + } + } end_copy: sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); - return(error); - -} /* sctp_copy_local_addr_list() */ - + return error; +} -/* Returns the mtu for the given v4 destination address. */ -int -sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) +/* Returns the mtu for the given v4 destination address. */ +int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) { int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; - struct rtable *rt; - struct rt_key key = { + struct rt_key key = { .dst = address->v4.sin_addr.s_addr, .src = 0, .iif = 0, @@ -302,10 +270,10 @@ sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) .tos = 0, .scope = 0 }; - + if (ip_route_output_key(&rt, &key)) { SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key" - " failed, returning %d as dst_mtu\n", + " failed, returning %d as dst_mtu\n", dst_mtu); } else { dst_mtu = rt->u.dst.pmtu; @@ -315,16 +283,13 @@ sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) ip_rt_put(rt); } - return (dst_mtu); - -} /* sctp_v4_get_dst_mtu() */ + return dst_mtu; +} - -/* Event handler for inet device events. +/* Event handler for inet device events. * Basically, whenever there is an event, we re-build our local address list. */ -static int -sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { long flags __attribute__ ((unused)); @@ -334,25 +299,23 @@ sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); return NOTIFY_DONE; - -} /* sctp_netdev_event() */ +} /* * Initialize the control inode/socket with a control endpoint data * structure. This endpoint is reserved exclusively for the OOTB processing. */ -int -sctp_ctl_sock_init(void) +int sctp_ctl_sock_init(void) { int err = 0; int family = PF_INET; SCTP_V6(family = PF_INET6;) - err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, + err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, &sctp_ctl_socket); if (err < 0) { - printk(KERN_ERR + printk(KERN_ERR "SCTP: Failed to create the SCTP control socket.\n"); return err; } @@ -360,67 +323,62 @@ sctp_ctl_sock_init(void) inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL; return 0; - -} /* sctp_ctl_sock_init() */ +} /* Get the table of functions for manipulating a particular address * family. */ -sctp_func_t * -sctp_get_af_specific(const sockaddr_storage_t *address) +sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) { list_t *pos; - sctp_protocol_t *proto = sctp_get_protocol(); - sctp_func_t *retval, *af; - + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *retval, *af; + retval = NULL; - /* Cycle through all AF specific functions looking for a + /* Cycle through all AF specific functions looking for a * match. */ list_for_each(pos, &proto->address_families) { af = list_entry(pos, sctp_func_t, list); + if (address->sa.sa_family == af->sa_family) { + retval = af; + break; + } + } - if (address->sa.sa_family == af->sa_family) { - retval = af; - break; - } - } - - return retval; - -} /* sctp_get_af_specific() */ + return retval; +} -/* Registration for netdev events. */ +/* Registration for netdev events. */ struct notifier_block sctp_netdev_notifier = { .notifier_call = sctp_netdev_event, }; -/* Socket operations. */ +/* Socket operations. */ struct proto_ops inet_seqpacket_ops = { .family = PF_INET, .release = inet_release, /* Needs to be wrapped... */ .bind = inet_bind, - .connect = inet_dgram_connect, + .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet_getname, /* Semantics are different. */ - .poll = sctp_poll, + .poll = sctp_poll, .ioctl = inet_ioctl, .listen = sctp_inet_listen, .shutdown = inet_shutdown, /* Looks harmless. */ .setsockopt = inet_setsockopt, /* IP_SOL IP_OPTION is a problem. */ - .getsockopt = inet_getsockopt, + .getsockopt = inet_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; -/* Registration with AF_INET family. */ -struct inet_protosw sctp_protosw = -{ - .type = SOCK_SEQPACKET, +/* Registration with AF_INET family. */ +struct inet_protosw sctp_protosw = { + .type = SOCK_SEQPACKET, .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet_seqpacket_ops, @@ -429,111 +387,107 @@ struct inet_protosw sctp_protosw = .flags = SCTP_PROTOSW_FLAG }; -/* Register with IP layer. */ -static struct inet_protocol sctp_protocol = -{ +/* Register with IP layer. */ +static struct inet_protocol sctp_protocol = { .handler = sctp_rcv, /* SCTP input handler. */ .err_handler = sctp_v4_err, /* SCTP error control */ .protocol = IPPROTO_SCTP, /* protocol ID */ .name = "SCTP" /* name */ }; -/* IPv4 address related functions. */ +/* IPv4 address related functions. */ sctp_func_t sctp_ipv4_specific = { - .queue_xmit = ip_queue_xmit, - .setsockopt = ip_setsockopt, - .getsockopt = ip_getsockopt, + .queue_xmit = ip_queue_xmit, + .setsockopt = ip_setsockopt, + .getsockopt = ip_getsockopt, .get_dst_mtu = sctp_v4_get_dst_mtu, .net_header_len = sizeof(struct iphdr), - .sockaddr_len = sizeof(struct sockaddr_in), + .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, -}; - +}; /* Initialize the universe into something sensible. */ -int -sctp_init(void) +int sctp_init(void) { int i; int status = 0; - - /* Add SCTP to inetsw linked list. */ + + /* Add SCTP to inetsw linked list. */ inet_register_protosw(&sctp_protosw); - - /* Add SCTP to inet_protos hash table. */ + + /* Add SCTP to inet_protos hash table. */ inet_add_protocol(&sctp_protocol); - /* Initialize proc fs directory. */ + /* Initialize proc fs directory. */ sctp_proc_init(); - /* Initialize object count debugging. */ + /* Initialize object count debugging. */ sctp_dbg_objcnt_init(); /* * 14. Suggested SCTP Protocol Parameter Values */ - /* The following protocol parameters are RECOMMENDED: */ - /* RTO.Initial - 3 seconds */ - sctp_proto.rto_initial = SCTP_RTO_INITIAL; - /* RTO.Min - 1 second */ - sctp_proto.rto_min = SCTP_RTO_MIN; - /* RTO.Max - 60 seconds */ - sctp_proto.rto_max = SCTP_RTO_MAX; - /* RTO.Alpha - 1/8 */ - sctp_proto.rto_alpha = SCTP_RTO_ALPHA; - /* RTO.Beta - 1/4 */ - sctp_proto.rto_beta = SCTP_RTO_BETA; - - /* Valid.Cookie.Life - 60 seconds - */ - sctp_proto.valid_cookie_life = 60 * HZ; + /* The following protocol parameters are RECOMMENDED: */ + /* RTO.Initial - 3 seconds */ + sctp_proto.rto_initial = SCTP_RTO_INITIAL; + /* RTO.Min - 1 second */ + sctp_proto.rto_min = SCTP_RTO_MIN; + /* RTO.Max - 60 seconds */ + sctp_proto.rto_max = SCTP_RTO_MAX; + /* RTO.Alpha - 1/8 */ + sctp_proto.rto_alpha = SCTP_RTO_ALPHA; + /* RTO.Beta - 1/4 */ + sctp_proto.rto_beta = SCTP_RTO_BETA; + + /* Valid.Cookie.Life - 60 seconds */ + sctp_proto.valid_cookie_life = 60 * HZ; /* Max.Burst - 4 */ sctp_proto.max_burst = SCTP_MAX_BURST; - /* Association.Max.Retrans - 10 attempts - * Path.Max.Retrans - 5 attempts (per destination address) - * Max.Init.Retransmits - 8 attempts - */ - sctp_proto.max_retrans_association = 10; - sctp_proto.max_retrans_path = 5; - sctp_proto.max_retrans_init = 8; + /* Association.Max.Retrans - 10 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts + */ + sctp_proto.max_retrans_association = 10; + sctp_proto.max_retrans_path = 5; + sctp_proto.max_retrans_init = 8; + + /* HB.interval - 30 seconds */ + sctp_proto.hb_interval = 30 * HZ; - /* HB.interval - 30 seconds */ - sctp_proto.hb_interval = 30 * HZ; - /* 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. + /* 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_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_hashbucket = (sctp_hashbucket_t *) kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); if (!sctp_proto.assoc_hashbucket) { - printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); + printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); status = -ENOMEM; - goto err_ahash_alloc; + goto err_ahash_alloc; } for (i = 0; i < sctp_proto.assoc_hashsize; i++) { sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED; sctp_proto.assoc_hashbucket[i].chain = NULL; } - /* Allocate and initialize the endpoint hash table. */ + /* Allocate and initialize the endpoint hash table. */ sctp_proto.ep_hashsize = 64; sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); if (!sctp_proto.ep_hashbucket) { - printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); + printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); status = -ENOMEM; - goto err_ehash_alloc; + goto err_ehash_alloc; } for (i = 0; i < sctp_proto.ep_hashsize; i++) { @@ -546,11 +500,10 @@ sctp_init(void) sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); if (!sctp_proto.port_hashtable) { - printk (KERN_ERR "SCTP: Failed bind hash alloc."); + printk (KERN_ERR "SCTP: Failed bind hash alloc."); status = -ENOMEM; - goto err_bhash_alloc; + goto err_bhash_alloc; } - sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED; sctp_proto.port_rover = sysctl_local_port_range[0] - 1; @@ -564,19 +517,18 @@ sctp_init(void) INIT_LIST_HEAD(&sctp_proto.address_families); INIT_LIST_HEAD(&sctp_ipv4_specific.list); list_add_tail(&sctp_ipv4_specific.list, &sctp_proto.address_families); - + status = sctp_v6_init(); - if (status != 0) { + if (status) goto err_v6_init; - } - /* Initialize the control inode/socket for handling OOTB packets. */ - if (0 != (status = sctp_ctl_sock_init())) { - printk (KERN_ERR + /* Initialize the control inode/socket for handling OOTB packets. */ + if ((status = sctp_ctl_sock_init())) { + printk (KERN_ERR "SCTP: Failed to initialize the SCTP control sock.\n"); - goto err_ctl_sock_init; + goto err_ctl_sock_init; } - + /* Initialize the local address list. */ INIT_LIST_HEAD(&sctp_proto.local_addr_list); sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; @@ -602,40 +554,36 @@ err_ahash_alloc: inet_del_protocol(&sctp_protocol); inet_unregister_protosw(&sctp_protosw); return status; +} -} /* sctp_init() */ - - -/* Exit handler for the SCTP protocol. */ -void -sctp_exit(void) +/* Exit handler for the SCTP protocol. */ +void sctp_exit(void) { - /* BUG. This should probably do something useful like clean - * up all the remaining associations and all that memory. - */ - - /* Free the local address list. */ + /* BUG. This should probably do something useful like clean + * up all the remaining associations and all that memory. + */ + + /* Free the local address list. */ unregister_inetaddr_notifier(&sctp_netdev_notifier); sctp_free_local_addr_list(&sctp_proto); - /* Free the control endpoint. */ + /* Free the control endpoint. */ sock_release(sctp_ctl_socket); sctp_v6_exit(); sctp_sysctl_unregister(); - list_del(&sctp_ipv4_specific.list); + list_del(&sctp_ipv4_specific.list); kfree(sctp_proto.assoc_hashbucket); kfree(sctp_proto.ep_hashbucket); kfree(sctp_proto.port_hashtable); - + sctp_dbg_objcnt_exit(); sctp_proc_exit(); inet_del_protocol(&sctp_protocol); inet_unregister_protosw(&sctp_protosw); - -} /* sctp_exit() */ +} module_init(sctp_init); module_exit(sctp_exit); diff --git a/net/sctp/sctp_sla1.c b/net/sctp/sctp_sla1.c index ce6a65bec0cc..9151f512c263 100644 --- a/net/sctp/sctp_sla1.c +++ b/net/sctp/sctp_sla1.c @@ -47,8 +47,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sla1.c,v 1.4 2002/07/19 22:00:33 jgrimm Exp $"; - -#include #include #include #include @@ -58,228 +56,229 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sla1.c,v 1.4 2002/07/1 #include -void -SLA1_Init(struct SLA_1_Context *ctx) +void SLA1_Init(struct SLA_1_Context *ctx) { - /* Init the SLA-1 context structure */ - ctx->A = 0; - ctx->B = 0; - ctx->C = 0; - ctx->D = 0; - ctx->E = 0; - ctx->H0 = H0INIT; - ctx->H1 = H1INIT; - ctx->H2 = H2INIT; - ctx->H3 = H3INIT; - ctx->H4 = H4INIT; - ctx->TEMP = 0; - memset(ctx->words,0,sizeof(ctx->words)); - ctx->howManyInBlock = 0; - ctx->runningTotal = 0; + /* Init the SLA-1 context structure. */ + ctx->A = 0; + ctx->B = 0; + ctx->C = 0; + ctx->D = 0; + ctx->E = 0; + ctx->H0 = H0INIT; + ctx->H1 = H1INIT; + ctx->H2 = H2INIT; + ctx->H3 = H3INIT; + ctx->H4 = H4INIT; + ctx->TEMP = 0; + memset(ctx->words, 0, sizeof(ctx->words)); + ctx->howManyInBlock = 0; + ctx->runningTotal = 0; } -void -SLA1processABlock(struct SLA_1_Context *ctx,unsigned int *block) +void SLA1processABlock(struct SLA_1_Context *ctx,unsigned int *block) { - int i; - /* init the W0-W15 to the block of words being - * hashed. - */ - /* step a) */ + int i; + /* init the W0-W15 to the block of words being + * hashed. + */ + /* step a) */ - for(i=0;i<16;i++){ - ctx->words[i] = ntohl(block[i]); - } - /* now init the rest based on the SLA-1 formula, step b) */ - for(i=16;i<80;i++){ - ctx->words[i] = CSHIFT(1,((ctx->words[(i-3)]) ^ (ctx->words[(i-8)]) ^ (ctx->words[(i-14)]) ^ (ctx->words[(i-16)]))); - } - /* step c) */ - ctx->A = ctx->H0; - ctx->B = ctx->H1; - ctx->C = ctx->H2; - ctx->D = ctx->H3; - ctx->E = ctx->H4; + for (i = 0; i < 16; i++) + ctx->words[i] = ntohl(block[i]); - /* step d) */ - for(i=0;i<80;i++){ - if(i < 20){ - ctx->TEMP = ((CSHIFT(5,ctx->A)) + - (F1(ctx->B,ctx->C,ctx->D)) + - (ctx->E) + - ctx->words[i] + - K1 - ); - }else if(i < 40){ - ctx->TEMP = ((CSHIFT(5,ctx->A)) + - (F2(ctx->B,ctx->C,ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K2 - ); - }else if(i < 60){ - ctx->TEMP = ((CSHIFT(5,ctx->A)) + - (F3(ctx->B,ctx->C,ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K3 - ); - }else{ - ctx->TEMP = ((CSHIFT(5,ctx->A)) + - (F4(ctx->B,ctx->C,ctx->D)) + - (ctx->E) + - (ctx->words[i]) + - K4 - ); - } - ctx->E = ctx->D; - ctx->D = ctx->C; - ctx->C = CSHIFT(30,ctx->B); - ctx->B = ctx->A; - ctx->A = ctx->TEMP; - } - /* step e) */ - ctx->H0 = (ctx->H0) + (ctx->A); - ctx->H1 = (ctx->H1) + (ctx->B); - ctx->H2 = (ctx->H2) + (ctx->C); - ctx->H3 = (ctx->H3) + (ctx->D); - ctx->H4 = (ctx->H4) + (ctx->E); -} + /* now init the rest based on the SLA-1 formula, step b) */ + for (i = 16; i < 80; i++) + ctx->words[i] = + CSHIFT(1, ((ctx->words[(i-3)]) ^ + (ctx->words[(i-8)]) ^ + (ctx->words[(i-14)]) ^ + (ctx->words[(i-16)]))); + /* step c) */ + ctx->A = ctx->H0; + ctx->B = ctx->H1; + ctx->C = ctx->H2; + ctx->D = ctx->H3; + ctx->E = ctx->H4; -void -SLA1_Process(struct SLA_1_Context *ctx, const unsigned char *ptr, int siz) -{ - int numberLeft,leftToFill; - numberLeft = siz; - while(numberLeft > 0){ - leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; - if(leftToFill > numberLeft){ - /* can only partially fill up this one */ - memcpy(&ctx->SLAblock[ctx->howManyInBlock],ptr,numberLeft); - ctx->howManyInBlock += siz; - ctx->runningTotal += siz; - break; - }else{ - /* block is now full, process it */ - memcpy(&ctx->SLAblock[ctx->howManyInBlock],ptr,leftToFill); - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - numberLeft -= leftToFill; - ctx->runningTotal += leftToFill; - ctx->howManyInBlock = 0; - } - } + /* step d) */ + for (i = 0; i < 80; i++) { + if (i < 20) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F1(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + ctx->words[i] + + K1 + ); + } else if (i < 40) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F2(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K2 + ); + } else if (i < 60) { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F3(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K3 + ); + } else { + ctx->TEMP = ((CSHIFT(5, ctx->A)) + + (F4(ctx->B, ctx->C, ctx->D)) + + (ctx->E) + + (ctx->words[i]) + + K4 + ); + } + ctx->E = ctx->D; + ctx->D = ctx->C; + ctx->C = CSHIFT(30, ctx->B); + ctx->B = ctx->A; + ctx->A = ctx->TEMP; + } + + /* step e) */ + ctx->H0 = (ctx->H0) + (ctx->A); + ctx->H1 = (ctx->H1) + (ctx->B); + ctx->H2 = (ctx->H2) + (ctx->C); + ctx->H3 = (ctx->H3) + (ctx->D); + ctx->H4 = (ctx->H4) + (ctx->E); } -void -SLA1_Final(struct SLA_1_Context *ctx,unsigned char *digestBuf) +void SLA1_Process(struct SLA_1_Context *ctx, const unsigned char *ptr, int siz) { - /* if any left in block fill with padding - * and process. Then transfer the digest to - * the pointer. At the last block some special - * rules need to apply. We must add a 1 bit - * following the message, then we pad with - * 0's. The total size is encoded as a 64 bit - * number at the end. Now if the last buffer has - * more than 55 octets in it we cannot fit - * the 64 bit number + 10000000 pad on the end - * and must add the 10000000 pad, pad the rest - * of the message with 0's and then create a - * all 0 message with just the 64 bit size - * at the end and run this block through by itself. - * Also the 64 bit int must be in network byte - * order. - */ - int i,leftToFill; - unsigned int *ptr; - if(ctx->howManyInBlock > 55){ - /* special case, we need to process two - * blocks here. One for the current stuff - * plus possibly the pad. The other for - * the size. - */ - leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; - if(leftToFill == 0){ - /* Should not really happen but I am paranoid */ - /* Not paranoid enough! It is possible for leftToFill to become - * negative! AAA!!!! This is another reason to pick MD5 :-)... - */ - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - /* init last block, a bit different then the rest :-) */ - ctx->SLAblock[0] = 0x80; - for(i=1;iSLAblock);i++){ - ctx->SLAblock[i] = 0x0; - } - }else if(leftToFill == 1){ - ctx->SLAblock[ctx->howManyInBlock] = 0x80; - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - /* init last block */ - memset(ctx->SLAblock,0,sizeof(ctx->SLAblock)); - }else{ - ctx->SLAblock[ctx->howManyInBlock] = 0x80; - for(i=(ctx->howManyInBlock+1);iSLAblock);i++){ - ctx->SLAblock[i] = 0x0; - } - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - /* init last block */ - memset(ctx->SLAblock,0,sizeof(ctx->SLAblock)); - } - /* This is in bits so multiply by 8 */ - ctx->runningTotal *= 8; - ptr = (unsigned int *)&ctx->SLAblock[60]; - *ptr = htonl(ctx->runningTotal); - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - }else{ - /* easy case, we just pad this - * message to size - end with 0 - * add the magic 0x80 to the next - * word and then put the network byte - * order size in the last spot and - * process the block. - */ - ctx->SLAblock[ctx->howManyInBlock] = 0x80; - for(i=(ctx->howManyInBlock+1);iSLAblock);i++){ - ctx->SLAblock[i] = 0x0; - } - /* get last int spot */ - ctx->runningTotal *= 8; - ptr = (unsigned int *)&ctx->SLAblock[60]; - *ptr = htonl(ctx->runningTotal); - SLA1processABlock(ctx,(unsigned int *)ctx->SLAblock); - } - /* Now at this point all we need do is transfer the - * digest back to the user - */ - digestBuf[3] = (ctx->H0 & 0xff); - digestBuf[2] = ((ctx->H0 >> 8) & 0xff); - digestBuf[1] = ((ctx->H0 >> 16) & 0xff); - digestBuf[0] = ((ctx->H0 >> 24) & 0xff); - - digestBuf[7] = (ctx->H1 & 0xff); - digestBuf[6] = ((ctx->H1 >> 8) & 0xff); - digestBuf[5] = ((ctx->H1 >> 16) & 0xff); - digestBuf[4] = ((ctx->H1 >> 24) & 0xff); - - digestBuf[11] = (ctx->H2 & 0xff); - digestBuf[10] = ((ctx->H2 >> 8) & 0xff); - digestBuf[9] = ((ctx->H2 >> 16) & 0xff); - digestBuf[8] = ((ctx->H2 >> 24) & 0xff); - - digestBuf[15] = (ctx->H3 & 0xff); - digestBuf[14] = ((ctx->H3 >> 8) & 0xff); - digestBuf[13] = ((ctx->H3 >> 16) & 0xff); - digestBuf[12] = ((ctx->H3 >> 24) & 0xff); - - digestBuf[19] = (ctx->H4 & 0xff); - digestBuf[18] = ((ctx->H4 >> 8) & 0xff); - digestBuf[17] = ((ctx->H4 >> 16) & 0xff); - digestBuf[16] = ((ctx->H4 >> 24) & 0xff); + int numberLeft, leftToFill; + numberLeft = siz; + while (numberLeft > 0) { + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if (leftToFill > numberLeft) { + /* can only partially fill up this one */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock], + ptr, numberLeft); + ctx->howManyInBlock += siz; + ctx->runningTotal += siz; + break; + } else { + /* block is now full, process it */ + memcpy(&ctx->SLAblock[ctx->howManyInBlock], + ptr, leftToFill); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + numberLeft -= leftToFill; + ctx->runningTotal += leftToFill; + ctx->howManyInBlock = 0; + } + } } +void SLA1_Final(struct SLA_1_Context *ctx, unsigned char *digestBuf) +{ + /* if any left in block fill with padding + * and process. Then transfer the digest to + * the pointer. At the last block some special + * rules need to apply. We must add a 1 bit + * following the message, then we pad with + * 0's. The total size is encoded as a 64 bit + * number at the end. Now if the last buffer has + * more than 55 octets in it we cannot fit + * the 64 bit number + 10000000 pad on the end + * and must add the 10000000 pad, pad the rest + * of the message with 0's and then create a + * all 0 message with just the 64 bit size + * at the end and run this block through by itself. + * Also the 64 bit int must be in network byte + * order. + */ + int i, leftToFill; + unsigned int *ptr; + if (ctx->howManyInBlock > 55) { + /* special case, we need to process two + * blocks here. One for the current stuff + * plus possibly the pad. The other for + * the size. + */ + leftToFill = sizeof(ctx->SLAblock) - ctx->howManyInBlock; + if (leftToFill == 0) { + /* Should not really happen but I am paranoid */ + /* Not paranoid enough! It is possible for leftToFill + * to become negative! AAA!!!! This is another reason + * to pick MD5 :-)... + */ + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block, a bit different then the rest :-) */ + ctx->SLAblock[0] = 0x80; + for (i = 1; i < sizeof(ctx->SLAblock); i++) { + ctx->SLAblock[i] = 0x0; + } + } else if (leftToFill == 1) { + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock)); + } else { + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for (i = (ctx->howManyInBlock + 1); + i < sizeof(ctx->SLAblock); + i++) { + ctx->SLAblock[i] = 0x0; + } + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + /* init last block */ + memset(ctx->SLAblock, 0, sizeof(ctx->SLAblock)); + } + /* This is in bits so multiply by 8 */ + ctx->runningTotal *= 8; + ptr = (unsigned int *) &ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + } else { + /* easy case, we just pad this + * message to size - end with 0 + * add the magic 0x80 to the next + * word and then put the network byte + * order size in the last spot and + * process the block. + */ + ctx->SLAblock[ctx->howManyInBlock] = 0x80; + for (i = (ctx->howManyInBlock + 1); + i < sizeof(ctx->SLAblock); + i++) { + ctx->SLAblock[i] = 0x0; + } + /* get last int spot */ + ctx->runningTotal *= 8; + ptr = (unsigned int *) &ctx->SLAblock[60]; + *ptr = htonl(ctx->runningTotal); + SLA1processABlock(ctx, (unsigned int *) ctx->SLAblock); + } + /* Now at this point all we need do is transfer the + * digest back to the user + */ + digestBuf[3] = (ctx->H0 & 0xff); + digestBuf[2] = ((ctx->H0 >> 8) & 0xff); + digestBuf[1] = ((ctx->H0 >> 16) & 0xff); + digestBuf[0] = ((ctx->H0 >> 24) & 0xff); + digestBuf[7] = (ctx->H1 & 0xff); + digestBuf[6] = ((ctx->H1 >> 8) & 0xff); + digestBuf[5] = ((ctx->H1 >> 16) & 0xff); + digestBuf[4] = ((ctx->H1 >> 24) & 0xff); + digestBuf[11] = (ctx->H2 & 0xff); + digestBuf[10] = ((ctx->H2 >> 8) & 0xff); + digestBuf[9] = ((ctx->H2 >> 16) & 0xff); + digestBuf[8] = ((ctx->H2 >> 24) & 0xff); + digestBuf[15] = (ctx->H3 & 0xff); + digestBuf[14] = ((ctx->H3 >> 8) & 0xff); + digestBuf[13] = ((ctx->H3 >> 16) & 0xff); + digestBuf[12] = ((ctx->H3 >> 24) & 0xff); - + digestBuf[19] = (ctx->H4 & 0xff); + digestBuf[18] = ((ctx->H4 >> 8) & 0xff); + digestBuf[17] = ((ctx->H4 >> 16) & 0xff); + digestBuf[16] = ((ctx->H4 >> 24) & 0xff); +} diff --git a/net/sctp/sctp_sm_make_chunk.c b/net/sctp/sctp_sm_make_chunk.c index 7846eb77294a..de999bd8a54b 100644 --- a/net/sctp/sctp_sm_make_chunk.c +++ b/net/sctp/sctp_sm_make_chunk.c @@ -55,7 +55,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_make_chunk.c,v 1.38 2002/07/26 22:52:32 jgrimm Exp $"; -#include #include #include #include @@ -76,7 +75,7 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_make_chunk.c,v 1.38 * of this parameter indicates that the sending endpoint can * support any address type. */ -static const sctp_supported_addrs_param_t sat_param= { +static const sctp_supported_addrs_param_t sat_param = { { SCTP_PARAM_SUPPORTED_ADDRESS_TYPES, __constant_htons(SCTP_SAT_LEN), @@ -85,33 +84,32 @@ static const sctp_supported_addrs_param_t sat_param= { SCTP_PARAM_IPV4_ADDRESS, SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) } -}; +}; /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 2: The ECN capable field is reserved for future use of * Explicit Congestion Notification. */ - -static const sctp_ecn_capable_param_t ecap_param = {{ - SCTP_PARAM_ECN_CAPABLE, - __constant_htons(sizeof(sctp_ecn_capable_param_t)), -}}; - +static const sctp_ecn_capable_param_t ecap_param = { + { + SCTP_PARAM_ECN_CAPABLE, + __constant_htons(sizeof(sctp_ecn_capable_param_t)), + } +}; /* A helper to initilize to initilize an op error inside a * provided chunk, as most cause codes will be embedded inside an * abort chunk. */ -void -sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, - size_t paylen) +void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, + const void *payload, size_t paylen) { sctp_errhdr_t err; int padlen; - uint16_t len; + __u16 len; - /* Cause code constants are now defined in network order. */ + /* Cause code constants are now defined in network order. */ err.cause = cause_code; len = sizeof(sctp_errhdr_t) + paylen; padlen = len % 4; @@ -119,17 +117,13 @@ sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, err.length = htons(len); sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); chunk->subh.err_hdr = sctp_addto_chunk(chunk, paylen, payload); - - return; - -} /* sctp_init_cause() */ - +} /* 3.3.2 Initiation (INIT) (1) - * + * * This chunk is used to initiate a SCTP association between two * endpoints. The format of the INIT chunk is shown below: - * + * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -147,11 +141,11 @@ sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, * / Optional/Variable-Length Parameters / * \ \ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * - * The INIT chunk contains the following parameters. Unless otherwise + * + * + * The INIT chunk contains the following parameters. Unless otherwise * noted, each parameter MUST only be included once in the INIT chunk. - * + * * Fixed Parameters Status * ---------------------------------------------- * Initiate Tag Mandatory @@ -159,7 +153,7 @@ sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, * Number of Outbound Streams Mandatory * Number of Inbound Streams Mandatory * Initial TSN Mandatory - * + * * Variable Parameters Status Type Value * ------------------------------------------------------------- * IPv4 Address (Note 1) Optional 5 @@ -169,153 +163,151 @@ sctp_init_cause(sctp_chunk_t *chunk, uint16_t cause_code, const void *payload, * Host Name Address (Note 3) Optional 11 * Supported Address Types (Note 4) Optional 12 */ - -sctp_chunk_t * -sctp_make_init(const sctp_association_t *asoc, const sctp_bind_addr_t *bp, - int priority) +sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, + const sctp_bind_addr_t *bp, + int priority) { - sctp_inithdr_t init; - sctpParam_t addrs; + sctp_inithdr_t init; + sctpParam_t addrs; size_t chunksize; - sctp_chunk_t *retval = NULL; - int addrs_len = 0; + sctp_chunk_t *retval = NULL; + int addrs_len = 0; /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 1: The INIT chunks can contain multiple addresses that - * can be IPv4 and/or IPv6 in any combination. - */ + * can be IPv4 and/or IPv6 in any combination. + */ retval = NULL; addrs.v = NULL; /* Convert the provided bind address list to raw format */ addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); - if (NULL == addrs.v) { goto nodata; } - - init.init_tag = htonl(asoc->c.my_vtag); - init.a_rwnd = htonl(asoc->rwnd); - init.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); - init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); - init.initial_tsn = htonl(asoc->c.initial_tsn); + if (!addrs.v) + goto nodata; + + init.init_tag = htonl(asoc->c.my_vtag); + init.a_rwnd = htonl(asoc->rwnd); + init.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + init.initial_tsn = htonl(asoc->c.initial_tsn); chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; chunksize += sizeof(ecap_param); - /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 3: An INIT chunk MUST NOT contain more than one Host - * Name address parameter. Moreover, the sender of the INIT - * MUST NOT combine any other address types with the Host Name - * address in the INIT. The receiver of INIT MUST ignore any - * other address types if the Host Name address parameter is - * present in the received INIT chunk. + * Name address parameter. Moreover, the sender of the INIT + * MUST NOT combine any other address types with the Host Name + * address in the INIT. The receiver of INIT MUST ignore any + * other address types if the Host Name address parameter is + * present in the received INIT chunk. * - * PLEASE DO NOT FIXME [This version does not support Host Name.] - */ + * PLEASE DO NOT FIXME [This version does not support Host Name.] + */ - retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); - if (NULL == retval) { goto nodata; } + retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); + if (!retval) + goto nodata; - retval->subh.init_hdr = - sctp_addto_chunk(retval, sizeof(init), &init); - retval->param_hdr.v = - sctp_addto_chunk(retval, addrs_len, addrs.v); - sctp_addto_chunk(retval, SCTP_SAT_LEN, &sat_param); + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(init), &init); + retval->param_hdr.v = + sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, SCTP_SAT_LEN, &sat_param); sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); - nodata: - if (NULL != addrs.v) { kfree(addrs.v); } - return retval; - -}; /* sctp_chunk_t *sctp_make_init() */ + if (addrs.v) + kfree(addrs.v); + return retval; +} -sctp_chunk_t * -sctp_make_init_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk, - int priority) +sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + int priority) { - sctp_inithdr_t initack; - sctp_chunk_t *retval; - sctpParam_t addrs; - int addrs_len; - sctp_cookie_param_t *cookie; - int cookie_len; + sctp_inithdr_t initack; + sctp_chunk_t *retval; + sctpParam_t addrs; + int addrs_len; + sctp_cookie_param_t *cookie; + int cookie_len; size_t chunksize; int error; sctp_scope_t scope; sctp_bind_addr_t *bp = NULL; int flags; - - + retval = NULL; /* Build up the bind address list for the association based on * info from the local endpoint and the remote peer. */ bp = sctp_bind_addr_new(priority); - if (NULL == bp) { goto nomem_bindaddr; } + if (!bp) + goto nomem_bindaddr; - /* Look for supported address types parameter and then build + /* Look for supported address types parameter and then build * our address list based on that. */ scope = sctp_scope(&asoc->peer.active_path->ipaddr); flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; - if (asoc->peer.ipv4_address) { + if (asoc->peer.ipv4_address) flags |= SCTP_ADDR4_PEERSUPP; - } - if (asoc->peer.ipv6_address) { + if (asoc->peer.ipv6_address) flags |= SCTP_ADDR6_PEERSUPP; - } error = sctp_bind_addr_copy(bp, &asoc->ep->base.bind_addr, scope, priority, flags); - if (0 != error) { goto nomem_copyaddr; } + if (error) + goto nomem_copyaddr; addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, priority); - if (NULL == addrs.v) { goto nomem_rawaddr; } - - initack.init_tag = htonl(asoc->c.my_vtag); - initack.a_rwnd = htonl(asoc->rwnd); - initack.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); - initack.num_inbound_streams = htons(asoc->c.sinit_max_instreams); - initack.initial_tsn = htonl(asoc->c.initial_tsn); - + if (!addrs.v) + goto nomem_rawaddr; + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(asoc->rwnd); + initack.num_outbound_streams = htons(asoc->c.sinit_num_ostreams); + initack.num_inbound_streams = htons(asoc->c.sinit_max_instreams); + initack.initial_tsn = htonl(asoc->c.initial_tsn); + /* FIXME: We really ought to build the cookie right - * into the packet instead of allocating more fresh memory. + * into the packet instead of allocating more fresh memory. */ - cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len, + cookie = sctp_pack_cookie(asoc->ep, asoc, chunk, &cookie_len, addrs.v, addrs_len); - if (NULL == cookie) { goto nomem_cookie; } + if (!cookie) + goto nomem_cookie; chunksize = sizeof(initack) + addrs_len + cookie_len; - /* Tell peer that we'll do ECN only if peer advertised such cap. */ - if (asoc->peer.ecn_capable) { + /* Tell peer that we'll do ECN only if peer advertised such cap. */ + if (asoc->peer.ecn_capable) chunksize += sizeof(ecap_param); - } - /* Now allocate and fill out the chunk. */ + /* Now allocate and fill out the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); + if (!retval) + goto nomem_chunk; - retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); - if (NULL == retval) { goto nomem_chunk; } - /* Per the advice in RFC 2960 6.4, send this reply to * the source of the INIT packet. - */ - retval->transport = chunk->transport; - retval->subh.init_hdr = - sctp_addto_chunk(retval, sizeof(initack), &initack); - retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); - sctp_addto_chunk(retval, cookie_len, cookie); - if (asoc->peer.ecn_capable) { + */ + retval->transport = chunk->transport; + retval->subh.init_hdr = + sctp_addto_chunk(retval, sizeof(initack), &initack); + retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); + sctp_addto_chunk(retval, cookie_len, cookie); + if (asoc->peer.ecn_capable) sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); - } /* We need to remove the const qualifier at this point. */ - retval->asoc = (sctp_association_t *) asoc; + retval->asoc = (sctp_association_t *) asoc; /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it received the DATA or control chunk @@ -323,30 +315,28 @@ sctp_make_init_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk, * * [INIT ACK back to where the INIT came from.] */ - if (NULL != chunk) { + if (chunk) retval->transport = chunk->transport; - } - + nomem_chunk: - kfree(cookie); + kfree(cookie); nomem_cookie: kfree(addrs.v); nomem_rawaddr: nomem_copyaddr: sctp_bind_addr_free(bp); nomem_bindaddr: - return retval; - -} /* sctp_make_init_ack() */ + return retval; +} /* 3.3.11 Cookie Echo (COOKIE ECHO) (10): - * + * * This chunk is used only during the initialization of an association. * It is sent by the initiator of an association to its peer to complete - * the initialization process. This chunk MUST precede any DATA chunk + * the initialization process. This chunk MUST precede any DATA chunk * sent within the association, but MAY be bundled with one or more DATA * chunks in the same packet. - * + * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -355,43 +345,43 @@ nomem_bindaddr: * / Cookie / * \ \ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * + * * Chunk Flags: 8 bit - * + * * Set to zero on transmit and ignored on receipt. - * + * * Length: 16 bits (unsigned integer) - * + * * Set to the size of the chunk in bytes, including the 4 bytes of * the chunk header and the size of the Cookie. - * + * * Cookie: variable size - * - * This field must contain the exact cookie received in the + * + * This field must contain the exact cookie received in the * State Cookie parameter from the previous INIT ACK. - * + * * An implementation SHOULD make the cookie as small as possible * to insure interoperability. */ -sctp_chunk_t * -sctp_make_cookie_echo(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) { - sctp_chunk_t *retval; + sctp_chunk_t *retval; void *cookie; int cookie_len; cookie = asoc->peer.cookie; cookie_len = asoc->peer.cookie_len; - /* Build a cookie echo chunk. */ - retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); - if (NULL == retval) { goto nodata; } - retval->subh.cookie_hdr = - sctp_addto_chunk(retval, cookie_len, cookie); - + /* Build a cookie echo chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); + if (!retval) + goto nodata; + retval->subh.cookie_hdr = + sctp_addto_chunk(retval, cookie_len, cookie); + /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -399,44 +389,40 @@ sctp_make_cookie_echo(const sctp_association_t *asoc, * * [COOKIE ECHO back to where the INIT ACK came from.] */ - if (NULL != chunk) { + if (chunk) retval->transport = chunk->transport; - } nodata: - return retval; - -} /* sctp_make_cookie_echo() */ - + return retval; +} /* 3.3.12 Cookie Acknowledgement (COOKIE ACK) (11): * * This chunk is used only during the initialization of an - * association. It is used to acknowledge the receipt of a COOKIE + * association. It is used to acknowledge the receipt of a COOKIE * ECHO chunk. This chunk MUST precede any DATA or SACK chunk sent * within the association, but MAY be bundled with one or more DATA * chunks or SACK chunk in the same SCTP packet. - * + * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type = 11 |Chunk Flags | Length = 4 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * + * * Chunk Flags: 8 bits - * - * + * * Set to zero on transmit and ignored on receipt. */ -sctp_chunk_t * -sctp_make_cookie_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk) +sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) { - sctp_chunk_t *retval; + sctp_chunk_t *retval; - retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); + retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -444,18 +430,16 @@ sctp_make_cookie_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk) * * [COOKIE ACK back to where the COOKIE ECHO came from.] */ - if (NULL != retval && NULL != chunk) { + if (retval && chunk) retval->transport = chunk->transport; - } - - return retval; -} /* sctp_make_cookie_ack() */ + return retval; +} -/* - * Appendix A: Explicit Congestion Notification: +/* + * Appendix A: Explicit Congestion Notification: * CWR: - * + * * RFC 2481 details a specific bit for a sender to send in the header of * its next outbound TCP segment to indicate to its peer that it has * reduced its congestion window. This is termed the CWR bit. For @@ -475,23 +459,25 @@ sctp_make_cookie_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk) * * Note: The CWR is considered a Control chunk. */ -sctp_chunk_t * -sctp_make_cwr(const sctp_association_t *asoc, const uint32_t lowest_tsn, - const sctp_chunk_t *chunk) +sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, + const __u32 lowest_tsn, + const sctp_chunk_t *chunk) { - sctp_chunk_t *retval; + sctp_chunk_t *retval; sctp_cwrhdr_t cwr; - + cwr.lowest_tsn = htonl(lowest_tsn); - retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, - sizeof(sctp_cwrhdr_t)); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, + sizeof(sctp_cwrhdr_t)); + + if (!retval) + goto nodata; - if (NULL == retval) { goto nodata; } - retval->subh.ecn_cwr_hdr = - sctp_addto_chunk(retval, sizeof(cwr), &cwr); + retval->subh.ecn_cwr_hdr = + sctp_addto_chunk(retval, sizeof(cwr), &cwr); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -500,49 +486,43 @@ sctp_make_cwr(const sctp_association_t *asoc, const uint32_t lowest_tsn, * [Report a reduced congestion window back to where the ECNE * came from.] */ - if (NULL != chunk) { + if (chunk) retval->transport = chunk->transport; - } - - nodata: - return retval; -} /* sctp_make_cwr() */ +nodata: + return retval; +} /* Make an ECNE chunk. This is a congestion experienced report. */ -sctp_chunk_t * -sctp_make_ecne(const sctp_association_t *asoc, const uint32_t lowest_tsn) +sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, + const __u32 lowest_tsn) { - sctp_chunk_t *retval; + sctp_chunk_t *retval; sctp_ecnehdr_t ecne; - + ecne.lowest_tsn = htonl(lowest_tsn); - retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, - sizeof(sctp_ecnehdr_t)); - if (NULL == retval) { goto nodata; } - retval->subh.ecne_hdr = - sctp_addto_chunk(retval, sizeof(ecne), &ecne); + retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, + sizeof(sctp_ecnehdr_t)); + if (!retval) + goto nodata; + retval->subh.ecne_hdr = + sctp_addto_chunk(retval, sizeof(ecne), &ecne); nodata: - return retval; - -} /* sctp_make_ecne() */ - + return retval; +} -/* Make a DATA chunk for the given association from the provided - * parameters. However, do not populate the data payload. +/* Make a DATA chunk for the given association from the provided + * parameters. However, do not populate the data payload. */ -sctp_chunk_t * -sctp_make_datafrag_empty(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len, uint8_t flags, uint16_t ssn) +sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, __u8 flags, __u16 ssn) { sctp_chunk_t *retval; sctp_datahdr_t dp; int chunk_len; - - retval = NULL; - + /* We assign the TSN as LATE as possible, not here when * creating the chunk. */ @@ -551,114 +531,97 @@ sctp_make_datafrag_empty(sctp_association_t *asoc, dp.ppid = htonl(sinfo->sinfo_ppid); dp.ssn = htons(ssn); - /* Set the flags for an unordered send. */ - if (sinfo->sinfo_flags & MSG_UNORDERED) { + /* Set the flags for an unordered send. */ + if (sinfo->sinfo_flags & MSG_UNORDERED) flags |= SCTP_DATA_UNORDERED; - } - + chunk_len = sizeof(dp) + data_len; - retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); - if (NULL == retval) { goto nodata; } - + if (!retval) + goto nodata; + retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); - memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); - + memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); + nodata: - return retval; - -} /* sctp_make_datafrag_empty() */ + return retval; +} /* Make a DATA chunk for the given association. Populate the data * payload. */ -sctp_chunk_t * -sctp_make_datafrag(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len, const uint8_t *data, - uint8_t flags, uint16_t ssn) +sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const __u8 *data, + __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; - - retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); - if (NULL != retval) { - sctp_addto_chunk(retval, data_len, data); - } + sctp_chunk_t *retval; + + retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); + if (retval) + sctp_addto_chunk(retval, data_len, data); - return retval; - -} /* sctp_make_datafrag() */ + return retval; +} /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body of 'data'. */ -sctp_chunk_t * -sctp_make_data(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len, const uint8_t *data) +sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len, const __u8 *data) { - sctp_chunk_t *retval = NULL; - - retval = sctp_make_data_empty(asoc, sinfo, data_len); - - if (NULL != retval) { - sctp_addto_chunk(retval, data_len, data); - } + sctp_chunk_t *retval = NULL; + retval = sctp_make_data_empty(asoc, sinfo, data_len); + if (retval) + sctp_addto_chunk(retval, data_len, data); return retval; - -} /* sctp_make_data() */ +} /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body big enough to * hold 'data_len' octets of data. We use this version when we need * to build the message AFTER allocating memory. */ -sctp_chunk_t * -sctp_make_data_empty(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - int data_len) +sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, + const struct sctp_sndrcvinfo *sinfo, + int data_len) { - sctp_chunk_t *retval; - uint16_t ssn; - uint8_t flags = SCTP_DATA_NOT_FRAG; - + sctp_chunk_t *retval; + __u16 ssn; + __u8 flags = SCTP_DATA_NOT_FRAG; + /* Sockets API Extensions for SCTP 5.2.2 * MSG_UNORDERED - This flag requests the un-ordered delivery of the - * message. If this flag is clear, the datagram is considered an - * ordered send and a new ssn is generated. The flags field is set - * in the inner routine - sctp_make_datafrag_empty(). + * message. If this flag is clear, the datagram is considered an + * ordered send and a new ssn is generated. The flags field is set + * in the inner routine - sctp_make_datafrag_empty(). */ if (sinfo->sinfo_flags & MSG_UNORDERED) { ssn = 0; } else { - ssn = __sctp_association_get_next_ssn(asoc, + ssn = __sctp_association_get_next_ssn(asoc, sinfo->sinfo_stream); } - - retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); - if (NULL == retval) { goto nodata; } - -nodata: - return retval; -} /* sctp_make_data_empty() */ + return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); +} /* Create a selective ackowledgement (SACK) for the given * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. */ -sctp_chunk_t * -sctp_make_sack(const sctp_association_t *asoc) +sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) { - sctp_chunk_t *retval; - sctp_sackhdr_t sack; + sctp_chunk_t *retval; + sctp_sackhdr_t sack; sctp_gap_ack_block_t gab; - int length; - uint32_t ctsn; + int length; + __u32 ctsn; sctp_tsnmap_iter_t iter; - uint16_t num_gabs; - uint16_t num_dup_tsns = asoc->peer.next_dup_tsn; + __u16 num_gabs; + __u16 num_dup_tsns = asoc->peer.next_dup_tsn; const sctp_tsnmap_t *map = &asoc->peer.tsn_map; ctsn = sctp_tsnmap_get_ctsn(map); @@ -667,36 +630,36 @@ sctp_make_sack(const sctp_association_t *asoc) /* Count the number of Gap Ack Blocks. */ sctp_tsnmap_iter_init(map, &iter); - for (num_gabs = 0; - sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); + for (num_gabs = 0; + sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); num_gabs++) { /* Do nothing. */ } - - /* Initialize the SACK header. */ - sack.cum_tsn_ack = htonl(ctsn); - sack.a_rwnd = htonl(asoc->rwnd); - sack.num_gap_ack_blocks = htons(num_gabs); - sack.num_dup_tsns = htons(num_dup_tsns); + /* Initialize the SACK header. */ + sack.cum_tsn_ack = htonl(ctsn); + sack.a_rwnd = htonl(asoc->rwnd); + sack.num_gap_ack_blocks = htons(num_gabs); + sack.num_dup_tsns = htons(num_dup_tsns); - length = sizeof(sack) - + sizeof(sctp_gap_ack_block_t) * num_gabs + length = sizeof(sack) + + sizeof(sctp_gap_ack_block_t) * num_gabs + sizeof(sctp_dup_tsn_t) * num_dup_tsns; - - /* Create the chunk. */ - retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); - if (NULL == retval) { goto nodata; } + + /* Create the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); + if (!retval) + goto nodata; /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, etc.) to the same destination transport * address from which it received the DATA or control chunk to * which it is replying. This rule should also be followed if * the endpoint is bundling DATA chunks together with the * reply chunk. - * + * * However, when acknowledging multiple DATA chunks received * in packets from different source addresses in a single * SACK, the SACK chunk may be transmitted to one of the @@ -707,7 +670,7 @@ sctp_make_sack(const sctp_association_t *asoc) * Perhaps we should remember the last transport we used for a * SACK and avoid that (if possible) if we have seen any * duplicates. --piggy] - * + * * When a receiver of a duplicate DATA chunk sends a SACK to a * multi- homed endpoint it MAY be beneficial to vary the * destination address and not use the source address of the @@ -715,16 +678,15 @@ sctp_make_sack(const sctp_association_t *asoc) * from a multi-homed endpoint might indicate that the return * path (as specified in the source address of the DATA chunk) * for the SACK is broken. - * - * + * * [Send to the address from which we last received a DATA chunk.] */ retval->transport = asoc->peer.last_data_from; - retval->subh.sack_hdr = - sctp_addto_chunk(retval, sizeof(sack), &sack); - - /* Put the Gap Ack Blocks into the chunk. */ + retval->subh.sack_hdr = + sctp_addto_chunk(retval, sizeof(sack), &sack); + + /* Put the Gap Ack Blocks into the chunk. */ sctp_tsnmap_iter_init(map, &iter); while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { gab.start = htons(gab.start); @@ -734,47 +696,45 @@ sctp_make_sack(const sctp_association_t *asoc) &gab); } - /* Register the duplicates. */ + /* Register the duplicates. */ sctp_addto_chunk(retval, sizeof(sctp_dup_tsn_t) * num_dup_tsns, &asoc->peer.dup_tsns); - nodata: - return retval; -} /* sctp_make_sack() */ +nodata: + return retval; +} -sctp_chunk_t * -sctp_make_shutdown(const sctp_association_t *asoc) +sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) { - sctp_chunk_t *retval; - sctp_shutdownhdr_t shut; - uint32_t ctsn; + sctp_chunk_t *retval; + sctp_shutdownhdr_t shut; + __u32 ctsn; ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); - shut.cum_tsn_ack = htonl(ctsn); + shut.cum_tsn_ack = htonl(ctsn); - retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, sizeof(sctp_shutdownhdr_t)); - if (NULL == retval) { goto nodata; } - - retval->subh.shutdown_hdr = - sctp_addto_chunk(retval, sizeof(shut), &shut); + if (!retval) + goto nodata; - nodata: - return retval; + retval->subh.shutdown_hdr = + sctp_addto_chunk(retval, sizeof(shut), &shut); -} /* sctp_make_shutdown() */ +nodata: + return retval; +} -sctp_chunk_t * -sctp_make_shutdown_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) { - sctp_chunk_t *retval; + sctp_chunk_t *retval; - retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -782,28 +742,25 @@ sctp_make_shutdown_ack(const sctp_association_t *asoc, * * [ACK back to where the SHUTDOWN came from.] */ - if (NULL != retval && NULL != chunk) { + if (retval && chunk) retval->transport = chunk->transport; - } - return retval; - -} /* sctp_make_shutdown_ack() */ + return retval; +} -sctp_chunk_t * -sctp_make_shutdown_complete(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) { - sctp_chunk_t *retval; - uint8_t flags = 0; + sctp_chunk_t *retval; + __u8 flags = 0; - /* Maybe set the T-bit if we have no association. */ - flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; - retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); + retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -812,31 +769,29 @@ sctp_make_shutdown_complete(const sctp_association_t *asoc, * [Report SHUTDOWN COMPLETE back to where the SHUTDOWN ACK * came from.] */ - if (NULL != retval && NULL != chunk) { + if (retval && chunk) retval->transport = chunk->transport; - } return retval; - -} /* sctp_make_shutdown_complete() */ +} /* Create an ABORT. Note that we set the T bit if we have no * association. */ -sctp_chunk_t * -sctp_make_abort(const sctp_association_t *asoc, const sctp_chunk_t *chunk, - const size_t hint) +sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + const size_t hint) { - sctp_chunk_t *retval; - uint8_t flags = 0; + sctp_chunk_t *retval; + __u8 flags = 0; - /* Maybe set the T-bit if we have no association. */ - flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; + /* Maybe set the T-bit if we have no association. */ + flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; - retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); + retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -844,34 +799,32 @@ sctp_make_abort(const sctp_association_t *asoc, const sctp_chunk_t *chunk, * * [ABORT back to where the offender came from.] */ - if (NULL != retval && NULL != chunk) { + if (retval && chunk) retval->transport = chunk->transport; - } - - return retval; -} /* sctp_make_abort() */ + return retval; +} -/* Helper to create ABORT with a NO_USER_DATA error. */ -sctp_chunk_t * -sctp_make_abort_no_data(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, uint32_t tsn) +/* Helper to create ABORT with a NO_USER_DATA error. */ +sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, __u32 tsn) { - sctp_chunk_t *retval; - uint32_t payload; + sctp_chunk_t *retval; + __u32 payload; - retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + sizeof(tsn)); - if (!retval) { goto no_mem; } + if (!retval) + goto no_mem; - /* Put the tsn back into network byte order. */ + /* Put the tsn back into network byte order. */ payload = htonl(tsn); - sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, + sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, sizeof(payload)); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -879,48 +832,47 @@ sctp_make_abort_no_data(const sctp_association_t *asoc, * * [ABORT back to where the offender came from.] */ - if (chunk) { + if (chunk) retval->transport = chunk->transport; - } no_mem: - return retval; - -} /* sctp_make_abort_no_data() */ - + return retval; +} -/* Make a HEARTBEAT chunk. */ -sctp_chunk_t * -sctp_make_heartbeat(const sctp_association_t *asoc, - const sctp_transport_t *transport, - const void *payload, const size_t paylen) +/* Make a HEARTBEAT chunk. */ +sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, + const sctp_transport_t *transport, + const void *payload, const size_t paylen) { - sctp_chunk_t *retval; - retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, paylen); - if (NULL == retval) { goto nodata; } + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, + 0, paylen); + + if (!retval) + goto nodata; /* Cast away the 'const', as this is just telling the chunk * what transport it belongs to. */ - retval->transport = (sctp_transport_t *)transport; + retval->transport = (sctp_transport_t *) transport; retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); - nodata: - return retval; -} /* sctp_make_heartbeat() */ +nodata: + return retval; +} -sctp_chunk_t * -sctp_make_heartbeat_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, - const void *payload, const size_t paylen) +sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + const void *payload, const size_t paylen) { - sctp_chunk_t *retval; - retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); - if (NULL == retval) { goto nodata; } + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, + 0, paylen); + + if (!retval) + goto nodata; retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk @@ -928,115 +880,104 @@ sctp_make_heartbeat_ack(const sctp_association_t *asoc, * * [HBACK back to where the HEARTBEAT came from.] */ - if (NULL != chunk) { + if (chunk) retval->transport = chunk->transport; - } - - nodata: - return retval; - -} /* sctp_make_heartbeat_ack() */ - +nodata: + return retval; +} -/* Create an Operation Error chunk. */ -sctp_chunk_t * -sctp_make_op_error(const sctp_association_t *asoc, const sctp_chunk_t *chunk, - uint16_t cause_code, const void *payload, size_t paylen) +/* Create an Operation Error chunk. */ +sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + __u16 cause_code, const void *payload, + size_t paylen) { - sctp_chunk_t *retval; - - retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, - sizeof(sctp_errhdr_t) + paylen); - if (NULL == retval) { goto nodata; } - - sctp_init_cause(retval, cause_code, payload, paylen); + sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, + sizeof(sctp_errhdr_t) + paylen); + + if (!retval) + goto nodata; + sctp_init_cause(retval, cause_code, payload, paylen); /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * + * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk * to which it is replying. - * */ - if (NULL != chunk) { + if (chunk) retval->transport = chunk->transport; - } - - nodata: - return retval; -} /* sctp_make_op_error() */ +nodata: + return retval; +} /******************************************************************** * 2nd Level Abstractions ********************************************************************/ - -/* Turn an skb into a chunk. +/* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */ -sctp_chunk_t * -sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, - struct sock *sk) +sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, + struct sock *sk) { - sctp_chunk_t *retval; - - retval = t_new(sctp_chunk_t, GFP_ATOMIC); - if (NULL == retval) { goto nodata; } - memset(retval, 0, sizeof(sctp_chunk_t)); - - if (!sk) { - SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); - } - - retval->skb = skb; - retval->asoc = (sctp_association_t *)asoc; - retval->num_times_sent = 0; - retval->has_tsn = 0; - retval->rtt_in_progress = 0; - retval->sent_at = jiffies; - retval->singleton = 1; - retval->end_of_packet = 0; - retval->ecn_ce_done = 0; - retval->pdiscard = 0; - - /* sctpimpguide-05.txt Section 2.8.2 - * M1) Each time a new DATA chunk is transmitted + sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); + + if (!retval) + goto nodata; + memset(retval, 0, sizeof(sctp_chunk_t)); + + if (!sk) { + SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); + } + + retval->skb = skb; + retval->asoc = (sctp_association_t *) asoc; + retval->num_times_sent = 0; + retval->has_tsn = 0; + retval->rtt_in_progress = 0; + retval->sent_at = jiffies; + retval->singleton = 1; + retval->end_of_packet = 0; + retval->ecn_ce_done = 0; + retval->pdiscard = 0; + + /* sctpimpguide-05.txt Section 2.8.2 + * M1) Each time a new DATA chunk is transmitted * set the 'TSN.Missing.Report' count for that TSN to 0. The - * 'TSN.Missing.Report' count will be used to determine missing chunks + * 'TSN.Missing.Report' count will be used to determine missing chunks * and when to fast retransmit. */ retval->tsn_missing_report = 0; retval->tsn_gap_acked = 0; retval->fast_retransmit = 0; - /* Polish the bead hole. */ - INIT_LIST_HEAD(&retval->transmitted_list); + /* Polish the bead hole. */ + INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); - nodata: - return retval; - -} /* sctp_chunkify() */ +nodata: + return retval; +} /* Set chunk->source based on the IP header in chunk->skb. */ -void -sctp_init_source(sctp_chunk_t *chunk) +void sctp_init_source(sctp_chunk_t *chunk) { - sockaddr_storage_t *source; - struct sk_buff *skb; - struct sctphdr *sh; - struct iphdr *ih4; + sockaddr_storage_t *source; + struct sk_buff *skb; + struct sctphdr *sh; + struct iphdr *ih4; struct ipv6hdr *ih6; - - source = &chunk->source; - skb = chunk->skb; - ih4 = skb->nh.iph; - ih6 = skb->nh.ipv6h; - sh = chunk->sctp_hdr; + + source = &chunk->source; + skb = chunk->skb; + ih4 = skb->nh.iph; + ih6 = skb->nh.ipv6h; + sh = chunk->sctp_hdr; switch (ih4->version) { case 4: @@ -1044,456 +985,425 @@ sctp_init_source(sctp_chunk_t *chunk) source->v4.sin_port = ntohs(sh->source); source->v4.sin_addr.s_addr = ih4->saddr; break; + case 6: SCTP_V6( source->v6.sin6_family = AF_INET6; source->v6.sin6_port = ntohs(sh->source); source->v6.sin6_addr = ih6->saddr; - /* FIXME: What do we do with scope, etc. ? - */ + /* FIXME: What do we do with scope, etc. ? */ break; ) + default: /* This is a bogus address type, just bail. */ break; - } /* switch (IP version of header) */ - -} /* sctp_init_source() */ + }; +} /* Extract the source address from a chunk. */ -const sockaddr_storage_t * -sctp_source(const sctp_chunk_t *chunk) +const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk) { - /* If we have a known transport, use that. */ if (chunk->transport) { return &chunk->transport->ipaddr; - } else { - /* Otherwise, extract it from the IP header. */ + } else { + /* Otherwise, extract it from the IP header. */ return &chunk->source; } - -} /* sctp_source() */ +} /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ -sctp_chunk_t * -sctp_make_chunk(const sctp_association_t *asoc, uint8_t type, uint8_t flags, - int paylen) +sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, + __u8 type, __u8 flags, int paylen) { - sctp_chunk_t *retval; - sctp_chunkhdr_t *chunk_hdr; - struct sk_buff *skb; - struct sock *sk; - - skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen)); - if (NULL == skb) { goto nodata; } - - /* Make room for the chunk header. */ - chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); - skb_pull(skb, sizeof(sctp_chunkhdr_t)); - - chunk_hdr->type = type; - chunk_hdr->flags = flags; - chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); - - /* Move the data pointer back up to the start of the chunk. */ - skb_push(skb, sizeof(sctp_chunkhdr_t)); - - sk = asoc ? asoc->base.sk : NULL; - retval = sctp_chunkify(skb, asoc, sk); - if (NULL == retval) { + sctp_chunk_t *retval; + sctp_chunkhdr_t *chunk_hdr; + struct sk_buff *skb; + struct sock *sk; + + skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen)); + if (!skb) + goto nodata; + + /* Make room for the chunk header. */ + chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); + skb_pull(skb, sizeof(sctp_chunkhdr_t)); + + chunk_hdr->type = type; + chunk_hdr->flags = flags; + chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); + + /* Move the data pointer back up to the start of the chunk. */ + skb_push(skb, sizeof(sctp_chunkhdr_t)); + + sk = asoc ? asoc->base.sk : NULL; + retval = sctp_chunkify(skb, asoc, sk); + if (!retval) { dev_kfree_skb(skb); - goto nodata; - } - - retval->chunk_hdr = chunk_hdr; - retval->chunk_end = ((uint8_t *)chunk_hdr) - + sizeof(sctp_chunkhdr_t); + goto nodata; + } + + retval->chunk_hdr = chunk_hdr; + retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(sctp_chunkhdr_t); /* Set the skb to the belonging sock for accounting. */ skb->sk = sk; - return retval; - nodata: - return NULL; + return retval; -} /* sctp_make_chunk() */ +nodata: + return NULL; +} /* Release the memory occupied by a chunk. */ -void -sctp_free_chunk(sctp_chunk_t *chunk) +void sctp_free_chunk(sctp_chunk_t *chunk) { - /* Make sure that we are not on any list. */ - skb_unlink((struct sk_buff *)chunk); - list_del(&chunk->transmitted_list); + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *) chunk); + list_del(&chunk->transmitted_list); /* Free the chunk skb data and the SCTP_chunk stub itself. */ - dev_kfree_skb(chunk->skb); + dev_kfree_skb(chunk->skb); kfree(chunk); SCTP_DBG_OBJCNT_DEC(chunk); - -} /* sctp_free_chunk() */ +} /* Do a deep copy of a chunk. */ -sctp_chunk_t * -sctp_copy_chunk(sctp_chunk_t *chunk, const int priority) +sctp_chunk_t *sctp_copy_chunk(sctp_chunk_t *chunk, const int priority) { - sctp_chunk_t *retval; - long offset; + sctp_chunk_t *retval; + long offset; - retval = t_new(sctp_chunk_t, priority); - if (NULL == retval) { goto nodata; } + retval = t_new(sctp_chunk_t, priority); + if (!retval) + goto nodata; - /* Do the shallow copy. */ - *retval = *chunk; + /* Do the shallow copy. */ + *retval = *chunk; - /* Make sure that the copy does NOT think it is on any lists. */ - retval->next = NULL; - retval->prev = NULL; - retval->list = NULL; - INIT_LIST_HEAD(&retval->transmitted_list); + /* Make sure that the copy does NOT think it is on any lists. */ + retval->next = NULL; + retval->prev = NULL; + retval->list = NULL; + INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); - /* Now we copy the deep structure. */ - retval->skb = skb_copy(chunk->skb, priority); - if (NULL == retval->skb) { - kfree(retval); - goto nodata; - } - - /* Move the copy headers to point into the new skb. */ - offset = ((uint8_t *)retval->skb->head) - - ((uint8_t *)chunk->skb->head); - - if (NULL != retval->param_hdr.v) { - retval->param_hdr.v += offset; - } - if (NULL != retval->subh.v) { - (retval->subh.v) += offset; - } - if (NULL != retval->chunk_end) { - ((uint8_t *)retval->chunk_end) += offset; - } - if (NULL != retval->chunk_hdr) { - ((uint8_t *)retval->chunk_hdr) += offset; - } - if (NULL != retval->sctp_hdr) { - ((uint8_t *)retval->sctp_hdr) += offset; - } - SCTP_DBG_OBJCNT_INC(chunk); - return retval; - nodata: - return NULL; + /* Now we copy the deep structure. */ + retval->skb = skb_copy(chunk->skb, priority); + if (!retval->skb) { + kfree(retval); + goto nodata; + } -} /* sctp_copy_chunk() */ + /* Move the copy headers to point into the new skb. */ + offset = ((__u8 *)retval->skb->head) + - ((__u8 *)chunk->skb->head); + + if (retval->param_hdr.v) + retval->param_hdr.v += offset; + if (retval->subh.v) + retval->subh.v += offset; + if (retval->chunk_end) + ((__u8 *) retval->chunk_end) += offset; + if (retval->chunk_hdr) + ((__u8 *) retval->chunk_hdr) += offset; + if (retval->sctp_hdr) + ((__u8 *) retval->sctp_hdr) += offset; + SCTP_DBG_OBJCNT_INC(chunk); + return retval; +nodata: + return NULL; +} /* Append bytes to the end of a chunk. Will panic if chunk is not big * enough. */ -void * -sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) { - void *target; - void *padding; + void *target; + void *padding; int chunklen = ntohs(chunk->chunk_hdr->length); int padlen = chunklen % 4; padding = skb_put(chunk->skb, padlen); - target = skb_put(chunk->skb, len); - + target = skb_put(chunk->skb, len); + memset(padding, 0, padlen); - memcpy(target, data, len); - /* Adjust the chunk length field. */ - chunk->chunk_hdr->length = htons(chunklen + padlen + len); - chunk->chunk_end = chunk->skb->tail; + memcpy(target, data, len); - return target; + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = htons(chunklen + padlen + len); + chunk->chunk_end = chunk->skb->tail; -} /* sctp_addto_chunk() */ + return target; +} /* Append bytes from user space to the end of a chunk. Will panic if * chunk is not big enough. * Returns a kernel err value. */ -int -sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data) +int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data) { - uint8_t *target; - int err = 0; - - /* Make room in chunk for data */ + __u8 *target; + int err = 0; + + /* Make room in chunk for data. */ target = skb_put(chunk->skb, len); /* Copy data (whole iovec) into chunk */ - if ((err = memcpy_fromiovec(target, data, len))) { + if ((err = memcpy_fromiovec(target, data, len))) goto out; - } - - /* Adjust the chunk length field. */ - chunk->chunk_hdr->length = - htons(ntohs(chunk->chunk_hdr->length) + len); - chunk->chunk_end = chunk->skb->tail; -out: - return err; + /* Adjust the chunk length field. */ + chunk->chunk_hdr->length = + htons(ntohs(chunk->chunk_hdr->length) + len); + chunk->chunk_end = chunk->skb->tail; -} /* sctp_user_addto_chunk() */ +out: + return err; +} /* Helper function to assign a TSN if needed. This assumes that both - * the data_hdr and association have already been assigned. + * the data_hdr and association have already been assigned. */ -void -sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) { if (!chunk->has_tsn) { /* This is the last possible instant to * assign a TSN. */ - chunk->subh.data_hdr->tsn = + chunk->subh.data_hdr->tsn = htonl(__sctp_association_get_next_tsn(chunk->asoc)); chunk->has_tsn = 1; } - } - /* Create a CLOSED association to use with an incoming packet. */ -sctp_association_t * -sctp_make_temp_asoc(const sctp_endpoint_t *ep, sctp_chunk_t *chunk, - int priority) +sctp_association_t *sctp_make_temp_asoc(const sctp_endpoint_t *ep, + sctp_chunk_t *chunk, + int priority) { - sctp_association_t *asoc; + sctp_association_t *asoc; sctp_scope_t scope; - /* Create the bare association. */ + /* Create the bare association. */ scope = sctp_scope(sctp_source(chunk)); - asoc = sctp_association_new(ep, ep->base.sk, scope, priority); - if (NULL == asoc) { goto nodata; } - - /* Create an entry for the source address of the packet. */ - switch (chunk->skb->nh.iph->version) { - case 4: - asoc->c.peer_addr.v4.sin_family = AF_INET; - asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source); - asoc->c.peer_addr.v4.sin_addr.s_addr = + asoc = sctp_association_new(ep, ep->base.sk, scope, priority); + if (!asoc) + goto nodata; + + /* Create an entry for the source address of the packet. */ + switch (chunk->skb->nh.iph->version) { + case 4: + asoc->c.peer_addr.v4.sin_family = AF_INET; + asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source); + asoc->c.peer_addr.v4.sin_addr.s_addr = chunk->skb->nh.iph->saddr; break; - case 6: - asoc->c.peer_addr.v6.sin6_family = AF_INET6; - asoc->c.peer_addr.v6.sin6_port + + case 6: + asoc->c.peer_addr.v6.sin6_family = AF_INET6; + asoc->c.peer_addr.v6.sin6_port = ntohs(chunk->sctp_hdr->source); - asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */ - asoc->c.peer_addr.v6.sin6_addr = chunk->skb->nh.ipv6h->saddr; - asoc->c.peer_addr.v6.sin6_scope_id = 0; /* BUG BUG BUG */ - break; + asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */ + asoc->c.peer_addr.v6.sin6_addr = chunk->skb->nh.ipv6h->saddr; + asoc->c.peer_addr.v6.sin6_scope_id = 0; /* BUG BUG BUG */ + break; + default: - /* Yikes! I never heard of this kind of address. */ + /* Yikes! I never heard of this kind of address. */ goto fail; - } + }; nodata: - return asoc; + return asoc; + fail: sctp_association_free(asoc); return NULL; - -} /* sctp_make_temp_asoc() */ - +} /* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */ -sctp_cookie_param_t * -sctp_pack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, - const sctp_chunk_t *init_chunk, int *cookie_len, - const uint8_t *raw_addrs, int addrs_len) - +sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_chunk_t *init_chunk, + int *cookie_len, + const __u8 *raw_addrs, int addrs_len) { - sctp_cookie_param_t *retval; + sctp_cookie_param_t *retval; sctp_signed_cookie_t *cookie; - int headersize, bodysize; + int headersize, bodysize; - headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; - bodysize = sizeof(sctp_cookie_t) + headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; + bodysize = sizeof(sctp_cookie_t) + ntohs(init_chunk->chunk_hdr->length) + addrs_len; - /* Pad out the cookie to a multiple to make the signature * functions simpler to write. */ - if (bodysize % SCTP_COOKIE_MULTIPLE) { + if (bodysize % SCTP_COOKIE_MULTIPLE) bodysize += SCTP_COOKIE_MULTIPLE - (bodysize % SCTP_COOKIE_MULTIPLE); - } - *cookie_len = headersize + bodysize; - - retval = (sctp_cookie_param_t *) - kmalloc(*cookie_len, GFP_ATOMIC); + *cookie_len = headersize + bodysize; - if (NULL == retval) { - *cookie_len = 0; + retval = (sctp_cookie_param_t *) + kmalloc(*cookie_len, GFP_ATOMIC); + if (!retval) { + *cookie_len = 0; goto nodata; - } + } /* Clear this memory since we are sending this data structure * out on the network. */ - memset(retval, 0x00, *cookie_len); + cookie = (sctp_signed_cookie_t *) retval->body; - cookie = (sctp_signed_cookie_t *)retval->body; - - /* Set up the parameter header. */ - retval->p.type = SCTP_PARAM_STATE_COOKIE; - retval->p.length = htons(*cookie_len); + /* Set up the parameter header. */ + retval->p.type = SCTP_PARAM_STATE_COOKIE; + retval->p.length = htons(*cookie_len); - /* Copy the cookie part of the association itself. */ - cookie->c = asoc->c; + /* Copy the cookie part of the association itself. */ + cookie->c = asoc->c; /* Save the raw address list length in the cookie. */ cookie->c.raw_addr_list_len = addrs_len; - /* Set an expiration time for the cookie. */ - do_gettimeofday(&cookie->c.expiration); - tv_add(&asoc->cookie_life, &cookie->c.expiration); - - /* Copy the peer's init packet. */ - memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, - ntohs(init_chunk->chunk_hdr->length)); + /* Set an expiration time for the cookie. */ + do_gettimeofday(&cookie->c.expiration); + tv_add(&asoc->cookie_life, &cookie->c.expiration); + + /* Copy the peer's init packet. */ + memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, + ntohs(init_chunk->chunk_hdr->length)); /* Copy the raw local address list of the association. */ - memcpy((uint8_t *)&cookie->c.peer_init[0] + - ntohs(init_chunk->chunk_hdr->length), raw_addrs, - addrs_len); - - /* Sign the message. */ - sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, - (uint8_t *)&cookie->c, bodysize, cookie->signature); - -nodata: - return retval; + memcpy((__u8 *)&cookie->c.peer_init[0] + + ntohs(init_chunk->chunk_hdr->length), raw_addrs, + addrs_len); -} /* sctp_pack_cookie() */ + /* Sign the message. */ + sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, + (__u8 *) &cookie->c, bodysize, cookie->signature); + +nodata: + return retval; +} /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ -sctp_association_t * -sctp_unpack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, - sctp_chunk_t *chunk, int priority, int *error) +sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, int priority, + int *error) { - sctp_association_t *retval = NULL; - sctp_signed_cookie_t *cookie; - sctp_cookie_t *bear_cookie; - int headersize, bodysize; + sctp_association_t *retval = NULL; + sctp_signed_cookie_t *cookie; + sctp_cookie_t *bear_cookie; + int headersize, bodysize; int fixed_size, var_size1, var_size2, var_size3; - uint8_t digest_buf[SCTP_SIGNATURE_SIZE]; - int secret; + __u8 digest_buf[SCTP_SIGNATURE_SIZE]; + int secret; sctp_scope_t scope; - uint8_t *raw_addr_list; - - headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; - bodysize = ntohs(chunk->chunk_hdr->length) - headersize; + __u8 *raw_addr_list; + + headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; + bodysize = ntohs(chunk->chunk_hdr->length) - headersize; fixed_size = headersize + sizeof(sctp_cookie_t); - /* Verify that the chunk looks like it even has a cookie. + /* Verify that the chunk looks like it even has a cookie. * There must be enough room for our cookie and our peer's * INIT chunk. */ - if (ntohs(chunk->chunk_hdr->length) < - (fixed_size + sizeof(sctp_chunkhdr_t))) { + if (ntohs(chunk->chunk_hdr->length) < + (fixed_size + sizeof(sctp_chunkhdr_t))) goto malformed; - } /* Verify that the cookie has been padded out. */ - if (bodysize % SCTP_COOKIE_MULTIPLE) { + if (bodysize % SCTP_COOKIE_MULTIPLE) goto malformed; - } - /* Process the cookie. */ - cookie = chunk->subh.cookie_hdr; - bear_cookie = &cookie->c; + cookie = chunk->subh.cookie_hdr; + bear_cookie = &cookie->c; var_size1 = ntohs(chunk->chunk_hdr->length) - fixed_size; var_size2 = ntohs(bear_cookie->peer_init->chunk_hdr.length); var_size3 = bear_cookie->raw_addr_list_len; - - - /* Check the signature. */ - secret = ep->current_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (uint8_t *)bear_cookie, bodysize, - digest_buf); - if (memcmp(digest_buf, cookie->signature, - SCTP_SIGNATURE_SIZE)) { - - /* Try the previous key. */ - secret = ep->last_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (uint8_t *)bear_cookie, bodysize, digest_buf); - if (memcmp(digest_buf, cookie->signature, - SCTP_SIGNATURE_SIZE)) { - /* Yikes! Still bad signature! */ - *error = -SCTP_IERROR_BAD_SIG; + + /* Check the signature. */ + secret = ep->current_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (__u8 *) bear_cookie, bodysize, + digest_buf); + if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + /* Try the previous key. */ + secret = ep->last_key; + sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, + (__u8 *) bear_cookie, bodysize, digest_buf); + if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + /* Yikes! Still bad signature! */ + *error = -SCTP_IERROR_BAD_SIG; goto fail; - } - } /* if (the current secret failed) */ + } + } /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. */ - if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { - *error = -SCTP_IERROR_STALE_COOKIE; + if (!asoc && tv_lt(bear_cookie->expiration, chunk->skb->stamp)) { + *error = -SCTP_IERROR_STALE_COOKIE; goto fail; - } + } - /* Make a new base association. */ + /* Make a new base association. */ scope = sctp_scope(sctp_source(chunk)); - retval = sctp_association_new(ep, ep->base.sk, scope, priority); - if (NULL == retval) { - *error = -SCTP_IERROR_NOMEM; + retval = sctp_association_new(ep, ep->base.sk, scope, priority); + if (!retval) { + *error = -SCTP_IERROR_NOMEM; goto fail; - } + } /* Set up our peer's port number. */ retval->peer.port = ntohs(chunk->sctp_hdr->source); - /* Populate the association from the cookie. */ - retval->c = *bear_cookie; - /* Build the bind address list based on the cookie */ - raw_addr_list = (uint8_t *)bear_cookie + + /* Populate the association from the cookie. */ + retval->c = *bear_cookie; + + /* Build the bind address list based on the cookie. */ + raw_addr_list = (__u8 *) bear_cookie + sizeof(sctp_cookie_t) + var_size2; - if (sctp_raw_to_bind_addrs(&retval->base.bind_addr, raw_addr_list, - var_size3, retval->base.bind_addr.port, + if (sctp_raw_to_bind_addrs(&retval->base.bind_addr, raw_addr_list, + var_size3, retval->base.bind_addr.port, priority)) { *error = -SCTP_IERROR_NOMEM; goto fail; } retval->next_tsn = retval->c.initial_tsn; - retval->ctsn_ack_point = retval->next_tsn - 1; + retval->ctsn_ack_point = retval->next_tsn - 1; /* The INIT stuff will be done by the side effects. */ + return retval; - return retval; - fail: - if (retval) { +fail: + if (retval) sctp_association_free(retval); - } return NULL; - malformed: +malformed: /* Yikes! The packet is either corrupt or deliberately * malformed. */ *error = -SCTP_IERROR_MALFORMED; goto fail; - -} /* sctp_unpack_cookie() */ - +} /******************************************************************** * 3rd Level Abstractions @@ -1501,20 +1411,19 @@ sctp_unpack_cookie(const sctp_endpoint_t *ep, const sctp_association_t *asoc, /* Unpack the parameters in an INIT packet. * FIXME: There is no return status to allow callers to do - * error handling. + * error handling. */ -void -sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, - const sockaddr_storage_t *peer_addr, - sctp_init_chunk_t *peer_init, - int priority) +void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, + const sockaddr_storage_t *peer_addr, + sctp_init_chunk_t *peer_init, + int priority) { sctpParam_t param; - uint8_t *end; + __u8 *end; sctp_transport_t *transport; list_t *pos, *temp; - /* We must include the address that the INIT packet came from. + /* We must include the address that the INIT packet came from. * This is the only address that matters for an INIT packet. * When processing a COOKIE ECHO, we retrieve the from address * of the INIT from the cookie. @@ -1524,57 +1433,49 @@ sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, * added as the primary transport. The source address seems to * be a a better choice than any of the embedded addresses. */ - if (NULL != peer_addr) { + if (peer_addr) sctp_assoc_add_peer(asoc, peer_addr, priority); - } - - /* Process the initialization parameters. */ - - end = ((uint8_t *)peer_init - + ntohs(peer_init->chunk_hdr.length)); - - for (param.v = peer_init->init_hdr.params; - param.v < end; - param.v += WORD_ROUND(ntohs(param.p->length))) { + /* Process the initialization parameters. */ + end = ((__u8 *)peer_init + ntohs(peer_init->chunk_hdr.length)); + for (param.v = peer_init->init_hdr.params; + param.v < end; + param.v += WORD_ROUND(ntohs(param.p->length))) { if (!sctp_process_param(asoc, param, peer_addr, cid, - priority)) { + priority)) goto clean_up; - } + } - } /* for (loop through all parameters) */ - - /* The fixed INIT headers are always in network byte * order. */ - asoc->peer.i.init_tag = + asoc->peer.i.init_tag = ntohl(peer_init->init_hdr.init_tag); asoc->peer.i.a_rwnd = ntohl(peer_init->init_hdr.a_rwnd); - asoc->peer.i.num_outbound_streams = + asoc->peer.i.num_outbound_streams = ntohs(peer_init->init_hdr.num_outbound_streams); - asoc->peer.i.num_inbound_streams = + asoc->peer.i.num_inbound_streams = ntohs(peer_init->init_hdr.num_inbound_streams); - asoc->peer.i.initial_tsn = + asoc->peer.i.initial_tsn = ntohl(peer_init->init_hdr.initial_tsn); - /* Apply the upper bounds for output streams based on peer's - * number of inbound streams. + /* Apply the upper bounds for output streams based on peer's + * number of inbound streams. */ - if (asoc->c.sinit_num_ostreams - > ntohs(peer_init->init_hdr.num_inbound_streams)) { - asoc->c.sinit_num_ostreams = + if (asoc->c.sinit_num_ostreams > + ntohs(peer_init->init_hdr.num_inbound_streams)) { + asoc->c.sinit_num_ostreams = ntohs(peer_init->init_hdr.num_inbound_streams); - } + } - /* Copy Initiation tag from INIT to VT_peer in cookie */ + /* Copy Initiation tag from INIT to VT_peer in cookie. */ asoc->c.peer_vtag = asoc->peer.i.init_tag; - /* Peer Rwnd : Current calculated value of the peer's rwnd. */ + /* Peer Rwnd : Current calculated value of the peer's rwnd. */ asoc->peer.rwnd = asoc->peer.i.a_rwnd; - /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily + /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily * high (for example, implementations MAY use the size of the receiver * advertised window). */ @@ -1588,7 +1489,7 @@ sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, asoc->peer.i.initial_tsn); /* ADDIP Section 4.1 ASCONF Chunk Procedures - * + * * When an endpoint has an ASCONF signaled change to be sent to the * remote endpoint it should do the following: * ... @@ -1598,22 +1499,19 @@ sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, * association to the same value as the Initial TSN. */ asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; - return; - clean_up: - /* Release the transport structures. */ - list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + +clean_up: + /* Release the transport structures. */ + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, sctp_transport_t, transports); list_del(pos); sctp_transport_free(transport); } - return; - -} /* sctp_process_init() */ - +} /* Update asoc with the option described in param. - * + * * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT * * asoc is the association to update. @@ -1623,10 +1521,9 @@ sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, * work we do. In particular, we should not build transport * structures for the addresses. */ -int -sctp_process_param(sctp_association_t *asoc, sctpParam_t param, - const sockaddr_storage_t *peer_addr, - sctp_cid_t cid, int priority) +int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, + const sockaddr_storage_t *peer_addr, + sctp_cid_t cid, int priority) { sockaddr_storage_t addr; int j; @@ -1634,84 +1531,93 @@ sctp_process_param(sctp_association_t *asoc, sctpParam_t param, int retval = 1; sctp_scope_t scope; -/* We maintain all INIT parameters in network byte order all the - * time. This allows us to not worry about whether the parameters - * came from a fresh INIT, and INIT ACK, or were stored in a cookie. - */ - + /* We maintain all INIT parameters in network byte order all the + * time. This allows us to not worry about whether the parameters + * came from a fresh INIT, and INIT ACK, or were stored in a cookie. + */ switch (param.p->type) { case SCTP_PARAM_IPV4_ADDRESS: if (SCTP_CID_INIT != cid) { sctp_param2sockaddr(&addr, param, asoc->peer.port); scope = sctp_scope(peer_addr); - if (sctp_in_scope(&addr, scope)) { + if (sctp_in_scope(&addr, scope)) sctp_assoc_add_peer(asoc, &addr, priority); - } } break; + case SCTP_PARAM_IPV6_ADDRESS: if (SCTP_CID_INIT != cid) { if (PF_INET6 == asoc->base.sk->family) { - sctp_param2sockaddr(&addr, param, + sctp_param2sockaddr(&addr, param, asoc->peer.port); scope = sctp_scope(peer_addr); - if (sctp_in_scope(&addr, scope)) { - sctp_assoc_add_peer(asoc, &addr, + if (sctp_in_scope(&addr, scope)) + sctp_assoc_add_peer(asoc, &addr, priority); - } } } break; + case SCTP_PARAM_COOKIE_PRESERVATIVE: - asoc->cookie_preserve - = ntohl(param.bht->lifespan_increment); + asoc->cookie_preserve = + ntohl(param.bht->lifespan_increment); break; + case SCTP_PARAM_HOST_NAME_ADDRESS: SCTP_DEBUG_PRINTK("unimplmented SCTP_HOST_NAME_ADDRESS\n"); - break; + break; + case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: /* Turn off the default values first so we'll know which - * ones are really set by the peer. + * ones are really set by the peer. */ asoc->peer.ipv4_address = 0; asoc->peer.ipv6_address = 0; - j = (ntohs(param.p->length) - - sizeof(sctp_paramhdr_t)) - / sizeof(uint16_t); + j = (ntohs(param.p->length) - + sizeof(sctp_paramhdr_t)) / + sizeof(__u16); for (i = 0; i < j; ++i) { switch (param.sat->types[i]) { case SCTP_PARAM_IPV4_ADDRESS: asoc->peer.ipv4_address = 1; break; + case SCTP_PARAM_IPV6_ADDRESS: asoc->peer.ipv6_address = 1; break; + case SCTP_PARAM_HOST_NAME_ADDRESS: asoc->peer.hostname_address = 1; break; + default: /* Just ignore anything else. */ break; - } + }; } break; + case SCTP_PARAM_STATE_COOKIE: asoc->peer.cookie_len = - ntohs(param.p->length) - - sizeof(sctp_paramhdr_t); + ntohs(param.p->length) = + sizeof(sctp_paramhdr_t); asoc->peer.cookie = param.cookie->body; break; + case SCTP_PARAM_HEATBEAT_INFO: SCTP_DEBUG_PRINTK("unimplmented " "SCTP_PARAM_HEATBEAT_INFO\n"); break; + case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: SCTP_DEBUG_PRINTK("unimplemented " "SCTP_PARAM_UNRECOGNIZED_PARAMETERS\n"); break; + case SCTP_PARAM_ECN_CAPABLE: - asoc->peer.ecn_capable = 1; + asoc->peer.ecn_capable = 1; break; + default: SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", ntohs(param.p->type), asoc); @@ -1722,46 +1628,42 @@ sctp_process_param(sctp_association_t *asoc, sctpParam_t param, retval = 1; break; - } - return retval; + }; -} /* sctp_process_param() */ + return retval; +} /* Select a new verification tag. */ -uint32_t -sctp_generate_tag(const sctp_endpoint_t *ep) +__u32 sctp_generate_tag(const sctp_endpoint_t *ep) { - /* I believe that this random number generator complies with RFC1750. + /* I believe that this random number generator complies with RFC1750. * A tag of 0 is reserved for special cases (e.g. INIT). */ - uint32_t x; - do { get_random_bytes(&x, sizeof(uint32_t)); } while( x==0 ); - return x; + __u32 x; -} /* sctp_generate_tag() */ + do { + get_random_bytes(&x, sizeof(__u32)); + } while (x == 0); + + return x; +} /* Select an initial TSN to send during startup. */ -uint32_t -sctp_generate_tsn(const sctp_endpoint_t *ep) +__u32 sctp_generate_tsn(const sctp_endpoint_t *ep) { - /* I believe that this random number generator complies with RFC1750. - */ - - uint32_t retval; - get_random_bytes(&retval, sizeof(uint32_t)); + /* I believe that this random number generator complies with RFC1750. */ + __u32 retval; - return retval; - -} /* sctp_generate_tsn() */ + get_random_bytes(&retval, sizeof(__u32)); + return retval; +} /******************************************************************** * 4th Level Abstractions ********************************************************************/ /* Convert from an SCTP IP parameter to a sockaddr_storage_t. */ -void -sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, - uint16_t port) +void sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, __u16 port) { switch(param.p->type) { case SCTP_PARAM_IPV4_ADDRESS: @@ -1769,6 +1671,7 @@ sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, addr->v4.sin_port = port; addr->v4.sin_addr.s_addr = param.v4->addr.s_addr; break; + case SCTP_PARAM_IPV6_ADDRESS: addr->v6.sin6_family = AF_INET6; addr->v6.sin6_port = port; @@ -1776,84 +1679,88 @@ sctp_param2sockaddr(sockaddr_storage_t *addr, sctpParam_t param, addr->v6.sin6_addr = param.v6->addr; addr->v6.sin6_scope_id = 0; /* BUG */ break; + default: SCTP_DEBUG_PRINTK("Illegal address type %d\n", ntohs(param.p->type)); break; - } -} /* sctp_param2sockaddr() */ + }; +} /* Convert an IP address in an SCTP param into a sockaddr_in. */ /* Returns true if a valid conversion was possible. */ -int -sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) +int sctp_addr2sockaddr(sctpParam_t p, sockaddr_storage_t *sa) { - if (NULL == p.v) { - return 0; - } - switch (p.p->type) { - case SCTP_PARAM_IPV4_ADDRESS: - sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); - sa->v4.sin_family = AF_INET; - break; - case SCTP_PARAM_IPV6_ADDRESS: - *((struct in6_addr *)&sa->v4.sin_addr) - = p.v6->addr; - sa->v4.sin_family = AF_INET6; - break; + if (!p.v) + return 0; + + switch (p.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); + sa->v4.sin_family = AF_INET; + break; + + case SCTP_PARAM_IPV6_ADDRESS: + *((struct in6_addr *)&sa->v4.sin_addr) + = p.v6->addr; + sa->v4.sin_family = AF_INET6; + break; + default: return 0; - } - return 1; + }; -} /* sctp_addr2sockaddr() */ + return 1; +} /* Convert from an IP version number to an Address Family symbol. */ -int ipver2af(uint8_t ipver) +int ipver2af(__u8 ipver) { - int family; - switch (ipver) { - case 4: - family = AF_INET; - break; - case 6: - family = AF_INET6; - break; - default: - family = 0; - break; - } /* switch (ipversion) */ + int family; + + switch (ipver) { + case 4: + family = AF_INET; + break; + + case 6: + family = AF_INET6; + break; - return family; + default: + family = 0; + break; + }; -} /* ipver2af() */ + return family; +} /* Convert a sockaddr_in to IP address in an SCTP para. */ /* Returns true if a valid conversion was possible. */ -int -sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctpParam_t p) +int sockaddr2sctp_addr(const sockaddr_storage_t *sa, sctpParam_t p) { - int len = 0; - - switch (sa->v4.sin_family) { - case AF_INET: - p.p->type = SCTP_PARAM_IPV4_ADDRESS; - p.p->length = ntohs(sizeof(sctp_ipv4addr_param_t)); - len = sizeof(sctp_ipv4addr_param_t); - p.v4->addr.s_addr = sa->v4.sin_addr.s_addr; - break; - case AF_INET6: - p.p->type = SCTP_PARAM_IPV6_ADDRESS; - p.p->length = ntohs(sizeof(sctp_ipv6addr_param_t)); - len = sizeof(sctp_ipv6addr_param_t); - p.v6->addr = *(&sa->v6.sin6_addr); - break; - default: + int len = 0; + + switch (sa->v4.sin_family) { + case AF_INET: + p.p->type = SCTP_PARAM_IPV4_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv4addr_param_t)); + len = sizeof(sctp_ipv4addr_param_t); + p.v4->addr.s_addr = sa->v4.sin_addr.s_addr; + break; + + case AF_INET6: + p.p->type = SCTP_PARAM_IPV6_ADDRESS; + p.p->length = ntohs(sizeof(sctp_ipv6addr_param_t)); + len = sizeof(sctp_ipv6addr_param_t); + p.v6->addr = *(&sa->v6.sin6_addr); + break; + + default: printk(KERN_WARNING "sockaddr2sctp_addr: Illegal family %d.\n", sa->v4.sin_family); - return 0; - } - - return len; + return 0; + }; -} /* sockaddr2sctp_addr() */ + return len; +} diff --git a/net/sctp/sctp_sm_sideeffect.c b/net/sctp/sctp_sm_sideeffect.c index 9cbafa30b839..5f568dd877c3 100644 --- a/net/sctp/sctp_sm_sideeffect.c +++ b/net/sctp/sctp_sm_sideeffect.c @@ -50,7 +50,6 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_sideeffect.c,v 1.44 2002/08/16 19:30:50 jgrimm Exp $"; #include -#include #include #include #include @@ -58,48 +57,34 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_sideeffect.c,v 1.44 #include #include - /* Do forward declarations of static functions. */ static void sctp_do_ecn_ce_work(sctp_association_t *asoc, - uint32_t lowest_tsn); -static -sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, - uint32_t lowest_tsn, - sctp_chunk_t *); -static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, - uint32_t lowest_tsn); + __u32 lowest_tsn); +static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, + __u32 lowest_tsn, + sctp_chunk_t *); +static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, + __u32 lowest_tsn); static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, sctp_transport_t *transport); -static void -sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); - -static void -sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); - -static void -sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, - sctp_chunk_t *chunk, sctp_init_chunk_t *peer_init, - int priority); -static void -sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); -static void -sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, - sctp_bind_addr_t *); - -static void -sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, - sctp_transport_t *); -static void -sctp_cmd_transport_on(sctp_cmd_seq_t *, sctp_association_t *, - sctp_transport_t *, sctp_chunk_t *); -static int -sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, - sctp_sackhdr_t *); - -static void -sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, sctp_chunk_t *); - +static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); +static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc); +static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_init_chunk_t *peer_init, + int priority); +static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *, sctp_association_t *); +static void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *, sctp_association_t *, + sctp_bind_addr_t *); +static void sctp_cmd_transport_reset(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *); +static void sctp_cmd_transport_on(sctp_cmd_seq_t *, sctp_association_t *, + sctp_transport_t *, sctp_chunk_t *); +static int sctp_cmd_process_sack(sctp_cmd_seq_t *, sctp_association_t *, + sctp_sackhdr_t *); +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, + sctp_chunk_t *); /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real @@ -116,32 +101,30 @@ sctp_cmd_setup_t2(sctp_cmd_seq_t *, sctp_association_t *, sctp_chunk_t *); SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \ "asoc %p, status: %s\n", \ asoc, sctp_status_tbl[status]) - + #define DEBUG_POST_SFX \ SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \ error, asoc, \ sctp_state_tbl[sctp_id2assoc(ep->base.sk, \ sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED]) - /* * This is the master state machine processing function. * * If you want to understand all of lksctp, this is a * good place to start. */ -int -sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, - void *event_arg, - int priority) +int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + int priority) { sctp_cmd_seq_t commands; - sctp_sm_table_entry_t *state_fn; - sctp_disposition_t status; - int error = 0; + sctp_sm_table_entry_t *state_fn; + sctp_disposition_t status; + int error = 0; typedef const char *(printfn_t)(sctp_subtype_t); static printfn_t *table[] = { @@ -152,24 +135,22 @@ sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, /* Look up the state function, run it, and then process the * side effects. These three steps are the heart of lksctp. */ + state_fn = sctp_sm_lookup_event(event_type, state, subtype); - state_fn = sctp_sm_lookup_event(event_type, state, subtype); - sctp_init_cmd_seq(&commands); DEBUG_PRE; status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands); DEBUG_POST; - + error = sctp_side_effects(event_type, subtype, state, ep, asoc, event_arg, status, &commands, priority); DEBUG_POST_SFX; - - return error; -} /* sctp_do_sm() */ + return error; +} #undef DEBUG_PRE #undef DEBUG_POST @@ -177,22 +158,20 @@ sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, /***************************************************************** * This the master state function side effect processing function. *****************************************************************/ -int -sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, - void *event_arg, - sctp_disposition_t status, - sctp_cmd_seq_t *commands, - int priority) +int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, + sctp_endpoint_t *ep, + sctp_association_t *asoc, + void *event_arg, + sctp_disposition_t status, + sctp_cmd_seq_t *commands, + int priority) { - int error; - sctp_chunk_t *chunk; - chunk = (sctp_chunk_t *)event_arg; - - /* FIXME - Most of the dispositions left today would be categorized - * as "exceptional" dispositions. For those dispositions, it + sctp_chunk_t *chunk = (sctp_chunk_t *) event_arg; + int error; + + /* FIXME - Most of the dispositions left today would be categorized + * as "exceptional" dispositions. For those dispositions, it * may not be proper to run through any of the commands at all. * For example, the command interpreter might be run only with * disposition SCTP_DISPOSITION_CONSUME. @@ -200,16 +179,16 @@ sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, ep, asoc, event_arg, status, - commands, priority))) { + commands, priority))) goto bail; - } - switch (status) { - case SCTP_DISPOSITION_DISCARD: + switch (status) { + case SCTP_DISPOSITION_DISCARD: SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, " "event_type %d, event_id %d\n", state, event_type, subtype.chunk); - break; + break; + case SCTP_DISPOSITION_NOMEM: /* We ran out of memory, so we need to discard this * packet. @@ -218,79 +197,80 @@ sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, * reneging... */ break; + case SCTP_DISPOSITION_DELETE_TCB: /* This should now be a command. */ break; - case SCTP_DISPOSITION_CONSUME: - case SCTP_DISPOSITION_ABORT: - /* - * We should no longer have much work to do here as the + + case SCTP_DISPOSITION_CONSUME: + case SCTP_DISPOSITION_ABORT: + /* + * We should no longer have much work to do here as the * real work has been done as explicit commands above. */ break; - case SCTP_DISPOSITION_VIOLATION: + + case SCTP_DISPOSITION_VIOLATION: printk(KERN_ERR "sctp protocol violation state %d " "chunkid %d\n", state, subtype.chunk); - break; - case SCTP_DISPOSITION_NOT_IMPL: + break; + + case SCTP_DISPOSITION_NOT_IMPL: printk(KERN_WARNING "sctp unimplemented feature in state %d, " "event_type %d, event_id %d\n", state, event_type, subtype.chunk); - - break; + break; + case SCTP_DISPOSITION_BUG: printk(KERN_ERR "sctp bug in state %d, " "event_type %d, event_id %d\n", state, event_type, subtype.chunk); BUG(); break; - default: + + default: printk(KERN_ERR "sctp impossible disposition %d " "in state %d, event_type %d, event_id %d\n", status, state, event_type, subtype.chunk); BUG(); - break; - } /* switch (status) */ - - bail: - return error; + break; + }; -} /* sctp_side_effects() */ +bail: + return error; +} /******************************************************************** * 2nd Level Abstractions ********************************************************************/ /* This is the side-effect interpreter. */ -int -sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, sctp_endpoint_t *ep, - sctp_association_t *asoc, void *event_arg, - sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority) +int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, + sctp_state_t state, sctp_endpoint_t *ep, + sctp_association_t *asoc, void *event_arg, + sctp_disposition_t status, sctp_cmd_seq_t *commands, + int priority) { - int error = 0; + int error = 0; int force; sctp_cmd_t *command; sctp_chunk_t *new_obj; sctp_chunk_t *chunk; sctp_packet_t *packet; - struct timer_list *timer; - unsigned long timeout; - sctp_transport_t *t; - sctp_sackhdr_t sackh; - + struct timer_list *timer; + unsigned long timeout; + sctp_transport_t *t; + sctp_sackhdr_t sackh; - chunk = (sctp_chunk_t *)event_arg; + chunk = (sctp_chunk_t *) event_arg; - /* Note: This whole file is a huge candidate for rework. - * For example, each command could either have its own handler, so - * the loop would look like: + /* Note: This whole file is a huge candidate for rework. + * For example, each command could either have its own handler, so + * the loop would look like: * while (cmds) * cmd->handle(x, y, z) * --jgrimm */ - while (NULL != (command = sctp_next_cmd(commands))) { switch (command->verb) { case SCTP_CMD_NOP: @@ -312,7 +292,7 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_PURGE_OUTQUEUE: sctp_outqueue_teardown(&asoc->outqueue); break; - + case SCTP_CMD_DELETE_TCB: /* Delete the current association. */ sctp_unhash_established(asoc); @@ -321,7 +301,7 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, break; case SCTP_CMD_NEW_STATE: - /* Enter a new state. */ + /* Enter a new state. */ asoc->state = command->obj.state; asoc->state_timestamp = jiffies; break; @@ -344,46 +324,47 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_PROCESS_SACK: /* Process an inbound SACK. */ - error = sctp_cmd_process_sack(commands, asoc, + error = sctp_cmd_process_sack(commands, asoc, command->obj.ptr); break; - case SCTP_CMD_GEN_INIT_ACK: /* Generate an INIT ACK chunk. */ new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC); - if (!new_obj) { goto nomem; } + if (!new_obj) + goto nomem; - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; case SCTP_CMD_PEER_INIT: - /* Process a unified INIT from the peer. */ - sctp_cmd_process_init(commands, + /* Process a unified INIT from the peer. */ + sctp_cmd_process_init(commands, asoc, chunk, command->obj.ptr, priority); break; case SCTP_CMD_GEN_COOKIE_ECHO: - /* Generate a COOKIE ECHO chunk. */ + /* Generate a COOKIE ECHO chunk. */ new_obj = sctp_make_cookie_echo(asoc, chunk); - if (!new_obj) { goto nomem; } - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + if (!new_obj) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; case SCTP_CMD_GEN_SHUTDOWN: - /* Generate SHUTDOWN when in SHUTDOWN_SENT state. - * Reset error counts. + /* Generate SHUTDOWN when in SHUTDOWN_SENT state. + * Reset error counts. */ asoc->overall_error_count = 0; - - /* Generate a SHUTDOWN chunk. */ + /* Generate a SHUTDOWN chunk. */ new_obj = sctp_make_shutdown(asoc); - if (!new_obj) { goto nomem; } - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + if (!new_obj) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; @@ -400,28 +381,28 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, break; case SCTP_CMD_EVENT_ULP: - /* Send a notification to the sockets layer. */ + /* Send a notification to the sockets layer. */ SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n", "event_up:", command->obj.ptr, "ulpq:", &asoc->ulpq); - sctp_ulpqueue_tail_event(&asoc->ulpq, + sctp_ulpqueue_tail_event(&asoc->ulpq, command->obj.ptr); break; case SCTP_CMD_REPLY: /* Send a chunk to our peer. */ - error = sctp_push_outqueue(&asoc->outqueue, + error = sctp_push_outqueue(&asoc->outqueue, command->obj.ptr); break; case SCTP_CMD_SEND_PKT: /* Send a full packet to our peer. */ packet = command->obj.ptr; - sctp_packet_transmit(packet); - sctp_transport_free(packet->transport); - sctp_packet_free(packet); + sctp_packet_transmit(packet); + sctp_transport_free(packet->transport); + sctp_packet_free(packet); break; case SCTP_CMD_RETRAN: @@ -460,50 +441,46 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sctp_cmd_setup_t2(commands, asoc, command->obj.ptr); break; - case SCTP_CMD_TIMER_START: + case SCTP_CMD_TIMER_START: timer = &asoc->timers[command->obj.to]; timeout = asoc->timeouts[command->obj.to]; - if (0 == timeout) { BUG(); } + if (!timeout) + BUG(); - timer->expires = jiffies + timeout; + timer->expires = jiffies + timeout; sctp_association_hold(asoc); - add_timer(timer); - break; + add_timer(timer); + break; - case SCTP_CMD_TIMER_RESTART: + case SCTP_CMD_TIMER_RESTART: timer = &asoc->timers[command->obj.to]; timeout = asoc->timeouts[command->obj.to]; - - if (!mod_timer(timer, jiffies + timeout)) { + if (!mod_timer(timer, jiffies + timeout)) sctp_association_hold(asoc); - } - break; + break; - case SCTP_CMD_TIMER_STOP: + case SCTP_CMD_TIMER_STOP: timer = &asoc->timers[command->obj.to]; - if (timer_pending(timer) && del_timer(timer)) { + if (timer_pending(timer) && del_timer(timer)) sctp_association_put(asoc); - } - break; + break; case SCTP_CMD_INIT_RESTART: /* Do the needed accounting and updates * associated with restarting an initialization - * timer. + * timer. */ asoc->counters[SCTP_COUNTER_INIT_ERROR]++; asoc->timeouts[command->obj.to] *= 2; - - if (asoc->timeouts[command->obj.to] - > asoc->max_init_timeo) { - asoc->timeouts[command->obj.to] - = asoc->max_init_timeo; + if (asoc->timeouts[command->obj.to] > + asoc->max_init_timeo) { + asoc->timeouts[command->obj.to] = + asoc->max_init_timeo; } - + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(command->obj.to)); - break; case SCTP_CMD_INIT_FAILED: @@ -517,15 +494,15 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_COUNTER_INC: asoc->counters[command->obj.counter]++; break; - + case SCTP_CMD_COUNTER_RESET: - asoc->counters[command->obj.counter]=0; + asoc->counters[command->obj.counter] = 0; break; case SCTP_CMD_REPORT_DUP: if (asoc->peer.next_dup_tsn < SCTP_MAX_DUP_TSNS) { - asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] - = ntohl(command->obj.u32); + asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] = + ntohl(command->obj.u32); } break; @@ -535,6 +512,7 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, &asoc->peer.tsn_map), command->obj.u32); break; + case SCTP_CMD_REPORT_BAD_TAG: SCTP_DEBUG_PRINTK("vtag mismatch!\n"); break; @@ -553,17 +531,17 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_TRANSPORT_RESET: t = command->obj.transport; sctp_cmd_transport_reset(commands, asoc, t); - break; - + break; + case SCTP_CMD_TRANSPORT_ON: - t = command->obj.transport; + t = command->obj.transport; sctp_cmd_transport_on(commands, asoc, t, chunk); - break; - + break; + case SCTP_CMD_HB_TIMERS_START: - sctp_cmd_hb_timers_start(commands, asoc); + sctp_cmd_hb_timers_start(commands, asoc); break; - + case SCTP_CMD_REPORT_ERROR: error = command->obj.error; break; @@ -574,92 +552,81 @@ sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sackh.a_rwnd = 0; sackh.num_gap_ack_blocks = 0; sackh.num_dup_tsns = 0; - sctp_add_cmd_sf(commands, - SCTP_CMD_PROCESS_SACK, + sctp_add_cmd_sf(commands, + SCTP_CMD_PROCESS_SACK, SCTP_SACKH(&sackh)); break; - + case SCTP_CMD_DISCARD_PACKET: /* We need to discard the whole packet. */ chunk->pdiscard = 1; break; - + default: printk(KERN_WARNING "Impossible command: %u, %p\n", command->verb, command->obj.ptr); break; - } /* switch (cmd->verb) */ - } /* while (more commands) */ + }; + } return error; nomem: error = -ENOMEM; return error; - -} /* sctp_cmd_interpreter() */ - +} /* A helper function for delayed processing of INET ECN CE bit. */ -static void -sctp_do_ecn_ce_work(sctp_association_t *asoc, uint32_t lowest_tsn) +static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) { - /* + /* * Save the TSN away for comparison when we receive CWR - * Note: dp->TSN is expected in host endian + * Note: dp->TSN is expected in host endian */ asoc->last_ecne_tsn = lowest_tsn; asoc->need_ecne = 1; - -} /* void sctp_do_ecn_ce_work(asoc, command) */ - +} /* Helper function for delayed processing of SCTP ECNE chunk. */ /* RFC 2960 Appendix A * - * RFC 2481 details a specific bit for a sender to send in - * the header of its next outbound TCP segment to indicate to - * its peer that it has reduced its congestion window. This - * is termed the CWR bit. For SCTP the same indication is made - * by including the CWR chunk. This chunk contains one data - * element, i.e. the TSN number that was sent in the ECNE chunk. - * This element represents the lowest TSN number in the datagram + * RFC 2481 details a specific bit for a sender to send in + * the header of its next outbound TCP segment to indicate to + * its peer that it has reduced its congestion window. This + * is termed the CWR bit. For SCTP the same indication is made + * by including the CWR chunk. This chunk contains one data + * element, i.e. the TSN number that was sent in the ECNE chunk. + * This element represents the lowest TSN number in the datagram * that was originally marked with the CE bit. */ -static sctp_chunk_t * -sctp_do_ecn_ecne_work(sctp_association_t *asoc, - uint32_t lowest_tsn, - sctp_chunk_t *chunk) +static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, + __u32 lowest_tsn, + sctp_chunk_t *chunk) { - sctp_chunk_t *repl; sctp_transport_t *transport; - /* Our previously transmitted packet ran into some congestion * so we should take action by reducing cwnd and ssthresh - * and then ACK our peer that we we've done so by + * and then ACK our peer that we we've done so by * sending a CWR. */ - - - /* Find which transport's congestion variables + + /* Find which transport's congestion variables * need to be adjusted. */ - + transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn); /* Update the congestion variables. */ - - if (transport) { + if (transport) sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE); - } - + /* Save away a rough idea of when we last sent out a CWR. - * We compare against this value (see above) to decide if - * this is a fairly new request. - * Note that this is not a perfect solution. We may + * We compare against this value (see above) to decide if + * this is a fairly new request. + * Note that this is not a perfect solution. We may * have moved beyond the window (several times) by the * next time we get an ECNE. However, it is cute. This idea * came from Randy's reference code. @@ -668,7 +635,7 @@ sctp_do_ecn_ecne_work(sctp_association_t *asoc, * what we do. * * RFC 2960 Appendix A - * + * * CWR: * * RFC 2481 details a specific bit for a sender to send in @@ -679,108 +646,97 @@ sctp_do_ecn_ecne_work(sctp_association_t *asoc, * chunk contains one data element, i.e. the TSN number * that was sent in the ECNE chunk. This element * represents the lowest TSN number in the datagram that - * was originally marked with the CE bit. + * was originally marked with the CE bit. */ asoc->last_cwr_tsn = asoc->next_tsn - 1; - repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); + repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); /* If we run out of memory, it will look like a lost CWR. We'll * get back in sync eventually. */ - return repl; +} -} /* sctp_chunk_t *sctp_do_ecn_ecne_work(asoc, command) */ - -/* Helper function to do delayed processing of ECN CWR chunk */ -static void -sctp_do_ecn_cwr_work(sctp_association_t *asoc, - uint32_t lowest_tsn) +/* Helper function to do delayed processing of ECN CWR chunk. */ +static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, + __u32 lowest_tsn) { - /* Turn off ECNE getting auto-prepended to every outgoing * packet */ - asoc->need_ecne = 0; +} -} /* void sctp_do_ecn_cwr_work(asoc, command) */ - -/* This macro is to compress the text a bit... */ +/* This macro is to compress the text a bit... */ #define AP(v) asoc->peer.v /* Generate SACK if necessary. We call this at the end of a packet. */ -int -sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands) +int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands) { - uint32_t ctsn, max_tsn_seen; + __u32 ctsn, max_tsn_seen; sctp_chunk_t *sack; int error = 0; - if (force) { - asoc->peer.sack_needed = 1; - } + if (force) + asoc->peer.sack_needed = 1; ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map); - /* From 12.2 Parameters necessary per association (i.e. the TCB): - * - * Ack State : This flag indicates if the next received packet - * : is to be responded to with a SACK. ... - * : When DATA chunks are out of order, SACK's - * : are not delayed (see Section 6). - * - * [This is actually not mentioned in Section 6, but we - * implement it here anyway. --piggy] - */ - if (max_tsn_seen != ctsn) { - asoc->peer.sack_needed = 1; - } - - /* From 6.2 Acknowledgement on Reception of DATA Chunks: - * - * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, - * an acknowledgement SHOULD be generated for at least every - * second packet (not every second DATA chunk) received, and - * SHOULD be generated within 200 ms of the arrival of any - * unacknowledged DATA chunk. ... - */ - if (!asoc->peer.sack_needed) { + /* From 12.2 Parameters necessary per association (i.e. the TCB): + * + * Ack State : This flag indicates if the next received packet + * : is to be responded to with a SACK. ... + * : When DATA chunks are out of order, SACK's + * : are not delayed (see Section 6). + * + * [This is actually not mentioned in Section 6, but we + * implement it here anyway. --piggy] + */ + if (max_tsn_seen != ctsn) + asoc->peer.sack_needed = 1; + + /* From 6.2 Acknowledgement on Reception of DATA Chunks: + * + * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, + * an acknowledgement SHOULD be generated for at least every + * second packet (not every second DATA chunk) received, and + * SHOULD be generated within 200 ms of the arrival of any + * unacknowledged DATA chunk. ... + */ + if (!asoc->peer.sack_needed) { /* We will need a SACK for the next packet. */ - asoc->peer.sack_needed = 1; + asoc->peer.sack_needed = 1; goto out; - } else { + } else { sack = sctp_make_sack(asoc); - if (NULL == sack) { goto nomem; } + if (!sack) + goto nomem; - asoc->peer.sack_needed = 0; + asoc->peer.sack_needed = 0; asoc->peer.next_dup_tsn = 0; - error = sctp_push_outqueue(&asoc->outqueue, sack); - - /* Stop the SACK timer. */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, - SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + error = sctp_push_outqueue(&asoc->outqueue, sack); - } /* else (we needed a sack) */ + /* Stop the SACK timer. */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); + } - out: +out: return error; - nomem: + +nomem: error = -ENOMEM; return error; - -} /* sctp_gen_sack() */ +} /* Handle a duplicate TSN. */ -void -sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, - long gap) +void sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, long gap) { #if 0 - sctp_chunk_t *sack; + sctp_chunk_t *sack; /* Caution: gap < 2 * SCTP_TSN_MAP_SIZE * so gap can be negative. @@ -788,27 +744,27 @@ sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, * --xguo */ - /* Count this TSN. */ - if (gap < SCTP_TSN_MAP_SIZE) { - asoc->peer.tsn_map[gap]++; - } else { - asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++; - } - - /* From 6.2 Acknowledgement on Reception of DATA Chunks - * - * When a packet arrives with duplicate DATA chunk(s) - * and with no new DATA chunk(s), the endpoint MUST - * immediately send a SACK with no delay. If a packet - * arrives with duplicate DATA chunk(s) bundled with - * new DATA chunks, the endpoint MAY immediately send a - * SACK. Normally receipt of duplicate DATA chunks - * will occur when the original SACK chunk was lost and - * the peer's RTO has expired. The duplicate TSN - * number(s) SHOULD be reported in the SACK as - * duplicate. - */ - asoc->counters[SctpCounterAckState] = 2; + /* Count this TSN. */ + if (gap < SCTP_TSN_MAP_SIZE) { + asoc->peer.tsn_map[gap]++; + } else { + asoc->peer.tsn_map_overflow[gap - SCTP_TSN_MAP_SIZE]++; + } + + /* From 6.2 Acknowledgement on Reception of DATA Chunks + * + * When a packet arrives with duplicate DATA chunk(s) + * and with no new DATA chunk(s), the endpoint MUST + * immediately send a SACK with no delay. If a packet + * arrives with duplicate DATA chunk(s) bundled with + * new DATA chunks, the endpoint MAY immediately send a + * SACK. Normally receipt of duplicate DATA chunks + * will occur when the original SACK chunk was lost and + * the peer's RTO has expired. The duplicate TSN + * number(s) SHOULD be reported in the SACK as + * duplicate. + */ + asoc->counters[SctpCounterAckState] = 2; #endif /* 0 */ } /* sctp_do_TSNdup() */ @@ -817,194 +773,160 @@ sctp_do_TSNdup(sctp_association_t *asoc, sctp_chunk_t *chunk, /* When the T3-RTX timer expires, it calls this function to create the * relevant state machine event. */ -void -sctp_generate_t3_rtx_event(unsigned long peer) +void sctp_generate_t3_rtx_event(unsigned long peer) { - int error; - sctp_transport_t *transport = (sctp_transport_t *)peer; + int error; + sctp_transport_t *transport = (sctp_transport_t *) peer; sctp_association_t *asoc = transport->asoc; - /* Check whether a task is in the sock. */ + /* Check whether a task is in the sock. */ sctp_bh_lock_sock(asoc->base.sk); - if (__sctp_sock_busy(asoc->base.sk)) { SCTP_DEBUG_PRINTK(__FUNCTION__ ":Sock is busy.\n"); - /* Try again later. */ - if (!mod_timer(&transport->T3_rtx_timer, - jiffies + (HZ/20))) { + /* Try again later. */ + if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20))) sctp_transport_hold(transport); - } goto out_unlock; } /* Is this transport really dead and just waiting around for * the timer to let go of the reference? - */ - if (transport->dead) { + */ + if (transport->dead) goto out_unlock; - } - /* Run through the state machine. */ - error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX), - asoc->state, - asoc->ep, asoc, - transport, GFP_ATOMIC); + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); - if (error) { - asoc->base.sk->err = -error; - } + if (error) + asoc->base.sk->err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); sctp_transport_put(transport); - -} /* sctp_generate_t3_rtx_event() */ - +} /* This is a sa interface for producing timeout events. It works * for timeouts which use the association as their parameter. */ -static void -sctp_generate_timeout_event(sctp_association_t *asoc, - sctp_event_timeout_t timeout_type) +static void sctp_generate_timeout_event(sctp_association_t *asoc, + sctp_event_timeout_t timeout_type) { - int error = 0; - - sctp_bh_lock_sock(asoc->base.sk); + int error = 0; + sctp_bh_lock_sock(asoc->base.sk); if (__sctp_sock_busy(asoc->base.sk)) { SCTP_DEBUG_PRINTK(__FUNCTION__ "Sock is busy: timer %d\n", timeout_type); - /* Try again later. */ - if (!mod_timer(&asoc->timers[timeout_type], - jiffies + (HZ/20))) { + + /* Try again later. */ + if (!mod_timer(&asoc->timers[timeout_type], jiffies + (HZ/20))) sctp_association_hold(asoc); - } goto out_unlock; - } + } /* Is this association really dead and just waiting around for * the timer to let go of the reference? */ - if (asoc->base.dead) { + if (asoc->base.dead) goto out_unlock; - } - /* Run through the state machine. */ + /* Run through the state machine. */ error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(timeout_type), - asoc->state, asoc->ep, asoc, + asoc->state, asoc->ep, asoc, (void *)timeout_type, GFP_ATOMIC); - if (error) { asoc->base.sk->err = -error; } - + if (error) + asoc->base.sk->err = -error; + out_unlock: sctp_bh_unlock_sock(asoc->base.sk); sctp_association_put(asoc); +} -} /* sctp_generate_timeout_event() */ - -void -sctp_generate_t1_cookie_event(unsigned long data) +void sctp_generate_t1_cookie_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - + sctp_association_t *asoc = (sctp_association_t *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); +} -} /* sctp_generate_t1_cookie_event() */ - -void -sctp_generate_t1_init_event(unsigned long data) +void sctp_generate_t1_init_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - - sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); +} -} /* sctp_generate_t1_init_event() */ - -void -sctp_generate_t2_shutdown_event(unsigned long data) +void sctp_generate_t2_shutdown_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); - -} /* sctp_generate_t2_shutdown_event() */ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); +} -void -sctp_generate_autoclose_event(unsigned long data) +void sctp_generate_autoclose_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); +} -} /* sctp_generate_autoclose_event() */ - -/* Generate a heart beat event. If the sock is busy, reschedule. Make - * sure that the transport is still valid. +/* Generate a heart beat event. If the sock is busy, reschedule. Make + * sure that the transport is still valid. */ -void -sctp_generate_heartbeat_event(unsigned long data) +void sctp_generate_heartbeat_event(unsigned long data) { - int error = 0; - sctp_transport_t *transport = (sctp_transport_t *)data; + int error = 0; + sctp_transport_t *transport = (sctp_transport_t *) data; sctp_association_t *asoc = transport->asoc; sctp_bh_lock_sock(asoc->base.sk); if (__sctp_sock_busy(asoc->base.sk)) { SCTP_DEBUG_PRINTK(__FUNCTION__ ":Sock is busy.\n"); - /* Try again later. */ - if (!mod_timer(&transport->hb_timer, - jiffies + (HZ/20))) { + /* Try again later. */ + if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20))) sctp_transport_hold(transport); - } goto out_unlock; } - /* Is this structure just waiting around for us to actually + /* Is this structure just waiting around for us to actually * get destroyed? */ - if (transport->dead) { + if (transport->dead) goto out_unlock; - } - - error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, - SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), - asoc->state, - asoc->ep, asoc, - transport, GFP_ATOMIC); - if (error) { - - asoc->base.sk->err = -error; - } + error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, + SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), + asoc->state, + asoc->ep, asoc, + transport, GFP_ATOMIC); + if (error) + asoc->base.sk->err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); sctp_transport_put(transport); +} -} /* sctp_generate_heartbeat_event() */ - -/* Inject a SACK Timeout event into the state machine. */ -void -sctp_generate_sack_event(unsigned long data) +/* Inject a SACK Timeout event into the state machine. */ +void sctp_generate_sack_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); +} -} /* sctp_generate_sack_event() */ - -void -sctp_generate_pmtu_raise_event(unsigned long data) +void sctp_generate_pmtu_raise_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; - sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_PMTU_RAISE); -} /* sctp_generate_pmtu_raise_event() */ + sctp_association_t *asoc = (sctp_association_t *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_PMTU_RAISE); +} sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { NULL, @@ -1023,13 +945,12 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { * 3rd Level Abstractions ********************************************************************/ - /* RFC 2960 8.2 Path Failure Detection * * When its peer endpoint is multi-homed, an endpoint should keep a * error counter for each of the destination transport addresses of the * peer endpoint. - * + * * Each time the T3-rtx timer expires on any address, or when a * HEARTBEAT sent to an idle address is not acknowledged within a RTO, * the error counter of that destination address will be incremented. @@ -1037,41 +958,37 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { * 'Path.Max.Retrans' of that destination address, the endpoint should * mark the destination transport address as inactive, and a * notification SHOULD be sent to the upper layer. - * - * + * */ - -static void -sctp_do_8_2_transport_strike(sctp_association_t *asoc, - sctp_transport_t *transport) +static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, + sctp_transport_t *transport) { /* The check for association's overall error counter exceeding the * threshold is done in the state function. */ asoc->overall_error_count++; - if ( transport->state.active - && (transport->error_count++ >= transport->error_threshold) ) { + if (transport->state.active && + (transport->error_count++ >= transport->error_threshold)) { SCTP_DEBUG_PRINTK("transport_strike: transport " "IP:%d.%d.%d.%d failed.\n", NIPQUAD(transport->ipaddr.v4.sin_addr)); - sctp_assoc_control_transport(asoc, transport, - SCTP_TRANSPORT_DOWN, + sctp_assoc_control_transport(asoc, transport, + SCTP_TRANSPORT_DOWN, SCTP_FAILED_THRESHOLD); } - /* E2) For the destination address for which the timer - * expires, set RTO <- RTO * 2 ("back off the timer"). The - * maximum value discussed in rule C7 above (RTO.max) may be - * used to provide an upper bound to this doubling operation. - */ + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ transport->rto = min((transport->rto * 2), transport->asoc->rto_max); +} -} /* sctp_do_8_2_transport_strike() */ - -/* Worker routine to handle INIT command failure. */ -static void -sctp_cmd_init_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) +/* Worker routine to handle INIT command failure. */ +static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, + sctp_association_t *asoc) { sctp_ulpevent_t *event; @@ -1080,11 +997,10 @@ sctp_cmd_init_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) SCTP_CANT_STR_ASSOC, 0, 0, 0, GFP_ATOMIC); - - if (event) { + + if (event) sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event)); - } /* FIXME: We need to handle data possibly either * sent via COOKIE-ECHO bundling or just waiting in @@ -1092,15 +1008,11 @@ sctp_cmd_init_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) * SEND_FAILED notifications. */ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - - return; - -} /* sctp_cmd_init_failed() */ +} - -/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */ -static void -sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) +/* Worker routine to handle SCTP_CMD_ASSOC_FAILED. */ +static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, + sctp_association_t *asoc) { sctp_ulpevent_t *event; @@ -1109,44 +1021,39 @@ sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, sctp_association_t *asoc) SCTP_COMM_LOST, 0, 0, 0, GFP_ATOMIC); - - if (event) { + + if (event) sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(event)); - } /* FIXME: We need to handle data that could not be sent or was not * acked, if the user has enabled SEND_FAILED notifications. */ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - - return; - -} /* sctp_cmd_assoc_failed() */ +} /* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT - * inside the cookie. + * inside the cookie. */ -static void -sctp_cmd_process_init(sctp_cmd_seq_t *commands, sctp_association_t *asoc, - sctp_chunk_t *chunk, sctp_init_chunk_t *peer_init, - int priority) +static void sctp_cmd_process_init(sctp_cmd_seq_t *commands, + sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_init_chunk_t *peer_init, + int priority) { - /* The command sequence holds commands assuming that the + /* The command sequence holds commands assuming that the * processing will happen successfully. If this is not the * case, rewind the sequence and add appropriate error handling - * to the sequence. + * to the sequence. */ sctp_process_init(asoc, chunk->chunk_hdr->type, sctp_source(chunk), peer_init, priority); - - -} /* sctp_cmd_process_init() */ +} /* Helper function to break out starting up of heartbeat timers. */ -static void -sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, sctp_association_t *asoc) +static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, + sctp_association_t *asoc) { sctp_transport_t *t; list_t *pos; @@ -1157,18 +1064,16 @@ sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, sctp_association_t *asoc) */ list_for_each(pos, &asoc->peer.transport_addr_list) { t = list_entry(pos, sctp_transport_t, transports); - if (!mod_timer(&t->hb_timer, + if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) { sctp_transport_hold(t); } - } /* for (all transports) */ - -} /* sctp_cmd_hb_timers_start() */ - -/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ -void -sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_bind_addr_t *bp) + } +} + +/* Helper function to break out SCTP_CMD_SET_BIND_ADDR handling. */ +void sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_bind_addr_t *bp) { list_t *pos, *temp; @@ -1178,72 +1083,65 @@ sctp_cmd_set_bind_addrs(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, } /* Free the temporary bind addr header, otherwise - * there will a memory leak. + * there will a memory leak. */ sctp_bind_addr_free(bp); - -} /* sctp_cmd_set_bind_addrs() */ +} -/* Helper function to handle the reception of an HEARTBEAT ACK. */ -static void -sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_transport_t *t, sctp_chunk_t *chunk) +/* Helper function to handle the reception of an HEARTBEAT ACK. */ +static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_transport_t *t, sctp_chunk_t *chunk) { - sctp_sender_hb_info_t *hbinfo; + sctp_sender_hb_info_t *hbinfo; - /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the - * HEARTBEAT should clear the error counter of the destination - * transport address to which the HEARTBEAT was sent. + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the + * HEARTBEAT should clear the error counter of the destination + * transport address to which the HEARTBEAT was sent. * The association's overall error count is also cleared. */ t->error_count = 0; - t->asoc->overall_error_count = 0; + t->asoc->overall_error_count = 0; - /* Mark the destination transport address as active if it is not so - * marked. + /* Mark the destination transport address as active if it is not so + * marked. */ - if (!t->state.active) { + if (!t->state.active) sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, SCTP_HEARTBEAT_SUCCESS); - } - + /* The receiver of the HEARTBEAT ACK should also perform an * RTT measurement for that destination transport address * using the time value carried in the HEARTBEAT ACK chunk. */ - hbinfo = (sctp_sender_hb_info_t *)chunk->skb->data; + hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at)); +} -} /* sctp_cmd_transport_on() */ - -/* Helper function to do a transport reset at the expiry of the hearbeat - * timer. - */ -static void -sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_transport_t *t) +/* Helper function to do a transport reset at the expiry of the hearbeat + * timer. + */ +static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, + sctp_association_t *asoc, + sctp_transport_t *t) { sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); /* Mark one strike against a transport. */ sctp_do_8_2_transport_strike(asoc, t); - /* Update the heartbeat timer. */ - if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) { + /* Update the heartbeat timer. */ + if (!mod_timer(&t->hb_timer, t->hb_interval + t->rto + jiffies)) sctp_transport_hold(t); - } +} -} /* sctp_cmd_transport_reset() */ - -/* Helper function to process the process SACK command. */ -static int -sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_sackhdr_t *sackh) +/* Helper function to process the process SACK command. */ +static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_sackhdr_t *sackh) { int err; if (sctp_sack_outqueue(&asoc->outqueue, sackh)) { - /* There are no more TSNs awaiting SACK. */ + /* There are no more TSNs awaiting SACK. */ err = sctp_do_sm(SCTP_EVENT_T_OTHER, SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), asoc->state, asoc->ep, asoc, NULL, @@ -1256,16 +1154,13 @@ sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, } return err; - -} /* sctp_cmd_process_sack() */ - +} /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set - * the transport for a shutdown chunk. + * the transport for a shutdown chunk. */ -static void -sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_chunk_t *chunk) +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, + sctp_chunk_t *chunk) { sctp_transport_t *t; @@ -1273,8 +1168,4 @@ sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, asoc->shutdown_last_sent_to = t; asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto; chunk->transport = t; - - return; - -} /* sctp_cmd_setup_t2() */ - +} diff --git a/net/sctp/sctp_sm_statefuns.c b/net/sctp/sctp_sm_statefuns.c index 49162bd91b65..3542119f998c 100644 --- a/net/sctp/sctp_sm_statefuns.c +++ b/net/sctp/sctp_sm_statefuns.c @@ -51,7 +51,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.49 2002/08/21 18:34:04 jgrimm Exp $"; -#include #include #include #include @@ -59,23 +58,19 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.49 #include #include #include -#ifndef CONFIG_INET_ECN -#define CONFIG_INET_ECN -#endif /* CONFIG_INET_ECN */ #include #include #include #include #include - /********************************************************** * These are the state functions for handling chunk events. **********************************************************/ /* * Process the final SHUTDOWN COMPLETE. - * + * * Section: 4 (C) (diagram), 9.2 * Upon reception of the SHUTDOWN COMPLETE chunk the endpoint will verify * that it is in SHUTDOWN-ACK-SENT state, if it is not the chunk should be @@ -88,27 +83,26 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statefuns.c,v 1.49 * ... * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the * Verification Tag field of the packet matches its own tag OR it is - * set to its peer's tag and the T bit is set in the Chunk Flags. - * Otherwise, the receiver MUST silently discard the packet and take - * no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if - * it is not in the SHUTDOWN-ACK-SENT state. + * set to its peer's tag and the T bit is set in the Chunk Flags. + * Otherwise, the receiver MUST silently discard the packet and take + * no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if + * it is not in the SHUTDOWN-ACK-SENT state. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_4_C(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; +sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; sctp_ulpevent_t *ev; /* RFC 2960 6.10 Bundling @@ -116,49 +110,46 @@ sctp_sf_do_4_C(const sctp_endpoint_t *ep, * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ - if (!chunk->singleton) { + if (!chunk->singleton) return SCTP_DISPOSITION_VIOLATION; - } - /* RFC 2960 8.5.1 Exceptions in Verification Tag Rules - * + /* RFC 2960 8.5.1 Exceptions in Verification Tag Rules + * * (C) The receiver of a SHUTDOWN COMPLETE shall accept the * packet if the Verification Tag field of the packet * matches its own tag OR it is set to its peer's tag and - * the T bit is set in the Chunk Flags. Otherwise, the - * receiver MUST silently discard the packet and take no + * the T bit is set in the Chunk Flags. Otherwise, the + * receiver MUST silently discard the packet and take no * further action.... */ - if ((ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) - && !(sctp_test_T_bit(chunk) - || (ntohl(chunk->sctp_hdr->vtag) - != asoc->peer.i.init_tag))) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } + if ((ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) && + !(sctp_test_T_bit(chunk) || + (ntohl(chunk->sctp_hdr->vtag) != asoc->peer.i.init_tag))) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - /* RFC 2960 10.2 SCTP-to-ULP + /* RFC 2960 10.2 SCTP-to-ULP * * H) SHUTDOWN COMPLETE notification - * - * When SCTP completes the shutdown procedures (section 9.2) this - * notification is passed to the upper layer. - */ + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, - 0, 0, 0, GFP_ATOMIC); - if (!ev) { goto nomem; } - - sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + 0, 0, 0, GFP_ATOMIC); + if (!ev) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); - /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint - * will verify that it is in SHUTDOWN-ACK-SENT state, if it is - * not the chunk should be discarded. If the endpoint is in - * the SHUTDOWN-ACK-SENT state the endpoint should stop the - * T2-shutdown timer and remove all knowledge of the - * association (and thus the association enters the CLOSED - * state). - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint + * will verify that it is in SHUTDOWN-ACK-SENT state, if it is + * not the chunk should be discarded. If the endpoint is in + * the SHUTDOWN-ACK-SENT state the endpoint should stop the + * T2-shutdown timer and remove all knowledge of the + * association (and thus the association enters the CLOSED + * state). + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -168,121 +159,110 @@ sctp_sf_do_4_C(const sctp_endpoint_t *ep, return SCTP_DISPOSITION_DELETE_TCB; - nomem: +nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_4_C() */ - +} /* * Discard the whole packet. - * + * * Section: 8.4 2) * - * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST - * silently discard the OOTB packet and take no further action. + * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST + * silently discard the OOTB packet and take no further action. * Otherwise, * * Verification Tag: No verification necessary * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_pdiscard(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_pdiscard() */ - +} /* * Respond to a normal INIT chunk. * We are the side that is being asked for an association. - * + * * Section: 5.1 Normal Establishment of an Association, B * B) "Z" shall respond immediately with an INIT ACK chunk. The - * destination IP address of the INIT ACK MUST be set to the source - * IP address of the INIT to which this INIT ACK is responding. In + * destination IP address of the INIT ACK MUST be set to the source + * IP address of the INIT to which this INIT ACK is responding. In * the response, besides filling in other parameters, "Z" must set the - * Verification Tag field to Tag_A, and also provide its own - * Verification Tag (Tag_Z) in the Initiate Tag field. + * Verification Tag field to Tag_A, and also provide its own + * Verification Tag (Tag_Z) in the Initiate Tag field. * * Verification Tag: No checking. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + sctp_chunk_t *chunk = arg; sctp_chunk_t *repl; sctp_association_t *new_asoc; - /* If the packet is an OOTB packet which is temporarily on the + /* If the packet is an OOTB packet which is temporarily on the * control endpoint, responding with an ABORT. */ - - if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { - return sctp_sf_ootb(ep, asoc, type, arg, commands); - } + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) + return sctp_sf_ootb(ep, asoc, type, arg, commands); /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ - if (!chunk->singleton) { + if (!chunk->singleton) return SCTP_DISPOSITION_VIOLATION; - } /* Grab the INIT header. */ - chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; - /* Tag the variable length parameters. */ + /* Tag the variable length parameters. */ chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); - if (NULL == new_asoc) { goto nomem; } + if (!new_asoc) + goto nomem; - /* FIXME: sctp_process_init can fail, but there is no - * status nor handling. + /* FIXME: sctp_process_init can fail, but there is no + * status nor handling. */ sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); - /* B) "Z" shall respond immediately with an INIT ACK chunk. - */ - + /* B) "Z" shall respond immediately with an INIT ACK chunk. */ repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); - if (!repl) { goto nomem_ack; } - + if (!repl) + goto nomem_ack; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); /* @@ -291,8 +271,7 @@ sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, * new association. Otherwise, "Z" will be vulnerable to resource * attacks. */ - - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; @@ -300,222 +279,209 @@ nomem_ack: sctp_association_free(new_asoc); nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_5_1B_init() */ +} /* * Respond to a normal INIT ACK chunk. * We are the side that is initiating the association. - * + * * Section: 5.1 Normal Establishment of an Association, C * C) Upon reception of the INIT ACK from "Z", "A" shall stop the T1-init - * timer and leave COOKIE-WAIT state. "A" shall then send the State - * Cookie received in the INIT ACK chunk in a COOKIE ECHO chunk, start + * timer and leave COOKIE-WAIT state. "A" shall then send the State + * Cookie received in the INIT ACK chunk in a COOKIE ECHO chunk, start * the T1-cookie timer, and enter the COOKIE-ECHOED state. - * + * * Note: The COOKIE ECHO chunk can be bundled with any pending outbound * DATA chunks, but it MUST be the first chunk in the packet and * until the COOKIE ACK is returned the sender MUST NOT send any * other packets to the peer. - * + * * Verification Tag: 3.3.3 - * If the value of the Initiate Tag in a received INIT ACK chunk is + * If the value of the Initiate Tag in a received INIT ACK chunk is * found to be 0, the receiver MUST treat it as an error and close the * association by transmitting an ABORT. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + sctp_chunk_t *chunk = arg; sctp_init_chunk_t *initchunk; - uint32_t init_tag; + __u32 init_tag; /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ - if (!chunk->singleton) { + if (!chunk->singleton) return SCTP_DISPOSITION_VIOLATION; - } - /* Grab the INIT header. - */ - chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; - init_tag = ntohl(chunk->subh.init_hdr->init_tag); + init_tag = ntohl(chunk->subh.init_hdr->init_tag); - /* Verification Tag: 3.3.3 - * If the value of the Initiate Tag in a received INIT ACK - * chunk is found to be 0, the receiver MUST treat it as an - * error and close the association by transmitting an ABORT. - */ - if (0 == init_tag) { - sctp_chunk_t *reply; - reply = sctp_make_abort(asoc, chunk, 0); - if (!reply) { goto nomem; } + /* Verification Tag: 3.3.3 + * If the value of the Initiate Tag in a received INIT ACK + * chunk is found to be 0, the receiver MUST treat it as an + * error and close the association by transmitting an ABORT. + */ + if (!init_tag) { + sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); + if (!reply) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - return SCTP_DISPOSITION_DELETE_TCB; - } + return SCTP_DISPOSITION_DELETE_TCB; + } - /* Tag the variable length paramters. Note that we never + /* Tag the variable length paramters. Note that we never * convert the parameters in an INIT chunk. */ chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); - initchunk = (sctp_init_chunk_t *)chunk->chunk_hdr; + initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr; - sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, + sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, SCTP_PEER_INIT(initchunk)); - - /* 5.1 C) "A" shall stop the T1-init timer and leave - * COOKIE-WAIT state. "A" shall then ... start the T1-cookie - * timer, and enter the COOKIE-ECHOED state. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + /* 5.1 C) "A" shall stop the T1-init timer and leave + * COOKIE-WAIT state. "A" shall then ... start the T1-cookie + * timer, and enter the COOKIE-ECHOED state. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); sctp_add_cmd_sf(commands, SCTP_CMD_COUNTER_RESET, SCTP_COUNTER(SCTP_COUNTER_INIT_ERROR)); - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); - - /* 5.1 C) "A" shall then send the State Cookie received in the - * INIT ACK chunk in a COOKIE ECHO chunk, ... - */ - sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, SCTP_NULL()); + /* 5.1 C) "A" shall then send the State Cookie received in the + * INIT ACK chunk in a COOKIE ECHO chunk, ... + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, SCTP_NULL()); return SCTP_DISPOSITION_CONSUME; - nomem: - return SCTP_DISPOSITION_NOMEM; -} /* sctp_sf_do_5_1C_ack() */ +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* * Respond to a normal COOKIE ECHO chunk. * We are the side that is being asked for an association. - * + * * Section: 5.1 Normal Establishment of an Association, D - * D) Upon reception of the COOKIE ECHO chunk, Endpoint "Z" will reply + * D) Upon reception of the COOKIE ECHO chunk, Endpoint "Z" will reply * with a COOKIE ACK chunk after building a TCB and moving to * the ESTABLISHED state. A COOKIE ACK chunk may be bundled with * any pending DATA chunks (and/or SACK chunks), but the COOKIE ACK * chunk MUST be the first chunk in the packet. - * + * * IMPLEMENTATION NOTE: An implementation may choose to send the * Communication Up notification to the SCTP user upon reception * of a valid COOKIE ECHO chunk. - * + * * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules * D) Rules for packet carrying a COOKIE ECHO - * + * * - When sending a COOKIE ECHO, the endpoint MUST use the value of the * Initial Tag received in the INIT ACK. - * + * * - The receiver of a COOKIE ECHO follows the procedures in Section 5. - * + * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, const sctp_association_t *asoc, - const sctp_subtype_t type, void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + sctp_chunk_t *chunk = arg; sctp_association_t *new_asoc; sctp_init_chunk_t *peer_init; sctp_chunk_t *repl; sctp_ulpevent_t *ev; int error = 0; - /* If the packet is an OOTB packet which is temporarily on the + /* If the packet is an OOTB packet which is temporarily on the * control endpoint, responding with an ABORT. */ - - if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) { + if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) return sctp_sf_ootb(ep, asoc, type, arg, commands); - } - /* "Decode" the chunk. We have no optional parameters so we - * are in good shape. - */ + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data; - skb_pull(chunk->skb, + skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint - * "Z" will reply with a COOKIE ACK chunk after building a TCB - * and moving to the ESTABLISHED state. - */ + /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint + * "Z" will reply with a COOKIE ACK chunk after building a TCB + * and moving to the ESTABLISHED state. + */ new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); - - /* FIXME: + + /* FIXME: * If the re-build failed, what is the proper error path * from here? * * [We should abort the association. --piggy] */ - - if (!new_asoc) { + if (!new_asoc) { /* FIXME: Several errors are possible. A bad cookie should * be silently discarded, but think about logging it too. */ switch (error) { case -SCTP_IERROR_NOMEM: goto nomem; + case -SCTP_IERROR_BAD_SIG: default: - return sctp_sf_pdiscard(ep, asoc, type, + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } - - } + }; + } sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); - - sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); - - if (new_asoc->autoclose) { - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + + if (new_asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - } sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - /* Re-build the bind address for the association is done in - * the sctp_unpack_cookie() already. + /* Re-build the bind address for the association is done in + * the sctp_unpack_cookie() already. */ - /* This is a brand-new association, so these are not yet side * effects--it is safe to run them here. */ @@ -524,233 +490,225 @@ sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, const sctp_association_t *asoc, &chunk->subh.cookie_hdr->c.peer_addr, peer_init, GFP_ATOMIC); - repl = sctp_make_cookie_ack(new_asoc, chunk); - if (!repl) { goto nomem_repl; } + repl = sctp_make_cookie_ack(new_asoc, chunk); + if (!repl) + goto nomem_repl; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - /* RFC 2960 5.1 Normal Establishment of an Association + /* RFC 2960 5.1 Normal Establishment of an Association * * D) IMPLEMENTATION NOTE: An implementation may choose to - * send the Communication Up notification to the SCTP user - * upon reception of a valid COOKIE ECHO chunk. + * send the Communication Up notification to the SCTP user + * upon reception of a valid COOKIE ECHO chunk. */ - ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0, new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_max_instreams, GFP_ATOMIC); - if (!ev) { goto nomem_ev; } - + if (!ev) + goto nomem_ev; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); return SCTP_DISPOSITION_CONSUME; nomem_ev: sctp_free_chunk(repl); + nomem_repl: sctp_association_free(new_asoc); + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_5_1D_ce() */ - +} /* * Respond to a normal COOKIE ACK chunk. * We are the side that is being asked for an association. - * + * * RFC 2960 5.1 Normal Establishment of an Association - * - * E) Upon reception of the COOKIE ACK, endpoint "A" will move from the + * + * E) Upon reception of the COOKIE ACK, endpoint "A" will move from the * COOKIE-ECHOED state to the ESTABLISHED state, stopping the T1-cookie * timer. It may also notify its ULP about the successful - * establishment of the association with a Communication Up - * notification (see Section 10). - * + * establishment of the association with a Communication Up + * notification (see Section 10). + * * Verification Tag: * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, const sctp_association_t *asoc, - const sctp_subtype_t type, void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) { sctp_ulpevent_t *ev; - + /* RFC 2960 5.1 Normal Establishment of an Association - * + * * E) Upon reception of the COOKIE ACK, endpoint "A" will move - * from the COOKIE-ECHOED state to the ESTABLISHED state, - * stopping the T1-cookie timer. + * from the COOKIE-ECHOED state to the ESTABLISHED state, + * stopping the T1-cookie timer. */ - - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); - - sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); - - if (asoc->autoclose) { - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - } - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - /* It may also notify its ULP about the successful - * establishment of the association with a Communication Up - * notification (see Section 10). - */ + /* It may also notify its ULP about the successful + * establishment of the association with a Communication Up + * notification (see Section 10). + */ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, asoc->c.sinit_num_ostreams, asoc->c.sinit_max_instreams, GFP_ATOMIC); - if (!ev) { goto nomem; } - + if (!ev) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); return SCTP_DISPOSITION_CONSUME; - nomem: - return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_5_1E_ca() */ +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* Generate a HEARTBEAT packet on the given transport. */ -sctp_disposition_t -sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_transport_t *transport = (sctp_transport_t *) arg; + sctp_transport_t *transport = (sctp_transport_t *) arg; sctp_chunk_t *reply; - sctp_sender_hb_info_t hbinfo; - size_t paylen = 0; + sctp_sender_hb_info_t hbinfo; + size_t paylen = 0; if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - } + } - /* Section 3.3.5. + /* Section 3.3.5. * The Sender-specific Heartbeat Info field should normally include * information about the sender's current time when this HEARTBEAT * chunk is sent and the destination transport address to which this * HEARTBEAT is sent (see Section 8.3). */ - hbinfo.param_hdr.type = SCTP_PARAM_HEATBEAT_INFO; - hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); - hbinfo.daddr = transport->ipaddr; - hbinfo.sent_at = jiffies; + hbinfo.param_hdr.type = SCTP_PARAM_HEATBEAT_INFO; + hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); + hbinfo.daddr = transport->ipaddr; + hbinfo.sent_at = jiffies; /* Set rto_pending indicating that an RTT measurement is started * with this heartbeat chunk. - */ + */ transport->rto_pending = 1; - /* Send a heartbeat to our peer. */ - - paylen = sizeof ( sctp_sender_hb_info_t ); + /* Send a heartbeat to our peer. */ + paylen = sizeof(sctp_sender_hb_info_t); reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen); - if (NULL == reply) { goto nomem; } + if (!reply) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, - SCTP_CHUNK(reply)); - - /* Set transport error counter and association error counter - * when sending heartbeat. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, + SCTP_CHUNK(reply)); + + /* Set transport error counter and association error counter + * when sending heartbeat. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET, SCTP_TRANSPORT(transport)); return SCTP_DISPOSITION_CONSUME; -nomem: - return SCTP_DISPOSITION_NOMEM; -} /* sctp_sf_sendbeat_8_3() */ +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* * Process an heartbeat request. - * + * * Section: 8.3 Path Heartbeat * The receiver of the HEARTBEAT should immediately respond with a - * HEARTBEAT ACK that contains the Heartbeat Information field copied + * HEARTBEAT ACK that contains the Heartbeat Information field copied * from the received HEARTBEAT chunk. - * + * * Verification Tag: 8.5 Verification Tag [Normal verification] * When receiving an SCTP packet, the endpoint MUST ensure that the * value in the Verification Tag field of the received SCTP packet * matches its own Tag. If the received Verification Tag value does not * match the receiver's own tag value, the receiver shall silently - * discard the packet and shall not process it any further except for + * discard the packet and shall not process it any further except for * those cases listed in Section 8.5.1 below. - * + * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_beat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; +sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; sctp_chunk_t *reply; size_t paylen = 0; + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. If the received - * Verification Tag value does not match the receiver's own - * tag value, the receiver shall silently discard the packet... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } - - /* 8.3 The receiver of the HEARTBEAT should immediately - * respond with a HEARTBEAT ACK that contains the Heartbeat - * Information field copied from the received HEARTBEAT chunk. - */ - - chunk->subh.hb_hdr = (sctp_heartbeathdr_t *)chunk->skb->data; + /* 8.3 The receiver of the HEARTBEAT should immediately + * respond with a HEARTBEAT ACK that contains the Heartbeat + * Information field copied from the received HEARTBEAT chunk. + */ + chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); - skb_pull(chunk->skb, paylen); + skb_pull(chunk->skb, paylen); - reply = sctp_make_heartbeat_ack(asoc, chunk, + reply = sctp_make_heartbeat_ack(asoc, chunk, chunk->subh.hb_hdr, paylen); - if (NULL == reply) { goto nomem; } + if (!reply) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - return SCTP_DISPOSITION_CONSUME; - nomem: - return SCTP_DISPOSITION_NOMEM; -} /* sctp_sf_beat_8_3() */ +nomem: + return SCTP_DISPOSITION_NOMEM; +} /* * Process the returning HEARTBEAT ACK. - * + * * Section: 8.3 Path Heartbeat * Upon the receipt of the HEARTBEAT ACK, the sender of the HEARTBEAT * should clear the error counter of the destination transport @@ -761,49 +719,47 @@ sctp_sf_beat_8_3(const sctp_endpoint_t *ep, * HEARTBEAT ACK. The receiver of the HEARTBEAT ACK must also * clear the association overall error count as well (as defined * in section 8.1). - * + * * The receiver of the HEARTBEAT ACK should also perform an RTT * measurement for that destination transport address using the time * value carried in the HEARTBEAT ACK chunk. - * + * * Verification Tag: 8.5 Verification Tag [Normal verification] * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + sctp_chunk_t *chunk = arg; sockaddr_storage_t from_addr; - sctp_transport_t *link; + sctp_transport_t *link; sctp_sender_hb_info_t *hbinfo; unsigned long max_interval; - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - hbinfo= (sctp_sender_hb_info_t *)chunk->skb->data; + hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; from_addr = hbinfo->daddr; link = sctp_assoc_lookup_paddr(asoc, &from_addr); - - /* This should never happen, but lets log it if so. */ + + /* This should never happen, but lets log it if so. */ if (!link) { - printk(KERN_WARNING __FUNCTION__ + printk(KERN_WARNING __FUNCTION__ ": Could not find address %d.%d.%d.%d\n", NIPQUAD(from_addr.v4.sin_addr)); return SCTP_DISPOSITION_DISCARD; @@ -812,39 +768,36 @@ sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, max_interval = link->hb_interval + link->rto; /* Check if the timestamp looks valid. */ - - if (time_after(hbinfo->sent_at, jiffies) - || time_after(jiffies, hbinfo->sent_at + max_interval)) { + if (time_after(hbinfo->sent_at, jiffies) || + time_after(jiffies, hbinfo->sent_at + max_interval)) { SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp received for transport: %p\n", __FUNCTION__, link); return SCTP_DISPOSITION_DISCARD; } - /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of - * the HEARTBEAT should clear the error counter of the - * destination transport address to which the HEARTBEAT was - * sent and mark the destination transport address as active if - * it is not so marked. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, - SCTP_TRANSPORT(link)); + /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of + * the HEARTBEAT should clear the error counter of the + * destination transport address to which the HEARTBEAT was + * sent and mark the destination transport address as active if + * it is not so marked. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, + SCTP_TRANSPORT(link)); return SCTP_DISPOSITION_CONSUME; nomem:__attribute__((unused)) return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_backbeat_8_3() */ +} /* Populate the verification/tie tags based on overlapping INIT - * scenario. - * + * scenario. + * * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. */ -static void -sctp_tietags_populate(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static void sctp_tietags_populate(sctp_association_t *new_asoc, + const sctp_association_t *asoc) { switch (asoc->state) { @@ -855,11 +808,12 @@ sctp_tietags_populate(sctp_association_t *new_asoc, new_asoc->c.my_ttag = asoc->c.my_vtag; new_asoc->c.peer_ttag = 0; break; + case SCTP_STATE_COOKIE_ECHOED: new_asoc->c.my_vtag = asoc->c.my_vtag; new_asoc->c.my_ttag = asoc->c.my_vtag; new_asoc->c.peer_ttag = asoc->c.peer_vtag; - break; + break; /* 5.2.2 Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED, * COOKIE-WAIT and SHUTDOWN-ACK-SENT @@ -868,162 +822,138 @@ sctp_tietags_populate(sctp_association_t *new_asoc, new_asoc->c.my_ttag = asoc->c.my_vtag; new_asoc->c.peer_ttag = asoc->c.peer_vtag; break; - } - + }; + /* Other parameters for the endpoint SHOULD be copied from the - * existing parameters of the association (e.g. number of - * outbound streams) into the INIT ACK and cookie. - */ + * existing parameters of the association (e.g. number of + * outbound streams) into the INIT ACK and cookie. + */ new_asoc->rwnd = asoc->rwnd; new_asoc->c.sinit_num_ostreams = asoc->c.sinit_num_ostreams; new_asoc->c.sinit_max_instreams = asoc->c.sinit_max_instreams; new_asoc->c.initial_tsn = asoc->c.initial_tsn; - - return; - -} /* sctp_tietags_populate() */ +} - -/* +/* * Compare vtag/tietag values to determine unexpected COOKIE-ECHO * handling action. * * RFC 2960 5.2.4 Handle a COOKIE ECHO when a TCB exists. - * - * Returns value representing action to be taken. These action values - * correspond to Action/Description values in RFC 2960, Table 2. + * + * Returns value representing action to be taken. These action values + * correspond to Action/Description values in RFC 2960, Table 2. */ -static char -sctp_tietags_compare(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static char sctp_tietags_compare(sctp_association_t *new_asoc, + const sctp_association_t *asoc) { - /* In this case, the peer may have restarted. */ - if ((asoc->c.my_vtag != new_asoc->c.my_vtag) - && (asoc->c.peer_vtag != new_asoc->c.peer_vtag) - && (asoc->c.my_vtag == new_asoc->c.my_ttag) - && (asoc->c.peer_vtag == new_asoc->c.peer_ttag)) { - + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && + (asoc->c.peer_vtag != new_asoc->c.peer_vtag) && + (asoc->c.my_vtag == new_asoc->c.my_ttag) && + (asoc->c.peer_vtag == new_asoc->c.peer_ttag)) return 'A'; - } /* Collision case D. * Note: Test case D first, otherwise it may be incorrectly * identified as second case of B if the value of the Tie_tag is * not filled into the state cookie. */ - if ((asoc->c.my_vtag == new_asoc->c.my_vtag) - && (asoc->c.peer_vtag == new_asoc->c.peer_vtag)) { - + if ((asoc->c.my_vtag == new_asoc->c.my_vtag) && + (asoc->c.peer_vtag == new_asoc->c.peer_vtag)) return 'D'; - } - + /* Collision case B. */ - if (( asoc->c.my_vtag == new_asoc->c.my_vtag) - && ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) - || (!new_asoc->c.my_ttag && !new_asoc->c.peer_ttag))) { - + if ((asoc->c.my_vtag == new_asoc->c.my_vtag) && + ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) || + (!new_asoc->c.my_ttag && !new_asoc->c.peer_ttag))) return 'B'; - } - + /* Collision case C. */ - if ((asoc->c.my_vtag != new_asoc->c.my_vtag) - && ( asoc->c.peer_vtag == new_asoc->c.peer_vtag) - && (0 == new_asoc->c.my_ttag) - && (0 == new_asoc->c.peer_ttag)) { + if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && + (asoc->c.peer_vtag == new_asoc->c.peer_vtag) && + (0 == new_asoc->c.my_ttag) && + (0 == new_asoc->c.peer_ttag)) return 'C'; - } - - return 'E'; /* No such case available. */ - -} /* sctp_tietags_compare() */ + return 'E'; /* No such case available. */ +} /* Common helper routine for both duplicate and simulataneous INIT * chunk handling. */ -static sctp_disposition_t -sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ +static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, const sctp_subtype_t type, + void *arg, sctp_cmd_seq_t *commands) +{ sctp_chunk_t *chunk = arg; sctp_chunk_t *repl; - sctp_association_t *new_asoc; + sctp_association_t *new_asoc; - /* 6.10 Bundling + /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. */ - if (!chunk->singleton) { + if (!chunk->singleton) return SCTP_DISPOSITION_VIOLATION; - } + /* Grab the INIT header. */ + chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; - /* Grab the INIT header. */ - chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; - - /* Tag the variable length parameters. - */ + /* Tag the variable length parameters. */ chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); - /* + /* * Other parameters for the endpoint SHOULD be copied from the * existing parameters of the association (e.g. number of * outbound streams) into the INIT ACK and cookie. - * FIXME: We are copying parameters from the endpoint not the - * association. + * FIXME: We are copying parameters from the endpoint not the + * association. */ new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC); - if (!new_asoc) { goto nomem; } - + if (!new_asoc) + goto nomem; + /* In the outbound INIT ACK the endpoint MUST copy its current - * Verification Tag and Peers Verification tag into a reserved - * place (local tie-tag and per tie-tag) within the state cookie. + * Verification Tag and Peers Verification tag into a reserved + * place (local tie-tag and per tie-tag) within the state cookie. */ sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), + sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC); sctp_tietags_populate(new_asoc, asoc); - - /* B) "Z" shall respond immediately with an INIT ACK chunk. - */ - repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); - if (!repl) { goto nomem; } + /* B) "Z" shall respond immediately with an INIT ACK chunk. */ + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + if (!repl) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + /* * Note: After sending out INIT ACK with the State Cookie parameter, * "Z" MUST NOT allocate any resources for this new association. * Otherwise, "Z" will be vulnerable to resource attacks. */ - - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - - return SCTP_DISPOSITION_CONSUME; + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; nomem: - return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_unexpected_init() */ + return SCTP_DISPOSITION_NOMEM; +} /* * Handle simultanous INIT. * This means we started an INIT and then we got an INIT request from * our peer. - * + * * Section: 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State (Item B) * This usually indicates an initialization collision, i.e., each * endpoint is attempting, at about the same time, to establish an * association with the other endpoint. - * + * * Upon receipt of an INIT in the COOKIE-WAIT or COOKIE-ECHOED state, an * endpoint MUST respond with an INIT ACK using the same parameters it * sent in its original INIT chunk (including its Verification Tag, @@ -1031,52 +961,43 @@ nomem: * newly received INIT chunk. The endpoint shall also generate a State * Cookie with the INIT ACK. The endpoint uses the parameters sent in its * INIT to calculate the State Cookie. - * - * After that, the endpoint MUST NOT change its state, the T1-init - * timer shall be left running and the corresponding TCB MUST NOT be + * + * After that, the endpoint MUST NOT change its state, the T1-init + * timer shall be left running and the corresponding TCB MUST NOT be * destroyed. The normal procedures for handling State Cookies when * a TCB exists will resolve the duplicate INITs to a single association. - * + * * For an endpoint that is in the COOKIE-ECHOED state it MUST populate * its Tie-Tags with the Tag information of itself and its peer (see * section 5.2.2 for a description of the Tie-Tags). - * + * * Verification Tag: Not explicit, but an INIT can not have a valid * verification tag, so we skip the check. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_disposition_t retval; - +sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ /* Call helper to do the real work for both simulataneous and - * duplicate INIT chunk handling. + * duplicate INIT chunk handling. */ - - retval = sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); - - return retval; - -} /* sctp_sf_do_5_2_1_siminit() */ - - + return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); +} /* - * Handle duplicated INIT messages. These are usually delayed + * Handle duplicated INIT messages. These are usually delayed * restransmissions. - * + * * Section: 5.2.2 Unexpected INIT in States Other than CLOSED, * COOKIE-ECHOED and COOKIE-WAIT * @@ -1102,51 +1023,45 @@ sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, * (i.e. the endpoint is in a COOKIE-WAIT state), the Tie-Tags MUST be * set to 0 (indicating that no previous TCB existed). The INIT ACK and * State Cookie are populated as specified in section 5.2.1. - * + * * Verification Tag: Not specifed, but an INIT has no way of knowing * what the verification tag could be, so we ignore it. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * - * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_disposition_t retval; - /* Call helper to do the real work for both simulataneous and - * duplicate INIT chunk handling. + * duplicate INIT chunk handling. */ - - retval = sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); - return retval; - -} /* sctp_sf_do_5_2_2_dupinit() */ + return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands); +} /* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A') - * - * Section 5.2.4 + * + * Section 5.2.4 * A) In this case, the peer may have restarted. */ -static sctp_disposition_t -sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) { sctp_init_chunk_t *peer_init; sctp_ulpevent_t *ev; sctp_chunk_t *repl; - sctp_transport_t *new_addr, *addr; + sctp_transport_t *new_addr, *addr; list_t *pos, *pos2, *temp; int found, error; @@ -1156,55 +1071,59 @@ sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk), peer_init, GFP_ATOMIC); - - /* Make sure peer is not adding new addresses. */ + /* Make sure peer is not adding new addresses. */ found = 0; new_addr = NULL; list_for_each(pos, &new_asoc->peer.transport_addr_list) { new_addr = list_entry(pos, sctp_transport_t, transports); found = 1; - list_for_each_safe(pos2, temp, + list_for_each_safe(pos2, temp, &asoc->peer.transport_addr_list) { addr = list_entry(pos2, sctp_transport_t, transports); if (!sctp_cmp_addr_exact(&new_addr->ipaddr, - &addr->ipaddr)){ + &addr->ipaddr)) { found = 0; break; } } - if (!found){ break; } - } /* list_for_each(...) */ - - if (!found){ + if (!found) + break; + } + + if (!found) { sctp_bind_addr_t *bp; sctpParam_t rawaddr; int len; bp = sctp_bind_addr_new(GFP_ATOMIC); - if (!bp) { goto nomem; } + if (!bp) + goto nomem; error = sctp_add_bind_addr(bp, &new_addr->ipaddr, GFP_ATOMIC); - if (error) { goto nomem_add; } + if (error) + goto nomem_add; rawaddr = sctp_bind_addrs_to_raw(bp, &len, GFP_ATOMIC); - if (!rawaddr.v) { goto nomem_raw; } + if (!rawaddr.v) + goto nomem_raw; repl = sctp_make_abort(asoc, chunk, len+sizeof(sctp_errhdr_t)); - - if (!repl) { goto nomem_abort; } + if (!repl) + goto nomem_abort; sctp_init_cause(repl, SCTP_ERROR_RESTART, rawaddr.v, len); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); return SCTP_DISPOSITION_CONSUME; + nomem_abort: kfree(rawaddr.v); + nomem_raw: nomem_add: - sctp_bind_addr_free(bp); - goto nomem; + sctp_bind_addr_free(bp); + goto nomem; } - + /* For now, fail any unsent/unacked data. Consider the optional * choice of resending of this data. */ @@ -1212,70 +1131,69 @@ sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); - + repl = sctp_make_cookie_ack(new_asoc, chunk); - if (!repl) { goto nomem; } - - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + /* Report association restart to upper layer. */ - ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, + ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_max_instreams, GFP_ATOMIC); - if (NULL == ev) { goto nomem_ev; } - - sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + if (!ev) + goto nomem_ev; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); return SCTP_DISPOSITION_CONSUME; nomem_ev: sctp_free_chunk(repl); + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_dupcook_a() */ +} /* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'B') - * - * Section 5.2.4 + * + * Section 5.2.4 * B) In this case, both sides may be attempting to start an association * at about the same time but the peer endpoint started its INIT * after responding to the local endpoint's INIT */ /* This case represents an intialization collision. */ -static sctp_disposition_t -sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) { sctp_init_chunk_t *peer_init; sctp_ulpevent_t *ev; - sctp_chunk_t *repl; + sctp_chunk_t *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; - sctp_process_init(new_asoc, chunk->chunk_hdr->type, + sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk), peer_init, GFP_ATOMIC); - - /* Update the content of current association. */ + + /* Update the content of current association. */ sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); - - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); - sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); - + repl = sctp_make_cookie_ack(new_asoc, chunk); - if (NULL == repl) { goto nomem; } - - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + if (!repl) + goto nomem; + + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - + /* RFC 2960 5.1 Normal Establishment of an Association * * D) IMPLEMENTATION NOTE: An implementation may choose to @@ -1283,59 +1201,56 @@ sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, * upon reception of a valid COOKIE ECHO chunk. */ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0, - new_asoc->c.sinit_num_ostreams, - new_asoc->c.sinit_max_instreams, - GFP_ATOMIC); - if (NULL == ev) { goto nomem_ev; } - + new_asoc->c.sinit_num_ostreams, + new_asoc->c.sinit_max_instreams, + GFP_ATOMIC); + if (!ev) + goto nomem_ev; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); - return SCTP_DISPOSITION_CONSUME; + nomem_ev: sctp_free_chunk(repl); nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_dupcook_b() */ +} /* Unexpected COOKIE-ECHO handler for setup collision (Table 2, action 'C') - * - * Section 5.2.4 + * + * Section 5.2.4 * C) In this case, the local endpoint's cookie has arrived late. * Before it arrived, the local endpoint sent an INIT and received an * INIT-ACK and finally sent a COOKIE ECHO with the peer's same tag * but a new tag of its own. */ /* This case represents an intialization collision. */ -static sctp_disposition_t -sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) { - /* The cookie should be silently discarded. + /* The cookie should be silently discarded. * The endpoint SHOULD NOT change states and should leave * any timers running. */ return SCTP_DISPOSITION_DISCARD; - -} /* sctp_sf_do_dupcook_c() */ +} /* Unexpected COOKIE-ECHO handler lost chunk (Table 2, action 'D') - * - * Section 5.2.4 - * + * + * Section 5.2.4 + * * D) When both local and remote tags match the endpoint should always * enter the ESTABLISHED state, if it has not already done so. */ /* This case represents an intialization collision. */ -static sctp_disposition_t -sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + sctp_cmd_seq_t *commands, + sctp_association_t *new_asoc) { sctp_ulpevent_t *ev = NULL; sctp_chunk_t *repl; @@ -1347,10 +1262,9 @@ sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, if (SCTP_STATE_ESTABLISHED != asoc->state) { sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_ESTABLISHED)); - sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); - + /* RFC 2960 5.1 Normal Establishment of an Association * * D) IMPLEMENTATION NOTE: An implementation may choose @@ -1358,353 +1272,340 @@ sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, * SCTP user upon reception of a valid COOKIE * ECHO chunk. */ - ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, - SCTP_COMM_UP, 0, + ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, + SCTP_COMM_UP, 0, new_asoc->c.sinit_num_ostreams, new_asoc->c.sinit_max_instreams, GFP_ATOMIC); - - if (NULL == ev) { goto nomem; } - - sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + if (!ev) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); } - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); - + repl = sctp_make_cookie_ack(new_asoc, chunk); - if (NULL == repl) { goto nomem; } - - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - - sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); + if (!repl) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); + sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); return SCTP_DISPOSITION_CONSUME; + nomem: - if (ev) { sctp_ulpevent_free(ev); } + if (ev) + sctp_ulpevent_free(ev); return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_dupcook_c() */ +} /* * Handle a duplicate COOKIE-ECHO. This usually means a cookie-carrying * chunk was retransmitted and then delayed in the network. - * + * * Section: 5.2.4 Handle a COOKIE ECHO when a TCB exists - * + * * Verification Tag: None. Do cookie validation. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_association_t *new_asoc; - int error = 0; - char action; - - /* "Decode" the chunk. We have no optional parameters so we - * are in good shape. - */ - chunk->subh.cookie_hdr = - (sctp_signed_cookie_t *)chunk->skb->data; - skb_pull(chunk->skb, - ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - - /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie - * of a duplicate COOKIE ECHO match the Verification Tags of the - * current association, consider the State Cookie valid even if - * the lifespan is exceeded. - */ - new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); - - /* FIXME: - * If the re-build failed, what is the proper error path - * from here? - * - * [We should abort the association. --piggy] - */ - - if (NULL == new_asoc) { + sctp_disposition_t retval; + sctp_chunk_t *chunk = arg; + sctp_association_t *new_asoc; + int error = 0; + char action; + + /* "Decode" the chunk. We have no optional parameters so we + * are in good shape. + */ + chunk->subh.cookie_hdr = + (sctp_signed_cookie_t *) chunk->skb->data; + skb_pull(chunk->skb, + ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + + /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie + * of a duplicate COOKIE ECHO match the Verification Tags of the + * current association, consider the State Cookie valid even if + * the lifespan is exceeded. + */ + new_asoc = sctp_unpack_cookie(ep, asoc, chunk, GFP_ATOMIC, &error); + + /* FIXME: + * If the re-build failed, what is the proper error path + * from here? + * + * [We should abort the association. --piggy] + */ + if (!new_asoc) { /* FIXME: Several errors are possible. A bad cookie should * be silently discarded, but think about logging it too. */ switch (error) { case -SCTP_IERROR_NOMEM: goto nomem; + case -SCTP_IERROR_BAD_SIG: default: - return sctp_sf_pdiscard(ep, asoc, type, + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } - } - - /* Compare the tie_tag in cookie with the verification tag of - * current association. - */ - action = sctp_tietags_compare(new_asoc, asoc); - - switch (action) { - case 'A': /* Association restart. */ + }; + } + + /* Compare the tie_tag in cookie with the verification tag of + * current association. + */ + action = sctp_tietags_compare(new_asoc, asoc); + + switch (action) { + case 'A': /* Association restart. */ retval = sctp_sf_do_dupcook_a(ep, asoc, chunk, commands, new_asoc); break; - case 'B': /* Collision case B. */ - retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands, - new_asoc); - break; - case 'C': /* Collisioun case C. */ + + case 'B': /* Collision case B. */ + retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands, + new_asoc); + break; + + case 'C': /* Collisioun case C. */ retval = sctp_sf_do_dupcook_c(ep, asoc, chunk, commands, new_asoc); break; - - case 'D': /* Collision case D. */ + + case 'D': /* Collision case D. */ retval = sctp_sf_do_dupcook_d(ep, asoc, chunk, commands, new_asoc); break; - default: /* No such case, discard it. */ - printk(KERN_WARNING __FUNCTION__ ":unknown case\n"); + default: /* No such case, discard it. */ + printk(KERN_WARNING __FUNCTION__ ":unknown case\n"); retval = SCTP_DISPOSITION_DISCARD; break; - } /* switch */ - - /* Delete the tempory new association. */ - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); - sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - + }; + + /* Delete the tempory new association. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); + return retval; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_5_2_4_dupcook() */ - +} #if 0 /* * Handle a Stale COOKIE Error - * + * * Section: 5.2.6 Handle Stale COOKIE Error * If the association is in the COOKIE-ECHOED state, the endpoint may elect - * one of the following three alternatives. + * one of the following three alternatives. * ... * 3) Send a new INIT chunk to the endpoint, adding a Cookie * Preservative parameter requesting an extension to the lifetime of - * the State Cookie. When calculating the time extension, an + * the State Cookie. When calculating the time extension, an * implementation SHOULD use the RTT information measured based on the - * previous COOKIE ECHO / ERROR exchange, and should add no more - * than 1 second beyond the measured RTT, due to long State Cookie + * previous COOKIE ECHO / ERROR exchange, and should add no more + * than 1 second beyond the measured RTT, due to long State Cookie * lifetimes making the endpoint more subject to a replay attack. - * + * * Verification Tag: Not explicit, but safe to ignore. * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -do_5_2_6_stale(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - - /* This is not a real chunk type. It is a subtype of the - * ERROR chunk type. The ERROR chunk processing will bring us - * here. - */ +sctp_disposition_t do_5_2_6_stale(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* This is not a real chunk type. It is a subtype of the + * ERROR chunk type. The ERROR chunk processing will bring us + * here. + */ sctp_chunk_t *in_packet; stp_chunk_t *reply; - sctp_inithdr_t initack; - uint8_t *addrs; - int addrs_len; + sctp_inithdr_t initack; + __u8 *addrs; + int addrs_len; time_t rtt; - extern struct timespec now; - - struct sctpCookiePreserve bht; + struct sctpCookiePreserve bht; - /* If we have gotten too many failures, give up. */ - if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts){ - /* FIXME: Move to new ulpevent. */ - retval->event_up = sctp_make_ulp_init_timeout(asoc); - if (NULL == retval->event_up) { goto nomem; } + /* If we have gotten too many failures, give up. */ + if (1 + asoc->counters[SctpCounterInits] > asoc->max_init_attempts) { + /* FIXME: Move to new ulpevent. */ + retval->event_up = sctp_make_ulp_init_timeout(asoc); + if (!retval->event_up) + goto nomem; sctp_add_cmd_sf(retval->commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - return SCTP_DISPOSITION_DELETE_TCB; - } - + return SCTP_DISPOSITION_DELETE_TCB; + } + retval->counters[0] = SCTP_COUNTER_INCR; retval->counters[0] = SctpCounterInits; retval->counters[1] = 0; retval->counters[1] = 0; - + /* Calculate the RTT in ms. */ - /* BUG--we should get the send time of the HEARTBEAT REQUEST. */ + /* BUG--we should get the send time of the HEARTBEAT REQUEST. */ in_packet = chunk; - rtt = 1000 * timeval_sub(in_packet->skb->stamp, + rtt = 1000 * timeval_sub(in_packet->skb->stamp, asoc->c.state_timestamp); - /* When calculating the time extension, an implementation - * SHOULD use the RTT information measured based on the - * previous COOKIE ECHO / ERROR exchange, and should add no - * more than 1 second beyond the measured RTT, due to long - * State Cookie lifetimes making the endpoint more subject to - * a replay attack. - */ - bht.p = {SCTP_COOKIE_PRESERVE, 8}; - bht.extraTime = htonl(rtt + 1000); - - initack.init_tag = htonl(asoc->c.my_vtag); - initack.a_rwnd = htonl(atomic_read(&asoc->rnwd)); - initack.num_outbound_streams = htons(asoc->streamoutcnt); - initack.num_inbound_streams = htons(asoc->streamincnt); - initack.initial_tsn = htonl(asoc->c.initSeqNumber); - - sctp_get_my_addrs(asoc, &addrs, &addrs_len); + /* When calculating the time extension, an implementation + * SHOULD use the RTT information measured based on the + * previous COOKIE ECHO / ERROR exchange, and should add no + * more than 1 second beyond the measured RTT, due to long + * State Cookie lifetimes making the endpoint more subject to + * a replay attack. + */ + bht.p = {SCTP_COOKIE_PRESERVE, 8}; + bht.extraTime = htonl(rtt + 1000); + + initack.init_tag = htonl(asoc->c.my_vtag); + initack.a_rwnd = htonl(atomic_read(&asoc->rnwd)); + initack.num_outbound_streams = htons(asoc->streamoutcnt); + initack.num_inbound_streams = htons(asoc->streamincnt); + initack.initial_tsn = htonl(asoc->c.initSeqNumber); + + sctp_get_my_addrs(asoc, &addrs, &addrs_len); /* Build that new INIT chunk. */ - reply = sctp_make_chunk(SCTP_INITIATION, 0, + reply = sctp_make_chunk(SCTP_INITIATION, 0, sizeof(initack) + sizeof(bht) + addrs_len); - if (NULL == reply) { goto nomem; } + if (!reply) + goto nomem; sctp_addto_chunk(reply, sizeof(initack), &initack); sctp_addto_chunk(reply, sizeof(bht), &bht); sctp_addto_chunk(reply, addrs_len, addrs); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; -} /* sctp_disposition_t do_5_2_6_stale (...) */ +} #endif /* 0 */ - /* * Process an ABORT. - * + * * Section: 9.1 - * After checking the Verification Tag, the receiving endpoint shall - * remove the association from its record, and shall report the + * After checking the Verification Tag, the receiving endpoint shall + * remove the association from its record, and shall report the * termination to its upper layer. * * Verification Tag: 8.5.1 Exceptions in Verification Tag Rules * B) Rules for packet carrying ABORT: - * + * * - The endpoint shall always fill in the Verification Tag field of the * outbound packet with the destination endpoint's tag value if it - * is known. - * + * is known. + * * - If the ABORT is sent in response to an OOTB packet, the endpoint * MUST follow the procedure described in Section 8.4. - * + * * - The receiver MUST accept the packet if the Verification Tag * matches either its own tag, OR the tag of its peer. Otherwise, the * receiver MUST silently discard the packet and take no further - * action. - * + * action. + * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - - /* Check the verification tag. */ - /* BUG: WRITE ME. */ - - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, +sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + /* Check the verification tag. */ + /* BUG: WRITE ME. */ + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); /* BUG? This does not look complete... */ return SCTP_DISPOSITION_ABORT; - -} /* sctp_sf_do_9_1_abort() */ +} /* * Process an ABORT. (COOKIE-WAIT state) - * + * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t -sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_CLOSED)); - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); /* CMD_INIT_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands,SCTP_CMD_INIT_FAILED, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - -} /* sctp_sf_cookie_wait_abort() */ +} /* * Process an ABORT. (COOKIE-ECHOED state) - * + * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t -sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - /* There is a single T1 timer, so we should be able to use - * common function with the COOKIE-WAIT state. + * common function with the COOKIE-WAIT state. */ return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands); - -} /* sctp_sf_cookie_echoed_abort() */ +} #if 0 /* * Handle a shutdown timeout or INIT during a shutdown phase. - * + * * Section: 9.2 - * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk - * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination - * transport addresses (either in the IP addresses or in the INIT chunk) - * that belong to this association, it should discard the INIT chunk and - * retransmit the SHUTDOWN ACK chunk. - *... + * If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk + * (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination + * transport addresses (either in the IP addresses or in the INIT chunk) + * that belong to this association, it should discard the INIT chunk and + * retransmit the SHUTDOWN ACK chunk. + *... * While in SHUTDOWN-SENT state ... If the timer expires, the endpoint * must re-send the SHUTDOWN ACK. * @@ -1713,27 +1614,26 @@ sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_do_9_2_reshutack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; +sctp_disposition_t sctp_do_9_2_reshutack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; /* If this was a timeout (not an INIT), then do the counter * work. We might need to just dump the association. */ if (!chunk) { if (1 + asoc->counters[SctpCounterRetran] > - asoc->maxRetrans){ + asoc->maxRetrans) { sctp_add_cmd(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; @@ -1744,26 +1644,26 @@ sctp_do_9_2_reshutack(const sctp_endpoint_t *ep, retval->counters[1] = 0; } - reply = sctp_make_shutdown_ack(asoc, chunk); - if (!reply) { goto nomem; } + reply = sctp_make_shutdown_ack(asoc, chunk); + if (!reply) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_disposition_t sctp_do_9_2_reshutack(...) */ +} #endif /* 0 */ /* * sctp_sf_do_9_2_shut - * + * * Section: 9.2 - * Upon the reception of the SHUTDOWN, the peer endpoint shall - * - enter the SHUTDOWN-RECEIVED state, + * Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, * - * - stop accepting new data from its SCTP user + * - stop accepting new data from its SCTP user * * - verify, by checking the Cumulative TSN Ack field of the chunk, * that all its outstanding DATA chunks have been received by the @@ -1772,81 +1672,75 @@ nomem: * Once an endpoint as reached the SHUTDOWN-RECEIVED state it MUST NOT * send a SHUTDOWN in response to a ULP request. And should discard * subsequent SHUTDOWN chunks. - * + * * If there are still outstanding DATA chunks left, the SHUTDOWN * receiver shall continue to follow normal data transmission * procedures defined in Section 6 until all outstanding DATA chunks * are acknowledged; however, the SHUTDOWN receiver MUST NOT accept * new data from its SCTP user. - * + * * Verification Tag: 8.5 Verification Tag [Normal verification] * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * - * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - sctp_shutdownhdr_t *sdh; - sctp_disposition_t disposition; - - /* Convert the elaborate header. */ - sdh = (sctp_shutdownhdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); - chunk->subh.shutdown_hdr = sdh; - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. If the received - * Verification Tag value does not match the receiver's own - * tag value, the receiver shall silently discard the packet... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } + * The return value is the disposition of the chunk. + */ +sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_shutdownhdr_t *sdh; + sctp_disposition_t disposition; - /* Upon the reception of the SHUTDOWN, the peer endpoint shall - * - enter the SHUTDOWN-RECEIVED state, - * - stop accepting new data from its SCTP user - * - * [This is implicit in the new state.] - */ + /* Convert the elaborate header. */ + sdh = (sctp_shutdownhdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); + chunk->subh.shutdown_hdr = sdh; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Upon the reception of the SHUTDOWN, the peer endpoint shall + * - enter the SHUTDOWN-RECEIVED state, + * - stop accepting new data from its SCTP user + * + * [This is implicit in the new state.] + */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED)); + SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED)); + disposition = SCTP_DISPOSITION_CONSUME; - disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_shutdown_ack(ep, asoc, type, + arg, commands); + } - if (sctp_outqueue_is_empty(&asoc->outqueue)) { - disposition = - sctp_sf_do_9_2_shutdown_ack(ep, asoc, type, - arg, commands); - } - /* - verify, by checking the Cumulative TSN Ack field of the - * chunk, that all its outstanding DATA chunks have been - * received by the SHUTDOWN sender. - */ + * chunk, that all its outstanding DATA chunks have been + * received by the SHUTDOWN sender. + */ sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); - - return disposition; - -} /* sctp_sf_do_9_2_shutdown() */ - + return disposition; +} /* * sctp_sf_do_ecn_cwr - * + * * Section: Appendix A: Explicit Congestion Notification * * CWR: @@ -1863,56 +1757,48 @@ sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, * Verification Tag: 8.5 Verification Tag [Normal verification] * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ - -sctp_disposition_t -sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_cwrhdr_t *cwr; - sctp_chunk_t *chunk = arg; + sctp_cwrhdr_t *cwr; + sctp_chunk_t *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. If the received - * Verification Tag value does not match the receiver's own - * tag value, the receiver shall silently discard the packet... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - cwr = (sctp_cwrhdr_t *)chunk->skb->data; + cwr = (sctp_cwrhdr_t *) chunk->skb->data; skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t)); cwr->lowest_tsn = ntohl(cwr->lowest_tsn); /* Does this CWR ack the last sent congestion notification? */ - if (TSN_lte(asoc->last_ecne_tsn, cwr->lowest_tsn)) { - /* Stop sending ECNE. */ sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CWR, SCTP_U32(cwr->lowest_tsn)); } - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_do_ecne_cwr() */ - +} /* * sctp_sf_do_ecne - * + * * Section: Appendix A: Explicit Congestion Notification * * ECN-Echo @@ -1927,126 +1813,115 @@ sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, * Verification Tag: 8.5 Verification Tag [Normal verification] * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ - -sctp_disposition_t -sctp_sf_do_ecne(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_ecnehdr_t *ecne; - sctp_chunk_t *chunk = arg; - + sctp_ecnehdr_t *ecne; + sctp_chunk_t *chunk = arg; + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. If the received - * Verification Tag value does not match the receiver's own - * tag value, the receiver shall silently discard the packet... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } - - ecne = (sctp_ecnehdr_t *)chunk->skb->data; + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. If the received + * Verification Tag value does not match the receiver's own + * tag value, the receiver shall silently discard the packet... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + + ecne = (sctp_ecnehdr_t *) chunk->skb->data; skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t)); ecne->lowest_tsn = ntohl(ecne->lowest_tsn); - + /* Casting away the const, as we are just modifying the spinlock, * not the association itself. This should go away in the near * future when we move to an endpoint based lock. */ - - /* If this is a newer ECNE than the last CWR packet we sent out */ - if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)){ + /* If this is a newer ECNE than the last CWR packet we sent out */ + if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)) { sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE, SCTP_U32(ecne->lowest_tsn)); } - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_do_ecne() */ - +} /* * Section: 6.2 Acknowledgement on Reception of DATA Chunks - * - * The SCTP endpoint MUST always acknowledge the reception of each valid - * DATA chunk. - * + * + * The SCTP endpoint MUST always acknowledge the reception of each valid + * DATA chunk. + * * The guidelines on delayed acknowledgement algorithm specified in * Section 4.2 of [RFC2581] SHOULD be followed. Specifically, an * acknowledgement SHOULD be generated for at least every second packet - * (not every second DATA chunk) received, and SHOULD be generated within - * 200 ms of the arrival of any unacknowledged DATA chunk. In some - * situations it may be beneficial for an SCTP transmitter to be more - * conservative than the algorithms detailed in this document allow. - * However, an SCTP transmitter MUST NOT be more aggressive than the + * (not every second DATA chunk) received, and SHOULD be generated within + * 200 ms of the arrival of any unacknowledged DATA chunk. In some + * situations it may be beneficial for an SCTP transmitter to be more + * conservative than the algorithms detailed in this document allow. + * However, an SCTP transmitter MUST NOT be more aggressive than the * following algorithms allow. - * + * * A SCTP receiver MUST NOT generate more than one SACK for every * incoming packet, other than to update the offered window as the * receiving application consumes new data. - * + * * Verification Tag: 8.5 Verification Tag [Normal verification] - * + * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - sctp_datahdr_t *data_hdr; +sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; sctp_chunk_t *err; - size_t datalen; + size_t datalen; int tmp; - uint32_t tsn; + __u32 tsn; - /* RFC 2960 8.5 Verification Tag + /* RFC 2960 8.5 Verification Tag * * When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, SCTP_NULL()); - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); tsn = ntohl(data_hdr->tsn); SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); - - /* ASSERT: Now skb->data is really the user data. */ + /* ASSERT: Now skb->data is really the user data. */ - /* Process ECN based congestion. - * + /* Process ECN based congestion. + * * Since the chunk structure is reused for all chunks within * a packet, we use ecn_ce_done to track if we've already * done CE processing for this packet. @@ -2057,16 +1932,13 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, if (!chunk->ecn_ce_done) { chunk->ecn_ce_done = 1; - if ( INET_ECN_is_ce(chunk->skb->nh.iph->tos) - && asoc->peer.ecn_capable) { - + if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && + asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); - - } /* if (packet experienced congestion) */ - - } /* if (we have not done ecn_ce processing) */ + } + } tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); if (tmp < 0) { @@ -2082,20 +1954,20 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, /* This is a new TSN. */ - /* If we don't have any room in our receive window, discard. + /* If we don't have any room in our receive window, discard. * Actually, allow a little bit of overflow (up to a MTU of * of overflow). */ datalen = ntohs(chunk->chunk_hdr->length); datalen -= sizeof(sctp_data_chunk_t); - if (!asoc->rwnd || (datalen > asoc->frag_point)) { + if (!asoc->rwnd || (datalen > asoc->frag_point)) { SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %d, " "rwnd: %d\n", tsn, datalen, asoc->rwnd); goto discard_noforce; - } + } - /* + /* * Section 3.3.10.9 No User Data (9) * * Cause of error @@ -2106,14 +1978,14 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, if (unlikely(0 == datalen)) { err = sctp_make_abort_no_data(asoc, chunk, tsn); if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); } /* We are going to ABORT, so we might as well stop * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_CONSUME; @@ -2125,42 +1997,39 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream + * + * If an endpoint receive a DATA chunk with an invalid stream * identifier, it shall acknowledge the reception of the DATA chunk * following the normal procedure, immediately send an ERROR chunk * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. + * and discard the DATA chunk. */ if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, sizeof(data_hdr->stream)); if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); } goto discard_noforce; - } - /* Send the data up to the user. Note: Schedule the - * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK + /* Send the data up to the user. Note: Schedule the + * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK * chunk needs the updated rwnd. */ sctp_add_cmd_sf(commands, SCTP_CMD_CHUNK_ULP, SCTP_CHUNK(chunk)); - if (asoc->autoclose) { sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); } - /* If this is the last chunk in a packet, we need to count it - * toward sack generation. Note that we need to SACK every - * OTHER packet containing data chunks, EVEN IF WE DISCARD - * THEM. We elect to NOT generate SACK's if the chunk fails - * the verification tag test. + /* If this is the last chunk in a packet, we need to count it + * toward sack generation. Note that we need to SACK every + * OTHER packet containing data chunks, EVEN IF WE DISCARD + * THEM. We elect to NOT generate SACK's if the chunk fails + * the verification tag test. * * RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks * @@ -2177,18 +2046,18 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, * be more conservative than the algorithms detailed in this * document allow. However, an SCTP transmitter MUST NOT be * more aggressive than the following algorithms allow. - */ + */ if (chunk->end_of_packet) { sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); - + /* Start the SACK timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); - } + } return SCTP_DISPOSITION_CONSUME; - discard_force: +discard_force: /* RFC 2960 6.2 Acknowledgement on Reception of DATA Chunks * * When a packet arrives with duplicate DATA chunk(s) and with @@ -2203,9 +2072,8 @@ sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, /* In our case, we split the MAY SACK advice up whether or not * the last chunk is a duplicate.' */ - if (chunk->end_of_packet) { + if (chunk->end_of_packet) sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); - } return SCTP_DISPOSITION_DISCARD; discard_noforce: @@ -2217,13 +2085,11 @@ discard_noforce: SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); } return SCTP_DISPOSITION_DISCARD; - -} /* sctp_sf_eat_data_6_2() */ - +} /* * sctp_sf_eat_data_fast_4_4 - * + * * Section: 4 (4) * (4) In SHUTDOWN-SENT state the endpoint MUST acknowledge any received * DATA chunks without delay. @@ -2231,51 +2097,48 @@ discard_noforce: * Verification Tag: 8.5 Verification Tag [Normal verification] * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - sctp_datahdr_t *data_hdr; +sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_datahdr_t *data_hdr; sctp_chunk_t *err; - size_t datalen; + size_t datalen; int tmp; - uint32_t tsn; + __u32 tsn; - /* RFC 2960 8.5 Verification Tag + /* RFC 2960 8.5 Verification Tag * * When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. */ - - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, SCTP_NULL()); - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + } - data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); + data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); tsn = ntohl(data_hdr->tsn); SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - - /* ASSERT: Now skb->data is really the user data. */ - /* Process ECN based congestion. - * + /* ASSERT: Now skb->data is really the user data. */ + + /* Process ECN based congestion. + * * Since the chunk structure is reused for all chunks within * a packet, we use ecn_ce_done to track if we've already * done CE processing for this packet. @@ -2283,19 +2146,15 @@ sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, * We need to do ECN processing even if we plan to discard the * chunk later. */ - if (!chunk->ecn_ce_done) { chunk->ecn_ce_done = 1; - if ( INET_ECN_is_ce(chunk->skb->nh.iph->tos) - && asoc->peer.ecn_capable) { - + if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && + asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); - - } /* if (packet experienced congestion) */ - - } /* if (we have not done ecn_ce processing) */ + } + } tmp = sctp_tsnmap_check(&asoc->peer.tsn_map, tsn); if (tmp < 0) { @@ -2311,10 +2170,10 @@ sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, /* This is a new TSN. */ - datalen = ntohs(chunk->chunk_hdr->length); + datalen = ntohs(chunk->chunk_hdr->length); datalen -= sizeof(sctp_data_chunk_t); - /* + /* * Section 3.3.10.9 No User Data (9) * * Cause of error @@ -2325,14 +2184,14 @@ sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, if (unlikely(0 == datalen)) { err = sctp_make_abort_no_data(asoc, chunk, tsn); if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); } /* We are going to ABORT, so we might as well stop * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_CONSUME; @@ -2342,29 +2201,28 @@ sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, /* Record the fact that we have received this TSN. */ sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); - + /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number - * - * If an endpoint receive a DATA chunk with an invalid stream + * + * If an endpoint receive a DATA chunk with an invalid stream * identifier, it shall acknowledge the reception of the DATA chunk * following the normal procedure, immediately send an ERROR chunk * with cause set to "Invalid Stream Identifier" (See Section 3.3.10) - * and discard the DATA chunk. + * and discard the DATA chunk. */ if (ntohs(data_hdr->stream) >= asoc->c.sinit_max_instreams) { - - err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, - &data_hdr->stream, + err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, + &data_hdr->stream, sizeof(data_hdr->stream)); if (err) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(err)); } } /* Go a head and force a SACK, since we are shutting down. */ gen_shutdown: - /* Implementor's Guide. + /* Implementor's Guide. * * While in SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately * respond to each received packet containing one or more DATA chunk(s) @@ -2372,7 +2230,7 @@ gen_shutdown: */ if (chunk->end_of_packet) { /* We must delay the chunk creation since the cumulative - * TSN has not been updated yet. + * TSN has not been updated yet. */ sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SHUTDOWN, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); @@ -2380,23 +2238,21 @@ gen_shutdown: SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); } return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_eat_data_fast4_4() */ - +} /* * Section: 6.2 Processing a Received SACK * D) Any time a SACK arrives, the endpoint performs the following: - * + * * i) If Cumulative TSN Ack is less than the Cumulative TSN Ack Point, * then drop the SACK. Since Cumulative TSN Ack is monotonically * increasing, a SACK whose Cumulative TSN Ack is less than the * Cumulative TSN Ack Point indicates an out-of-order SACK. - * + * * ii) Set rwnd equal to the newly received a_rwnd minus the number * of bytes still outstanding after processing the Cumulative TSN Ack * and the Gap Ack Blocks. - * + * * iii) If the SACK is missing a TSN that was previously * acknowledged via a Gap Ack Block (e.g., the data receiver * reneged on the data), then mark the corresponding DATA chunk @@ -2405,72 +2261,65 @@ gen_shutdown: * timer is running for the destination address to which the DATA * chunk was originally transmitted, then T3-rtx is started for * that destination address. - * + * * Verification Tag: 8.5 Verification Tag [Normal verification] * * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - sctp_sackhdr_t *sackh; - uint32_t ctsn; - - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } +sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + sctp_sackhdr_t *sackh; + __u32 ctsn; - /* Pull the SACK chunk from the data buffer */ - sackh = sctp_sm_pull_sack(chunk); - chunk->subh.sack_hdr = sackh; - ctsn = ntohl(sackh->cum_tsn_ack); - - /* i) If Cumulative TSN Ack is less than the Cumulative TSN - * Ack Point, then drop the SACK. Since Cumulative TSN - * Ack is monotonically increasing, a SACK whose - * Cumulative TSN Ack is less than the Cumulative TSN Ack - * Point indicates an out-of-order SACK. - */ - if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* Pull the SACK chunk from the data buffer */ + sackh = sctp_sm_pull_sack(chunk); + chunk->subh.sack_hdr = sackh; + ctsn = ntohl(sackh->cum_tsn_ack); + + /* i) If Cumulative TSN Ack is less than the Cumulative TSN + * Ack Point, then drop the SACK. Since Cumulative TSN + * Ack is monotonically increasing, a SACK whose + * Cumulative TSN Ack is less than the Cumulative TSN Ack + * Point indicates an out-of-order SACK. + */ + if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); - SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", + SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", asoc->ctsn_ack_point); - return SCTP_DISPOSITION_DISCARD; - } + return SCTP_DISPOSITION_DISCARD; + } - /* Return this SACK for further processing. */ + /* Return this SACK for further processing. */ sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh)); - /* Note: We do the rest of the work on the PROCESS_SACK + /* Note: We do the rest of the work on the PROCESS_SACK * sideeffect. */ - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_eat_sack_6_2() */ - +} /* * Generate an ABORT in response to a packet. - * + * * Section: 8.4 Handle "Out of the blue" Packets * * 8) The receiver should respond to the sender of the OOTB packet @@ -2484,170 +2333,159 @@ sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, * * Verification Tag: * - * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_packet_t *packet = NULL; - sctp_transport_t *transport = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *abort; - uint16_t sport; - uint16_t dport; - uint32_t vtag; - - - /* Grub in chunk and endpoint for kewl bitz. */ + * The return value is the disposition of the chunk. +*/ +sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *abort; + __u16 sport; + __u16 dport; + __u32 vtag; + + /* Grub in chunk and endpoint for kewl bitz. */ sport = ntohs(chunk->sctp_hdr->dest); dport = ntohs(chunk->sctp_hdr->source); /* -- Make sure the ABORT packet's V-tag is the same as the - * inbound packet if no association exists, otherwise use - * the peer's vtag. - */ - if (asoc) { - vtag = asoc->peer.i.init_tag; - } else { - vtag = ntohl(chunk->sctp_hdr->vtag); - } - - /* Make a transport for the bucket, Eliza... */ - transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); - - if (!transport) { - goto nomem; - } + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + if (asoc) + vtag = asoc->peer.i.init_tag; + else + vtag = ntohl(chunk->sctp_hdr->vtag); + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + if (!transport) + goto nomem; - /* Make a packet for the ABORT to go into. */ - packet = t_new(sctp_packet_t, GFP_ATOMIC); - if (!packet) { + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) goto nomem_packet; - } - packet = sctp_packet_init(packet, transport, sport, dport); + + packet = sctp_packet_init(packet, transport, sport, dport); packet = sctp_packet_config(packet, vtag, 0, NULL); /* Make an ABORT. - * This will set the T bit since we have no association. - */ - abort = sctp_make_abort(NULL, chunk, 0); - if (NULL == abort) { - goto nomem_chunk; - } + * This will set the T bit since we have no association. + */ + abort = sctp_make_abort(NULL, chunk, 0); + if (!abort) + goto nomem_chunk; - /* Set the skb to the belonging sock for accounting. */ - abort->skb->sk = ep->base.sk; + /* Set the skb to the belonging sock for accounting. */ + abort->skb->sk = ep->base.sk; - sctp_packet_append_chunk(packet, abort); - + sctp_packet_append_chunk(packet, abort); sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); - return SCTP_DISPOSITION_DISCARD; nomem_chunk: sctp_packet_free(packet); + nomem_packet: sctp_transport_free(transport); + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_tabort_8_4_8() */ +} /* - * Received an ERROR chunk from peer. Generate SCTP_REMOTE_ERROR + * Received an ERROR chunk from peer. Generate SCTP_REMOTE_ERROR * event as ULP notification for each cause included in the chunk. - * - * API 5.3.1.3 - SCTP_REMOTE_ERROR * - * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_operr_notify(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - + * API 5.3.1.3 - SCTP_REMOTE_ERROR + * + * The return value is the disposition of the chunk. +*/ +sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ sctp_chunk_t *chunk = arg; sctp_ulpevent_t *ev; - while (chunk->chunk_end > chunk->skb->data) { ev = sctp_ulpevent_make_remote_error(asoc,chunk,0, GFP_ATOMIC); - - if (!ev) { goto nomem; } - + if (!ev) + goto nomem; + if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev))) { sctp_ulpevent_free(ev); goto nomem; } } - return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_operr_notify() */ +} /* * Process an inbound SHUTDOWN ACK. - * - * From Section 9.2: + * + * From Section 9.2: * Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall * stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its * peer, and remove all record of the association. * - * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; sctp_chunk_t *reply; sctp_ulpevent_t *ev; - - /* 10.2 H) SHUTDOWN COMPLETE notification - * - * When SCTP completes the shutdown procedures (section 9.2) this - * notification is passed to the upper layer. - */ - + /* 10.2 H) SHUTDOWN COMPLETE notification + * + * When SCTP completes the shutdown procedures (section 9.2) this + * notification is passed to the upper layer. + */ ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, 0, 0, 0, GFP_ATOMIC); - if (!ev) { goto nomem; } + if (!ev) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); - - /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall - * stop the T2-shutdown timer, - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall + * stop the T2-shutdown timer, + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); - /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ - reply = sctp_make_shutdown_complete(asoc, chunk); - if (!reply) { goto nomem; } - + /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ + reply = sctp_make_shutdown_complete(asoc, chunk); + if (!reply) + goto nomem; + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - /* ...and remove all record of the association. */ + /* ...and remove all record of the association. */ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - nomem: +nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_9_2_final() */ +} /* * RFC 2960, 8.4 - Handle "Out of the blue" Packets @@ -2667,54 +2505,47 @@ sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, * TCB was found. After sending this ABORT, the receiver of the OOTB * packet shall discard the OOTB packet and take no further action. */ -sctp_disposition_t -sctp_sf_ootb(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { sctp_chunk_t *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; - uint8_t *ch_end; + __u8 *ch_end; int ootb_shut_ack = 0; - ch = (sctp_chunkhdr_t *)chunk->chunk_hdr; - + ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; do { - ch_end = ((uint8_t *)ch) + WORD_ROUND(ntohs(ch->length)); - - if (SCTP_CID_SHUTDOWN_ACK == ch->type) { + ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); + + if (SCTP_CID_SHUTDOWN_ACK == ch->type) ootb_shut_ack = 1; - } - ch = (sctp_chunkhdr_t *)ch_end; - + ch = (sctp_chunkhdr_t *) ch_end; } while (ch_end < skb->tail); - - if (ootb_shut_ack) { + if (ootb_shut_ack) sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); - } else { + else sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); - } - - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); -} /* sctp_sf_ootb() */ + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); +} /* * Handle an "Out of the blue" SHUTDOWN ACK. * * Section: 8.4 5) - * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should - * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. - * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet - * must fill in the Verification Tag field of the outbound packet with - * the Verification Tag received in the SHUTDOWN ACK and set the - * T-bit in the Chunk Flags to indicate that no TCB was found. - * + * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should + * respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + * When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet + * must fill in the Verification Tag field of the outbound packet with + * the Verification Tag received in the SHUTDOWN ACK and set the + * T-bit in the Chunk Flags to indicate that no TCB was found. + * * Verification Tag: 8.5.1 E) Rules for packet carrying a SHUTDOWN ACK * If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state the * procedures in section 8.4 SHOULD be followed, in other words it @@ -2724,78 +2555,73 @@ sctp_sf_ootb(const sctp_endpoint_t *ep, * * Inputs * (endpoint, asoc, type, arg, commands) - * + * * Outputs * (sctp_disposition_t) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_packet_t *packet = NULL; - sctp_transport_t *transport = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *shut; - uint16_t sport; - uint16_t dport; - uint32_t vtag; - - + sctp_packet_t *packet = NULL; + sctp_transport_t *transport = NULL; + sctp_chunk_t *chunk = arg; + sctp_chunk_t *shut; + __u16 sport; + __u16 dport; + __u32 vtag; + /* Grub in chunk and endpoint for kewl bitz. */ sport = ntohs(chunk->sctp_hdr->dest); dport = ntohs(chunk->sctp_hdr->source); /* Make sure the ABORT packet's V-tag is the same as the - * inbound packet if no association exists, otherwise use - * the peer's vtag. - */ - vtag = ntohl(chunk->sctp_hdr->vtag); - - /* Make a transport for the bucket, Eliza... */ - transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + * inbound packet if no association exists, otherwise use + * the peer's vtag. + */ + vtag = ntohl(chunk->sctp_hdr->vtag); - if (!transport) { + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + if (!transport) goto nomem; - } - /* Make a packet for the ABORT to go into. */ - packet = t_new(sctp_packet_t, GFP_ATOMIC); - if (!packet) { + /* Make a packet for the ABORT to go into. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) goto nomem_packet; - } - packet = sctp_packet_init(packet, transport, sport, dport); + + packet = sctp_packet_init(packet, transport, sport, dport); packet = sctp_packet_config(packet, vtag, 0, NULL); /* Make an ABORT. - * This will set the T bit since we have no association. - */ - shut = sctp_make_shutdown_complete(NULL, chunk); - if (!shut) { - goto nomem_chunk; - } + * This will set the T bit since we have no association. + */ + shut = sctp_make_shutdown_complete(NULL, chunk); + if (!shut) + goto nomem_chunk; /* Set the skb to the belonging sock for accounting. */ - shut->skb->sk = ep->base.sk; - - sctp_packet_append_chunk(packet, shut); + shut->skb->sk = ep->base.sk; + sctp_packet_append_chunk(packet, shut); sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); return SCTP_DISPOSITION_CONSUME; nomem_chunk: sctp_packet_free(packet); + nomem_packet: sctp_transport_free(transport); + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_shut_8_4_5() */ +} #if 0 /* @@ -2804,140 +2630,131 @@ nomem: * ABORT. * * Log the fact and then process normally. - * + * * Section: Not specified * Verification Tag: 8.5 Verification Tag [Normal verification] * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -lucky(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } +sctp_disposition_t lucky(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; -} /* sctp_disposition_t lucky(...) */ +} #endif /* 0 */ #if 0 /* * The other end is doing something very stupid. We'll ignore them * after logging their idiocy. :-) - * + * * Section: Not specified * Verification Tag: 8.5 Verification Tag [Normal verification] * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -other_stupid(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) { - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - } +sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *chunk = arg; + + /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure + * that the value in the Verification Tag field of the + * received SCTP packet matches its own Tag. ... + */ + if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_disposition_t other_stupid(...) */ +} #endif /* 0 */ - /* * The other end is violating protocol. - * + * * Section: Not specified * Verification Tag: Not specified * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * We simply tag the chunk as a violation. The state machine will log * the violation and continue. */ -sctp_disposition_t -sctp_sf_violation(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ +sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ return SCTP_DISPOSITION_VIOLATION; - -} /* sctp_sf_violation() */ - - +} /*************************************************************************** * These are the state functions for handling primitive (Section 10) events. ***************************************************************************/ /* * sctp_sf_do_prm_asoc - * + * * Section: 10.1 ULP-to-SCTP * B) Associate - * - * Format: ASSOCIATE(local SCTP instance name, destination transport addr, - * outbound stream count) + * + * Format: ASSOCIATE(local SCTP instance name, destination transport addr, + * outbound stream count) * -> association id [,destination transport addr list] [,outbound stream - * count] - * + * count] + * * This primitive allows the upper layer to initiate an association to a - * specific peer endpoint. - * + * specific peer endpoint. + * * The peer endpoint shall be specified by one of the transport addresses * which defines the endpoint (see Section 1.4). If the local SCTP * instance has not been initialized, the ASSOCIATE is considered an - * error. + * error. * [This is not relevant for the kernel implementation since we do all * initialization at boot time. It we hadn't initialized we wouldn't * get anywhere near this code.] - * + * * An association id, which is a local handle to the SCTP association, * will be returned on successful establishment of the association. If * SCTP is not able to open an SCTP association with the peer endpoint, * an error is returned. * [In the kernel implementation, the sctp_association_t needs to * be created BEFORE causing this primitive to run.] - * + * * Other association parameters may be returned, including the * complete destination transport addresses of the peer as well as the * outbound stream count of the local endpoint. One of the transport @@ -2948,9 +2765,9 @@ sctp_sf_violation(const sctp_endpoint_t *ep, * sending a packet to a specific transport address. [All of this * stuff happens when the INIT ACK arrives. This is a NON-BLOCKING * function.] - * + * * Mandatory attributes: - * + * * o local SCTP instance name - obtained from the INITIALIZE operation. * [This is the argument asoc.] * o destination transport addr - specified as one of the transport @@ -2961,17 +2778,16 @@ sctp_sf_violation(const sctp_endpoint_t *ep, * would like to open towards this peer endpoint. * [BUG: This is not currently implemented.] * Optional attributes: - * + * * None. - * + * * The return value is a disposition. */ -sctp_disposition_t -sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { sctp_chunk_t *repl; sctp_bind_addr_t *bp; @@ -2990,22 +2806,22 @@ sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, * info from the local endpoint and the remote peer. */ bp = sctp_bind_addr_new(GFP_ATOMIC); - if (NULL == bp) { goto nomem; } + if (!bp) + goto nomem; - /* Use scoping rules to determine the subset of addresses from - * the endpoint. + /* Use scoping rules to determine the subset of addresses from + * the endpoint. */ scope = sctp_scope(&asoc->peer.active_path->ipaddr); flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; - if (asoc->peer.ipv4_address) { + if (asoc->peer.ipv4_address) flags |= SCTP_ADDR4_PEERSUPP; - } - if (asoc->peer.ipv6_address) { + if (asoc->peer.ipv6_address) flags |= SCTP_ADDR6_PEERSUPP; - } - error = sctp_bind_addr_copy(bp, &ep->base.bind_addr, scope, + error = sctp_bind_addr_copy(bp, &ep->base.bind_addr, scope, GFP_ATOMIC, flags); - if (0 != error) { goto nomem; } + if (error) + goto nomem; /* FIXME: Either move address assignment out of this function * or else move the association allocation/init into this function. @@ -3013,175 +2829,167 @@ sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, * function, so would not be a sideeffect if the allocation * moved into this function. --jgrimm */ - sctp_add_cmd_sf(commands, SCTP_CMD_SET_BIND_ADDR, (sctp_arg_t)bp); + sctp_add_cmd_sf(commands, SCTP_CMD_SET_BIND_ADDR, (sctp_arg_t) bp); /* RFC 2960 5.1 Normal Establishment of an Association - * - * A) "A" first sends an INIT chunk to "Z". In the INIT, "A" - * must provide its Verification Tag (Tag_A) in the Initiate - * Tag field. Tag_A SHOULD be a random number in the range of - * 1 to 4294967295 (see 5.3.1 for Tag value selection). ... - */ + * + * A) "A" first sends an INIT chunk to "Z". In the INIT, "A" + * must provide its Verification Tag (Tag_A) in the Initiate + * Tag field. Tag_A SHOULD be a random number in the range of + * 1 to 4294967295 (see 5.3.1 for Tag value selection). ... + */ repl = sctp_make_init(asoc, bp, GFP_ATOMIC); - if (NULL == repl) { goto nomem; } + if (!repl) + goto nomem; /* Cast away the const modifier, as we want to just - * rerun it through as a sideffect. + * rerun it through as a sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, - SCTP_ASOC((sctp_association_t *)asoc)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, + SCTP_ASOC((sctp_association_t *) asoc)); - /* After sending the INIT, "A" starts the T1-init timer and - * enters the COOKIE-WAIT state. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + /* After sending the INIT, "A" starts the T1-init timer and + * enters the COOKIE-WAIT state. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); - return SCTP_DISPOSITION_CONSUME; + nomem: - if (bp) { + if (bp) sctp_bind_addr_free(bp); - } return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_prm_asoc() */ +} /* * Process the SEND primitive. - * + * * Section: 10.1 ULP-to-SCTP * E) Send - * + * * Format: SEND(association id, buffer address, byte count [,context] - * [,stream id] [,life time] [,destination transport address] + * [,stream id] [,life time] [,destination transport address] * [,unorder flag] [,no-bundle flag] [,payload protocol-id] ) * -> result - * - * This is the main method to send user data via SCTP. - * + * + * This is the main method to send user data via SCTP. + * * Mandatory attributes: - * + * * o association id - local handle to the SCTP association - * + * * o buffer address - the location where the user message to be * transmitted is stored; - * + * * o byte count - The size of the user data in number of bytes; - * + * * Optional attributes: - * + * * o context - an optional 32 bit integer that will be carried in the * sending failure notification to the ULP if the transportation of * this User Message fails. - * + * * o stream id - to indicate which stream to send the data on. If not * specified, stream 0 will be used. - * + * * o life time - specifies the life time of the user data. The user data * will not be sent by SCTP after the life time expires. This * parameter can be used to avoid efforts to transmit stale * user messages. SCTP notifies the ULP if the data cannot be * initiated to transport (i.e. sent to the destination via SCTP's * send primitive) within the life time variable. However, the - * user data will be transmitted if SCTP has attempted to transmit a + * user data will be transmitted if SCTP has attempted to transmit a * chunk before the life time expired. - * + * * o destination transport address - specified as one of the destination * transport addresses of the peer endpoint to which this packet * should be sent. Whenever possible, SCTP should use this destination * transport address for sending the packets, instead of the current - * primary path. - * + * primary path. + * * o unorder flag - this flag, if present, indicates that the user - * would like the data delivered in an unordered fashion to the peer - * (i.e., the U flag is set to 1 on all DATA chunks carrying this + * would like the data delivered in an unordered fashion to the peer + * (i.e., the U flag is set to 1 on all DATA chunks carrying this * message). - * + * * o no-bundle flag - instructs SCTP not to bundle this user data with - * other outbound DATA chunks. SCTP MAY still bundle even when + * other outbound DATA chunks. SCTP MAY still bundle even when * this flag is present, when faced with network congestion. - * - * o payload protocol-id - A 32 bit unsigned integer that is to be - * passed to the peer indicating the type of payload protocol data + * + * o payload protocol-id - A 32 bit unsigned integer that is to be + * passed to the peer indicating the type of payload protocol data * being transmitted. This value is passed as opaque data by SCTP. - * - * + * * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_prm_send(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + sctp_chunk_t *chunk = arg; + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_do_prm_send() */ +} /* * Process the SHUTDOWN primitive. - * + * * Section: 10.1: * C) Shutdown - * + * * Format: SHUTDOWN(association id) - * -> result - * + * -> result + * * Gracefully closes an association. Any locally queued user data * will be delivered to the peer. The association will be terminated only * after the peer acknowledges all the SCTP packets sent. A success code * will be returned on successful termination of the association. If * attempting to terminate the association results in a failure, an error * code shall be returned. - * + * * Mandatory attributes: - * + * * o association id - local handle to the SCTP association - * + * * Optional attributes: - * + * * None. * * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - int disposition; - - /* From 9.2 Shutdown of an Association - * Upon receipt of the SHUTDOWN primitive from its upper - * layer, the endpoint enters SHUTDOWN-PENDING state and - * remains there until all outstanding data has been - * acknowledged by its peer. The endpoint accepts no new data - * from its upper layer, but retransmits data to the far end - * if necessary to fill gaps. - */ - +sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); - disposition = SCTP_DISPOSITION_CONSUME; - if (sctp_outqueue_is_empty(&asoc->outqueue)) { - disposition = - sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, arg, commands); - } + } return disposition; - -} /* sctp_sf_do_9_2_prm_shutdown() */ +} /* * Process the ABORT primitive. @@ -3210,106 +3018,91 @@ sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, * * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - - /* From 9.1 Abort of an Association - * Upon receipt of the ABORT primitive from its upper - * layer, the endpoint enters CLOSED state and - * discard all outstanding data has been - * acknowledged by its peer. The endpoint accepts no new data - * from its upper layer, but retransmits data to the far end - * if necessary to fill gaps. - */ - - sctp_chunk_t *abort; + /* From 9.1 Abort of an Association + * Upon receipt of the ABORT primitive from its upper + * layer, the endpoint enters CLOSED state and + * discard all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ + sctp_chunk_t *abort; sctp_disposition_t retval; retval = SCTP_DISPOSITION_CONSUME; - /* Generate ABORT chunk to send the peer */ + /* Generate ABORT chunk to send the peer. */ abort = sctp_make_abort(asoc, NULL, 0); - if (!abort) { + if (!abort) retval = SCTP_DISPOSITION_NOMEM; - } else { - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); - } + else + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); - /* Even if we can't send the ABORT due to low memory delete the + /* Even if we can't send the ABORT due to low memory delete the * TCB. This is a departure from our typical NOMEM handling. */ - /* Change to CLOSED state */ + /* Change to CLOSED state. */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_CLOSED)); - /* Delete the established association */ + /* Delete the established association. */ sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); - return retval; - -} /* sctp_sf_do_9_1_prm_abort() */ - +} /* We tried an illegal operation on an association which is closed. */ -sctp_disposition_t -sctp_sf_error_closed(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, SCTP_ERROR(-EINVAL)); return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_error_closed() */ +} /* We tried an illegal operation on an association which is shutting * down. */ -sctp_disposition_t -sctp_sf_error_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - - sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_ERROR, SCTP_ERROR(-ESHUTDOWN)); return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_error_shutdown() */ +} /* * sctp_cookie_wait_prm_shutdown - * + * * Section: 4 Note: 2 * Verification Tag: * Inputs * (endpoint, asoc) - * + * * The RFC does not explicitly address this issue, but is the route through the * state table when someone issues a shutdown while in COOKIE_WAIT state. * * Outputs * (timers) */ -sctp_disposition_t -sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands){ - - - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, +sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, @@ -3318,37 +3111,33 @@ sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - -} /* sctp_sf_cookie_wait_prm_shutdown() */ +} /* * sctp_cookie_echoed_prm_shutdown - * + * * Section: 4 Note: 2 * Verification Tag: * Inputs * (endpoint, asoc) - * + * * The RFC does not explcitly address this issue, but is the route through the * state table when someone issues a shutdown while in COOKIE_ECHOED state. * * Outputs * (timers) */ -sctp_disposition_t -sctp_sf_cookie_echoed_prm_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( + const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, sctp_cmd_seq_t *commands) { - /* There is a single T1 timer, so we should be able to use - * common function with the COOKIE-WAIT state. + * common function with the COOKIE-WAIT state. */ return sctp_sf_cookie_wait_prm_shutdown(ep, asoc, type, arg, commands); - -} /* sctp_sf_cookie_echoed_prm_shutdown() */ +} /* * sctp_cookie_wait_prm_abort @@ -3364,20 +3153,17 @@ sctp_sf_cookie_echoed_prm_shutdown(const sctp_endpoint_t *ep, * Outputs * (timers) */ -sctp_disposition_t -sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands){ - +sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ /* Stop T1-init timer */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands); - -} /* sctp_sf_cookie_wait_prm_abort() */ +} /* * sctp_cookie_echoed_prm_abort @@ -3393,39 +3179,32 @@ sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, * Outputs * (timers) */ -sctp_disposition_t -sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - /* There is a single T1 timer, so we should be able to use * common function with the COOKIE-WAIT state. */ return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands); - -} /* sctp_sf_cookie_echoed_prm_abort() */ +} /* * Ignore the primitive event * * The return value is the disposition of the primitive. */ -sctp_disposition_t -sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); - return SCTP_DISPOSITION_DISCARD; - -} /* sctp_sf_ignore_primitive() */ - +} /*************************************************************************** * These are the state functions for the OTHER events. @@ -3433,131 +3212,126 @@ sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, /* * Start the shutdown negotiation. - * + * * From Section 9.2: - * Once all its outstanding data has been acknowledged, the endpoint - * shall send a SHUTDOWN chunk to its peer including in the Cumulative - * TSN Ack field the last sequential TSN it has received from the peer. - * It shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT - * state. If the timer expires, the endpoint must re-send the SHUTDOWN + * Once all its outstanding data has been acknowledged, the endpoint + * shall send a SHUTDOWN chunk to its peer including in the Cumulative + * TSN Ack field the last sequential TSN it has received from the peer. + * It shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT + * state. If the timer expires, the endpoint must re-send the SHUTDOWN * with the updated last sequential TSN received from its peer. - * + * * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ +sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ sctp_chunk_t *reply; - - /* Once all its outstanding data has been acknowledged, the - * endpoint shall send a SHUTDOWN chunk to its peer including - * in the Cumulative TSN Ack field the last sequential TSN it - * has received from the peer. - */ + + /* Once all its outstanding data has been acknowledged, the + * endpoint shall send a SHUTDOWN chunk to its peer including + * in the Cumulative TSN Ack field the last sequential TSN it + * has received from the peer. + */ reply = sctp_make_shutdown(asoc); - if (NULL == reply) { goto nomem; } + if (!reply) + goto nomem; /* Set the transport for the SHUTDOWN chunk and the timeout for the - * T2-shutdown timer. + * T2-shutdown timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); - /* It shall then start the T2-shutdown timer */ - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + /* It shall then start the T2-shutdown timer */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); - - if (asoc->autoclose) { - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - } - /* and enter the SHUTDOWN-SENT state. */ + /* and enter the SHUTDOWN-SENT state. */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_SHUTDOWN_SENT)); + SCTP_STATE(SCTP_STATE_SHUTDOWN_SENT)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_9_2_start_shutdown() */ - +} /* * Generate a SHUTDOWN ACK now that everything is SACK'd. - * - * From Section 9.2: - * + * + * From Section 9.2: + * * If it has no more outstanding DATA chunks, the SHUTDOWN receiver * shall send a SHUTDOWN ACK and start a T2-shutdown timer of its own, * entering the SHUTDOWN-ACK-SENT state. If the timer expires, the * endpoint must re-send the SHUTDOWN ACK. * - * The return value is the disposition. */ -sctp_disposition_t -sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ + * The return value is the disposition. + */ +sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ sctp_chunk_t *chunk = (sctp_chunk_t *) arg; sctp_chunk_t *reply; - /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver - * shall send a SHUTDOWN ACK ... - */ - reply = sctp_make_shutdown_ack(asoc, chunk); - if (NULL == reply) { goto nomem; } - - /* Set the transport for the SHUTDOWN ACK chunk and the timeout for - * the T2-shutdown timer. - */ + /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver + * shall send a SHUTDOWN ACK ... + */ + reply = sctp_make_shutdown_ack(asoc, chunk); + if (!reply) + goto nomem; + + /* Set the transport for the SHUTDOWN ACK chunk and the timeout for + * the T2-shutdown timer. + */ sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); /* and start/restart a T2-shutdown timer of its own, */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); - - if (asoc->autoclose) { - sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + + if (asoc->autoclose) + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); - } - /* Enter the SHUTDOWN-ACK-SENT state. */ + /* Enter the SHUTDOWN-ACK-SENT state. */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_SHUTDOWN_ACK_SENT)); - - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); + SCTP_STATE(SCTP_STATE_SHUTDOWN_ACK_SENT)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_do_9_2_shutdown_ack() */ +} /* * Ignore the event defined as other * * The return value is the disposition of the event. */ -sctp_disposition_t -sctp_sf_ignore_other(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", + SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", type.other); return SCTP_DISPOSITION_DISCARD; - -} /* sctp_sf_ignore_primitive() */ +} /************************************************************ * These are the state functions for handling timeout events. @@ -3565,71 +3339,68 @@ sctp_sf_ignore_other(const sctp_endpoint_t *ep, /* * RTX Timeout - * + * * Section: 6.3.3 Handle T3-rtx Expiration - * + * * Whenever the retransmission timer T3-rtx expires for a destination * address, do the following: * [See below] * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_transport_t *transport = arg; +sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_transport_t *transport = arg; if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - } - - /* E1) For the destination address for which the timer - * expires, adjust its ssthresh with rules defined in Section - * 7.2.3 and set the cwnd <- MTU. - */ - - /* E2) For the destination address for which the timer - * expires, set RTO <- RTO * 2 ("back off the timer"). The - * maximum value discussed in rule C7 above (RTO.max) may be - * used to provide an upper bound to this doubling operation. - */ - - /* E3) Determine how many of the earliest (i.e., lowest TSN) - * outstanding DATA chunks for the address for which the - * T3-rtx has expired will fit into a single packet, subject - * to the MTU constraint for the path corresponding to the - * destination transport address to which the retransmission - * is being sent (this may be different from the address for - * which the timer expires [see Section 6.4]). Call this - * value K. Bundle and retransmit those K DATA chunks in a - * single packet to the destination endpoint. - * - * Note: Any DATA chunks that were sent to the address for - * which the T3-rtx timer expired but did not fit in one MTU - * (rule E3 above), should be marked for retransmission and - * sent as soon as cwnd allows (normally when a SACK arrives). - */ - - /* NB: Rules E4 and F1 are implicit in R1. */ + } + + /* E1) For the destination address for which the timer + * expires, adjust its ssthresh with rules defined in Section + * 7.2.3 and set the cwnd <- MTU. + */ + + /* E2) For the destination address for which the timer + * expires, set RTO <- RTO * 2 ("back off the timer"). The + * maximum value discussed in rule C7 above (RTO.max) may be + * used to provide an upper bound to this doubling operation. + */ + + /* E3) Determine how many of the earliest (i.e., lowest TSN) + * outstanding DATA chunks for the address for which the + * T3-rtx has expired will fit into a single packet, subject + * to the MTU constraint for the path corresponding to the + * destination transport address to which the retransmission + * is being sent (this may be different from the address for + * which the timer expires [see Section 6.4]). Call this + * value K. Bundle and retransmit those K DATA chunks in a + * single packet to the destination endpoint. + * + * Note: Any DATA chunks that were sent to the address for + * which the T3-rtx timer expired but did not fit in one MTU + * (rule E3 above), should be marked for retransmission and + * sent as soon as cwnd allows (normally when a SACK arrives). + */ + /* NB: Rules E4 and F1 are implicit in R1. */ sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN, SCTP_TRANSPORT(transport)); /* Do some failure management (Section 8.2). */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); - - return SCTP_DISPOSITION_CONSUME; + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); -} /* sctp_sf_do_6_3_3_rtx() */ + return SCTP_DISPOSITION_CONSUME; +} /* * Generate delayed SACK on timeout - * + * * Section: 6.2 Acknowledgement on Reception of DATA Chunks * * The guidelines on delayed acknowledgement algorithm specified in @@ -3642,55 +3413,50 @@ sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, * allow. However, an SCTP transmitter MUST NOT be more aggressive than * the following algorithms allow. */ -sctp_disposition_t -sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - +sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_do_6_2_sack() */ +} /* * sctp_sf_t1_timer_expire - * + * * Section: 4 Note: 2 * Verification Tag: * Inputs * (endpoint, asoc) - * - * RFC 2960 Section 4 Notes + * + * RFC 2960 Section 4 Notes * 2) If the T1-init timer expires, the endpoint MUST retransmit INIT * and re-start the T1-init timer without changing state. This MUST * be repeated up to 'Max.Init.Retransmits' times. After that, the * endpoint MUST abort the initialization process and report the * error to SCTP user. - * + * * 3) If the T1-cookie timer expires, the endpoint MUST retransmit * COOKIE ECHO and re-start the T1-cookie timer without changing * state. This MUST be repeated up to 'Max.Init.Retransmits' times. * After that, the endpoint MUST abort the initialization process and * report the error to SCTP user. * - * * Outputs * (timers, events) * */ -sctp_disposition_t -sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *repl; +sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + sctp_chunk_t *repl; sctp_bind_addr_t *bp; - sctp_event_timeout_t timer = (sctp_event_timeout_t)arg; + sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; int timeout; int attempts; @@ -3700,40 +3466,40 @@ sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, SCTP_DEBUG_PRINTK("Timer T1 expired.\n"); - if ((timeout < asoc->max_init_timeo) - && (attempts < asoc->max_init_attempts)) { - + if ((timeout < asoc->max_init_timeo) && + (attempts < asoc->max_init_attempts)) { switch (timer) { case SCTP_EVENT_TIMEOUT_T1_INIT: - bp = (sctp_bind_addr_t *)&asoc->base.bind_addr; + bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; repl = sctp_make_init(asoc, bp, GFP_ATOMIC); break; + case SCTP_EVENT_TIMEOUT_T1_COOKIE: repl = sctp_make_cookie_echo(asoc, NULL); break; + default: BUG(); break; - } - - if (!repl) { goto nomem; } + }; + + if (!repl) + goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); /* Issue a sideeffect to do the needed accounting. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, SCTP_TO(timer)); - - } else { + } else { sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); - - return SCTP_DISPOSITION_DELETE_TCB; - } - + return SCTP_DISPOSITION_DELETE_TCB; + } + return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; - -} /* sctp_sf_t1_timer_expire() */ +} /* RFC2960 9.2 If the timer expires, the endpoint must re-send the SHUTDOWN * with the updated last sequential TSN received from its peer. @@ -3748,94 +3514,89 @@ nomem: * the T2-Shutdown timer, giving its peer ample opportunity to transmit * all of its queued DATA chunks that have not yet been sent. */ -sctp_disposition_t -sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ +sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ sctp_chunk_t *reply = NULL; SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); - if (asoc->overall_error_count >= asoc->overall_error_threshold) { - /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL()); return SCTP_DISPOSITION_DELETE_TCB; - } + } - switch (asoc->state) { + switch (asoc->state) { case SCTP_STATE_SHUTDOWN_SENT: reply = sctp_make_shutdown(asoc); break; + case SCTP_STATE_SHUTDOWN_ACK_SENT: reply = sctp_make_shutdown_ack(asoc, NULL); break; + default: BUG(); break; - } - if (!reply) { goto nomem; } + }; + + if (!reply) + goto nomem; /* Do some failure management (Section 8.2). */ - sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(asoc->shutdown_last_sent_to)); - /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for - * the T2-shutdown timer. - */ + /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for + * the T2-shutdown timer. + */ sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply)); /* Restart the T2-shutdown timer. */ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - return SCTP_DISPOSITION_CONSUME; + nomem: return SCTP_DISPOSITION_NOMEM; +} -} /* sctp_sf_t2_timer_expire() */ - -/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires, - * the association is automatically closed by starting the shutdown process. +/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires, + * the association is automatically closed by starting the shutdown process. * The work that needs to be done is same as when SHUTDOWN is initiated by * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). - */ -sctp_disposition_t -sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - int disposition; - - /* From 9.2 Shutdown of an Association - * Upon receipt of the SHUTDOWN primitive from its upper - * layer, the endpoint enters SHUTDOWN-PENDING state and - * remains there until all outstanding data has been - * acknowledged by its peer. The endpoint accepts no new data - * from its upper layer, but retransmits data to the far end - * if necessary to fill gaps. - */ - + */ +sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + int disposition; + + /* From 9.2 Shutdown of an Association + * Upon receipt of the SHUTDOWN primitive from its upper + * layer, the endpoint enters SHUTDOWN-PENDING state and + * remains there until all outstanding data has been + * acknowledged by its peer. The endpoint accepts no new data + * from its upper layer, but retransmits data to the far end + * if necessary to fill gaps. + */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, - SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); + SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); - disposition = SCTP_DISPOSITION_CONSUME; - if (sctp_outqueue_is_empty(&asoc->outqueue)) { - disposition = - sctp_sf_do_9_2_start_shutdown(ep, asoc, type, + disposition = SCTP_DISPOSITION_CONSUME; + if (sctp_outqueue_is_empty(&asoc->outqueue)) { + disposition = + sctp_sf_do_9_2_start_shutdown(ep, asoc, type, arg, commands); - } + } return disposition; - -} /* sctp_sf_autoclose_timer_expire() */ +} /***************************************************************************** * These are sa state functions which could apply to all types of events. @@ -3846,63 +3607,55 @@ sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, * * Inputs * (endpoint, asoc, chunk) - * + * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_not_impl(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { return SCTP_DISPOSITION_NOT_IMPL; - -} /* sctp_sf_not_impl() */ +} /* * This table entry represents a bug. * * Inputs * (endpoint, asoc, chunk) - * + * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_bug(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { return SCTP_DISPOSITION_BUG; - -} /* sctp_sf_bug() */ +} /* * This table entry represents the firing of a timer in the wrong state. * Since timer deletion cannot be guaranteed a timer 'may' end up firing - * when the association is in the wrong state. This event should - * be ignored, so as to prevent any rearming of the timer. + * when the association is in the wrong state. This event should + * be ignored, so as to prevent any rearming of the timer. * * Inputs * (endpoint, asoc, chunk) - * + * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_timer_ignore(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { SCTP_DEBUG_PRINTK("Timer %d ignored.\n", type.chunk); - return SCTP_DISPOSITION_CONSUME; - -} /* sctp_sf_timer_ignore() */ - +} /* * Discard the chunk. @@ -3912,45 +3665,39 @@ sctp_sf_timer_ignore(const sctp_endpoint_t *ep, * Verification Tag: No verification needed. * Inputs * (endpoint, asoc, chunk) - * + * * Outputs * (asoc, reply_msg, msg_up, timers, counters) * * The return value is the disposition of the chunk. */ -sctp_disposition_t -sctp_sf_discard_chunk(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); return SCTP_DISPOSITION_DISCARD; - -} /* sctp_sf_discard_chunk() */ - +} /******************************************************************** * 2nd Level Abstractions ********************************************************************/ /* Pull the SACK chunk based on the SACK header. */ -sctp_sackhdr_t * -sctp_sm_pull_sack(sctp_chunk_t *chunk) +sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) { - sctp_sackhdr_t *sack; - uint16_t num_blocks; - uint16_t num_dup_tsns; - - sack = (sctp_sackhdr_t *)chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_sackhdr_t)); - - num_blocks = ntohs(sack->num_gap_ack_blocks); - num_dup_tsns = ntohs(sack->num_dup_tsns); + sctp_sackhdr_t *sack; + __u16 num_blocks; + __u16 num_dup_tsns; - skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(uint32_t)); + sack = (sctp_sackhdr_t *) chunk->skb->data; + skb_pull(chunk->skb, sizeof(sctp_sackhdr_t)); - return sack; + num_blocks = ntohs(sack->num_gap_ack_blocks); + num_dup_tsns = ntohs(sack->num_dup_tsns); -} /* sctp_sm_pull_sack() */ + skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32)); + return sack; +} diff --git a/net/sctp/sctp_sm_statetable.c b/net/sctp/sctp_sm_statetable.c index adf5ceec3853..89029496cc16 100644 --- a/net/sctp/sctp_sm_statetable.c +++ b/net/sctp/sctp_sm_statetable.c @@ -50,8 +50,8 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sm_statetable.c,v 1.21 #include #include #include - -sctp_sm_table_entry_t nop = {fn: sctp_sf_discard_chunk, + +sctp_sm_table_entry_t nop = {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}; sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; @@ -61,490 +61,354 @@ sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; "sctp table %p possible attack:" \ " event %d exceeds max %d\n", \ _table, event_subtype._type, _max); \ - return(&bug); \ - } \ - return(&_table[event_subtype._type][(int)state]); + return(&bug); \ + } \ + return(&_table[event_subtype._type][(int)state]); -sctp_sm_table_entry_t * -sctp_sm_lookup_event(sctp_event_t event_type, sctp_state_t state, - sctp_subtype_t event_subtype) +sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, + sctp_state_t state, + sctp_subtype_t event_subtype) { - switch (event_type) { - case SCTP_EVENT_T_CHUNK : - return sctp_chunk_event_lookup(event_subtype.chunk, state); - break; - case SCTP_EVENT_T_TIMEOUT : - DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, + switch (event_type) { + case SCTP_EVENT_T_CHUNK: + return sctp_chunk_event_lookup(event_subtype.chunk, state); + break; + case SCTP_EVENT_T_TIMEOUT: + DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout, timeout_event_table); - break; - case SCTP_EVENT_T_OTHER : - DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table); - break; - case SCTP_EVENT_T_PRIMITIVE: - DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive, - primitive_event_table); - break; - default: - /* Yikes! We got an illegal event type. */ - return(&bug); - } + break; -} /* sctp_sm_lookup_event() */ + case SCTP_EVENT_T_OTHER: + DO_LOOKUP(SCTP_EVENT_OTHER_MAX, other, other_event_table); + break; + + case SCTP_EVENT_T_PRIMITIVE: + DO_LOOKUP(SCTP_EVENT_PRIMITIVE_MAX, primitive, + primitive_event_table); + break; + default: + /* Yikes! We got an illegal event type. */ + return &bug; + }; +} #define TYPE_SCTP_DATA { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_eat_data_fast_4_4, name: "sctp_sf_eat_data_fast_4_4"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_eat_data_fast_4_4, name: "sctp_sf_eat_data_fast_4_4"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ } /* TYPE_SCTP_DATA */ - - #define TYPE_SCTP_INIT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_do_5_1B_init, name: "sctp_sf_do_5_1B_init"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1B_init, name: "sctp_sf_do_5_1B_init"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_INIT */ #define TYPE_SCTP_INIT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_do_5_1C_ack, name: "sctp_sf_do_5_1C_ack"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_INIT_ACK */ #define TYPE_SCTP_SACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ } /* TYPE_SCTP_SACK */ #define TYPE_SCTP_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* This should not happen, but we are nice. */ \ - {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ -\ + {fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ } /* TYPE_SCTP_HEARTBEAT */ #define TYPE_SCTP_HEARTBEAT_ACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_HEARTBEAT_ACK */ #define TYPE_SCTP_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_pdiscard, name: "sctp_sf_pdiscard"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_pdiscard, name: "sctp_sf_pdiscard"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_cookie_wait_abort, name: "sctp_sf_cookie_wait_abort"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_cookie_echoed_abort, \ + {fn: sctp_sf_cookie_echoed_abort, \ name: "sctp_sf_cookie_echoed_abort"}, \ -\ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ -\ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ -\ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ -\ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ -\ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ -\ + {fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ } /* TYPE_SCTP_ABORT */ #define TYPE_SCTP_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_shutdown, name: "sctp_sf_do_9_2_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_9_2_shutdown, name: "sctp_sf_do_9_2_shutdown"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_9_2_shutdown_ack, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ name: "sctp_sf_do_9_2_shutdown_ack"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_SHUTDOWN */ #define TYPE_SCTP_SHUTDOWN_ACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ } /* TYPE_SCTP_SHUTDOWN_ACK */ #define TYPE_SCTP_ERROR { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_operr_notify, name: "sctp_sf_operr_notify"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_operr_notify, name: "sctp_sf_operr_notify"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_ERROR */ #define TYPE_SCTP_COOKIE_ECHO { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_do_5_1D_ce, name: "sctp_sf_do_5_1D_ce"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_5_1D_ce, name: "sctp_sf_do_5_1D_ce"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ -\ } /* TYPE_SCTP_COOKIE_ECHO */ #define TYPE_SCTP_COOKIE_ACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_5_1E_ca, name: "sctp_sf_do_5_1E_ca"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_5_1E_ca, name: "sctp_sf_do_5_1E_ca"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ } /* TYPE_SCTP_COOKIE_ACK */ #define TYPE_SCTP_ECN_ECNE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ } /* TYPE_SCTP_ECN_ECNE */ #define TYPE_SCTP_ECN_CWR { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ } /* TYPE_SCTP_ECN_CWR */ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_do_4_C, name: "sctp_sf_do_4_C"}, \ -\ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_4_C, name: "sctp_sf_do_4_C"}, \ } /* TYPE_SCTP_SHUTDOWN_COMPLETE */ /* The primary index for this table is the chunk type. @@ -553,982 +417,733 @@ sctp_sm_lookup_event(sctp_event_t event_type, sctp_state_t state, * For base protocol (RFC 2960). */ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { - TYPE_SCTP_DATA, - TYPE_SCTP_INIT, - TYPE_SCTP_INIT_ACK, - TYPE_SCTP_SACK, - TYPE_SCTP_HEARTBEAT, - TYPE_SCTP_HEARTBEAT_ACK, - TYPE_SCTP_ABORT, - TYPE_SCTP_SHUTDOWN, - TYPE_SCTP_SHUTDOWN_ACK, - TYPE_SCTP_ERROR, - TYPE_SCTP_COOKIE_ECHO, - TYPE_SCTP_COOKIE_ACK, - TYPE_SCTP_ECN_ECNE, - TYPE_SCTP_ECN_CWR, - TYPE_SCTP_SHUTDOWN_COMPLETE, + TYPE_SCTP_DATA, + TYPE_SCTP_INIT, + TYPE_SCTP_INIT_ACK, + TYPE_SCTP_SACK, + TYPE_SCTP_HEARTBEAT, + TYPE_SCTP_HEARTBEAT_ACK, + TYPE_SCTP_ABORT, + TYPE_SCTP_SHUTDOWN, + TYPE_SCTP_SHUTDOWN_ACK, + TYPE_SCTP_ERROR, + TYPE_SCTP_COOKIE_ECHO, + TYPE_SCTP_COOKIE_ACK, + TYPE_SCTP_ECN_ECNE, + TYPE_SCTP_ECN_CWR, + TYPE_SCTP_SHUTDOWN_COMPLETE, }; /* state_fn_t chunk_event_table[][] */ static sctp_sm_table_entry_t chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_CLOSED */ {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_COOKIE_WAIT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_COOKIE_ECHOED */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_ESTABLISHED */ - {fn: sctp_sf_discard_chunk, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"}, /* SCTP_STATE_SHUTDOWN_PENDING */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_SENT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_RECEIVED */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_ACK_SENT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, }; /* chunk asconf */ static sctp_sm_table_entry_t chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_CLOSED */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_COOKIE_WAIT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_COOKIE_ECHOED */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_ESTABLISHED */ - {fn: sctp_sf_discard_chunk, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"}, /* SCTP_STATE_SHUTDOWN_PENDING */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_SENT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_RECEIVED */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, /* SCTP_STATE_SHUTDOWN_ACK_SENT */ - {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, + {fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, }; /* chunk asconf_ack */ #define TYPE_SCTP_PRIMITIVE_INITIALIZE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_INITIALIZE */ #define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_do_prm_asoc, name: "sctp_sf_do_prm_asoc"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_do_prm_asoc, name: "sctp_sf_do_prm_asoc"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ #define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_cookie_wait_prm_shutdown, \ - name: "sctp_sf_cookie_wait_prm_shutdown"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_cookie_echoed_prm_shutdown, \ - name:"sctp_sf_cookie_echoed_prm_shutdown"},\ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_9_2_prm_shutdown, \ + name: "sctp_sf_cookie_wait_prm_shutdown"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_prm_shutdown, \ + name:"sctp_sf_cookie_echoed_prm_shutdown"},\ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_2_prm_shutdown, \ name: "sctp_sf_do_9_2_prm_shutdown"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ -\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ -\ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ } /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ #define TYPE_SCTP_PRIMITIVE_ABORT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_cookie_wait_prm_abort, \ - name: "sctp_sf_cookie_wait_prm_abort"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_cookie_echoed_prm_abort, \ - name: "sctp_sf_cookie_echoed_prm_abort"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_9_1_prm_abort, \ - name: "sctp_sf_do_9_1_prm_abort"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_9_1_prm_abort, \ - name: "sctp_sf_do_9_1_prm_abort"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_9_1_prm_abort, \ - name: "sctp_sf_do_9_1_prm_abort"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_9_1_prm_abort, \ - name: "sctp_sf_do_9_1_prm_abort"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_do_9_1_prm_abort, \ - name: "sctp_sf_do_9_1_prm_abort"}, \ -\ + name: "sctp_sf_cookie_wait_prm_abort"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_cookie_echoed_prm_abort, \ + name: "sctp_sf_cookie_echoed_prm_abort"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_do_9_1_prm_abort, \ + name: "sctp_sf_do_9_1_prm_abort"}, \ } /* TYPE_SCTP_PRIMITIVE_ABORT */ #define TYPE_SCTP_PRIMITIVE_SEND { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ + /* SCTP_STATE_ESTABLISHED */ \ {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ -\ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ } /* TYPE_SCTP_PRIMITIVE_SEND */ #define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ -} /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */ #define TYPE_SCTP_PRIMITIVE_RECEIVE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_RECEIVE */ #define TYPE_SCTP_PRIMITIVE_STATUS { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_STATUS */ #define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */ #define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ #define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */ #define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */ #define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */ #define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */ #define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */ #define TYPE_SCTP_PRIMITIVE_DESTROY { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ } /* TYPE_SCTP_PRIMITIVE_DESTROY */ /* The primary index for this table is the primitive type. * The secondary index for this table is the state. */ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { - TYPE_SCTP_PRIMITIVE_INITIALIZE, - TYPE_SCTP_PRIMITIVE_ASSOCIATE, - TYPE_SCTP_PRIMITIVE_SHUTDOWN, - TYPE_SCTP_PRIMITIVE_ABORT, - TYPE_SCTP_PRIMITIVE_SEND, - TYPE_SCTP_PRIMITIVE_SETPRIMARY, - TYPE_SCTP_PRIMITIVE_RECEIVE, - TYPE_SCTP_PRIMITIVE_STATUS, - TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT, - TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT, - TYPE_SCTP_PRIMITIVE_GETSRTTREPORT, - TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD, - TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS, - TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT, - TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED, - TYPE_SCTP_PRIMITIVE_DESTROY, -}; /* primitive_event_table[][] */ + TYPE_SCTP_PRIMITIVE_INITIALIZE, + TYPE_SCTP_PRIMITIVE_ASSOCIATE, + TYPE_SCTP_PRIMITIVE_SHUTDOWN, + TYPE_SCTP_PRIMITIVE_ABORT, + TYPE_SCTP_PRIMITIVE_SEND, + TYPE_SCTP_PRIMITIVE_SETPRIMARY, + TYPE_SCTP_PRIMITIVE_RECEIVE, + TYPE_SCTP_PRIMITIVE_STATUS, + TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT, + TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT, + TYPE_SCTP_PRIMITIVE_GETSRTTREPORT, + TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD, + TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT, + TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED, + TYPE_SCTP_PRIMITIVE_DESTROY, +}; #define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ + /* SCTP_STATE_ESTABLISHED */ \ {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_9_2_start_shutdown, \ + {fn: sctp_sf_do_9_2_start_shutdown, \ name: "sctp_do_9_2_start_shutdown"}, \ -\ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_9_2_shutdown_ack, \ + {fn: sctp_sf_do_9_2_shutdown_ack, \ name: "sctp_sf_do_9_2_shutdown_ack"}, \ -\ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ -\ -} /* TYPE_SCTP_OTHER_NO_PENDING_TSN */ + {fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ +} #define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ -} /* TYPE_SCTP_OTHER_ICMP_UNREACHFRAG */ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { - TYPE_SCTP_OTHER_NO_PENDING_TSN, - TYPE_SCTP_OTHER_ICMP_UNREACHFRAG, + TYPE_SCTP_OTHER_NO_PENDING_TSN, + TYPE_SCTP_OTHER_ICMP_UNREACHFRAG, }; #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_NONE */ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE */ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_T1_INIT */ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ -\ - /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN */ + /* SCTP_STATE_COOKIE_WAIT */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ - /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_WAIT */ \ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ - /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ -\ - /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ -\ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ -\ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ -\ + {fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_T3_RTX */ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_T4_RTO */ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ -\ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ -\ + {fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT */ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ -\ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ -\ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ -\ + {fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_SACK */ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_autoclose_timer_expire, \ + {fn: sctp_sf_autoclose_timer_expire, \ name: "sctp_sf_autoclose_timer_expire"}, \ -\ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE */ + {fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ +} #define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \ - /* SCTP_STATE_EMPTY */ \ - {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ -\ + /* SCTP_STATE_EMPTY */ \ + {fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ /* SCTP_STATE_COOKIE_ECHOED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_ESTABLISHED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ -\ -} /* TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE */ - + {fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ +} sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { - TYPE_SCTP_EVENT_TIMEOUT_NONE, - TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, - TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, - TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, - TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, + TYPE_SCTP_EVENT_TIMEOUT_NONE, + TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, + TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, + TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, + TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, TYPE_SCTP_EVENT_TIMEOUT_T4_RTO, - TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, - TYPE_SCTP_EVENT_TIMEOUT_SACK, - TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, - TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE, + TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, + TYPE_SCTP_EVENT_TIMEOUT_SACK, + TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, + TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE, }; -sctp_sm_table_entry_t * -sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) +sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) { - if ( state > SCTP_STATE_MAX ) { BUG(); } - if ( cid < 0 ) { return &nop; } - - if ( cid <= SCTP_CID_BASE_MAX ) { - return &chunk_event_table[cid][state]; - } - - switch ( cid ) { - case SCTP_CID_ASCONF : return &chunk_event_table_asconf[state]; - case SCTP_CID_ASCONF_ACK : return &chunk_event_table_asconf_ack[state]; - default: return &nop; - } + if (state > SCTP_STATE_MAX) + BUG(); + if (cid < 0) + return &nop; + + if (cid <= SCTP_CID_BASE_MAX) + return &chunk_event_table[cid][state]; + + switch (cid) { + case SCTP_CID_ASCONF: + return &chunk_event_table_asconf[state]; + + case SCTP_CID_ASCONF_ACK: + return &chunk_event_table_asconf_ack[state]; + default: + return &nop; + }; return &nop; } diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index dfc05cd885e8..e65150cf2933 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -82,67 +82,62 @@ static int sctp_writeable(struct sock *sk); static inline int sctp_wspace(sctp_association_t *asoc); static inline void sctp_set_owner_w(sctp_chunk_t *chunk); static void sctp_wfree(struct sk_buff *skb); -static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, +static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); -struct sk_buff * sctp_skb_recv_datagram(struct sock *sk, int flags, +struct sk_buff * sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err); -static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, +static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, int *addr_len, struct sk_buff *skb); -static inline void sctp_sk_addr_set(struct sock *, +static inline void sctp_sk_addr_set(struct sock *, const sockaddr_storage_t *newaddr, sockaddr_storage_t *saveaddr); -static inline void sctp_sk_addr_restore(struct sock *, +static inline void sctp_sk_addr_restore(struct sock *, const sockaddr_storage_t *); static inline int sctp_sendmsg_verify_name(struct sock *, struct msghdr *); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_do_bind(struct sock *, sockaddr_storage_t *, int); static int sctp_autobind(struct sock *sk); -static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, +static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum); /* API 3.1.2 bind() - UDP Style Syntax * The syntax of bind() is, - * + * * ret = bind(int sd, struct sockaddr *addr, int addrlen); - * + * * sd - the socket descriptor returned by socket(). * addr - the address structure (struct sockaddr_in or struct - * sockaddr_in6 [RFC 2553]), + * sockaddr_in6 [RFC 2553]), * addrlen - the size of the address structure. - * + * * The caller should use struct sockaddr_storage described in RFC 2553 * to represent addr for portability reason. */ -int -sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) +int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - int retval = 0; + int retval = 0; + + sctp_lock_sock(sk); - sctp_lock_sock(sk); - SCTP_DEBUG_PRINTK("sctp_bind(sk: %p, uaddr: %p, addr_len: %d)\n", sk, uaddr, addr_len); /* Disallow binding twice. */ - - if (0 == sctp_sk(sk)->ep->base.bind_addr.port) { + if (!sctp_sk(sk)->ep->base.bind_addr.port) retval = sctp_do_bind(sk, (sockaddr_storage_t *)uaddr, addr_len); - } else { + else retval = -EINVAL; - } - - sctp_release_sock(sk); - return retval; + sctp_release_sock(sk); -} /* sctp_bind() */ + return retval; +} -/* Bind a local address either to an endpoint or to an association. */ -static int -sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) +/* Bind a local address either to an endpoint or to an association. */ +static int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) { sctp_opt_t *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; @@ -151,176 +146,169 @@ sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) sockaddr_storage_t tmpaddr, saveaddr; unsigned short *snum; int ret = 0; - - SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", + + SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", sk, newaddr, addr_len); - /* FIXME: This function needs to handle v4-mapped-on-v6 + /* FIXME: This function needs to handle v4-mapped-on-v6 * addresses! */ - if (PF_INET == sk->family) { - if (sa_family != AF_INET) { + if (sa_family != AF_INET) return -EINVAL; - } } - /* Make a local copy of the new address. */ + /* Make a local copy of the new address. */ tmpaddr = *newaddr; switch (sa_family) { case AF_INET: - if (addr_len < sizeof(struct sockaddr_in)) { + if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; - } + ret = inet_addr_type(newaddr->v4.sin_addr.s_addr); /* FIXME: - * Should we allow apps to bind to non-local addresses by - * checking the IP sysctl parameter "ip_nonlocal_bind"? + * Should we allow apps to bind to non-local addresses by + * checking the IP sysctl parameter "ip_nonlocal_bind"? */ - if (newaddr->v4.sin_addr.s_addr != INADDR_ANY - && ret != RTN_LOCAL) { + if (newaddr->v4.sin_addr.s_addr != INADDR_ANY && + ret != RTN_LOCAL) return -EADDRNOTAVAIL; - } + tmpaddr.v4.sin_port = htons(tmpaddr.v4.sin_port); snum = &tmpaddr.v4.sin_port; break; + case AF_INET6: SCTP_V6( /* FIXME: Hui, please verify this. Looking at * the ipv6 code I see a SIN6_LEN_RFC2133 check. * I'm guessing that scope_id is a newer addition. */ - if (addr_len < sizeof(struct sockaddr_in6)) { + if (addr_len < sizeof(struct sockaddr_in6)) return -EINVAL; - } - /* FIXME - The support for IPv6 multiple types + + /* FIXME - The support for IPv6 multiple types * of addresses need to be added later. */ ret = sctp_ipv6_addr_type(&newaddr->v6.sin6_addr); - tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port); + tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port); snum = &tmpaddr.v6.sin6_port; break; ) + default: return -EINVAL; - } /* switch(family) */ - + }; SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", bp->port, *snum); - /* We must either be unbound, or bind to the same port. */ - if ((0 != bp->port) && (*snum != bp->port)) { + /* We must either be unbound, or bind to the same port. */ + if (bp->port && (*snum != bp->port)) { SCTP_DEBUG_PRINTK("sctp_do_bind:" " New port %d does not match existing port " "%d.\n", *snum, bp->port); - return -EINVAL; - } - - if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)){ - return -EACCES; + return -EINVAL; } + if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; - /* FIXME - Make socket understand that there might be multiple bind - * addresses and there will be multiple source addresses involved in - * routing and failover decisions. - */ - + /* FIXME - Make socket understand that there might be multiple bind + * addresses and there will be multiple source addresses involved in + * routing and failover decisions. + */ sctp_sk_addr_set(sk, &tmpaddr, &saveaddr); - + /* Make sure we are allowed to bind here. * The function sctp_get_port() does duplicate address * detection. */ - if (0 != (ret = sctp_get_port(sk, *snum))) { + if ((ret = sctp_get_port(sk, *snum))) { sctp_sk_addr_restore(sk, &saveaddr); - if (ret == (int)sk) { + if (ret == (long) sk) { /* This endpoint has a conflicting address. */ return -EINVAL; } else { return -EADDRINUSE; } } - - /* Refresh ephemeral port. */ - if (0 == *snum) { - *snum = inet_sk(sk)->num; - } - /* The getsockname() API depends on 'sport' being set. */ + /* Refresh ephemeral port. */ + if (!*snum) + *snum = inet_sk(sk)->num; + + /* The getsockname() API depends on 'sport' being set. */ inet_sk(sk)->sport = htons(inet_sk(sk)->num); - /* Add the address to the bind address list. */ + /* Add the address to the bind address list. */ sctp_local_bh_disable(); sctp_write_lock(&ep->base.addr_lock); - /* Use GFP_ATOMIC since BHs are disabled. */ - if (0 != (ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { + /* Use GFP_ATOMIC since BHs are disabled. */ + if ((ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { sctp_sk_addr_restore(sk, &saveaddr); - } else if (0 == bp->port) { - bp->port = *snum; - } + } else if (!bp->port) { + bp->port = *snum; + } sctp_write_unlock(&ep->base.addr_lock); sctp_local_bh_enable(); - - return ret; - -} /* sctp_do_bind */ + return ret; +} /* API 8.1 sctp_bindx() - * + * * The syntax of sctp_bindx() is, - * + * * ret = sctp_bindx(int sd, * struct sockaddr_storage *addrs, * int addrcnt, * int flags); - * + * * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. * If the sd is an IPv6 socket, the addresses passed can either be IPv4 * or IPv6 addresses. - * + * * A single address may be specified as INADDR_ANY or IPV6_ADDR_ANY, see * section 3.1.2 for this usage. - * + * * addrs is a pointer to an array of one or more socket addresses. Each * address is contained in a struct sockaddr_storage, so each address is * fixed length. The caller specifies the number of addresses in the * array with addrcnt. - * + * * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns -1, * and sets errno to the appropriate error code. [ Editor's note: need * to fill in all error code? ] - * + * * For SCTP, the port given in each socket address must be the same, or * sctp_bindx() will fail, setting errno to EINVAL . - * + * * The flags parameter is formed from the bitwise OR of zero or * more of the following currently defined flags: - * + * * SCTP_BINDX_ADD_ADDR * SCTP_BINDX_REM_ADDR - * + * * SCTP_BIND_ADD_ADDR directs SCTP to add the given addresses to the * association, and SCTP_BIND_REM_ADDR directs SCTP to remove the given * addresses from the association. The two flags are mutually exclusive; * if both are given, sctp_bindx() will fail with EINVAL. A caller may not * remove all addresses from an association; sctp_bindx() will reject such * an attempt with EINVAL. - * + * * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate * additional addresses with an endpoint after calling bind(). Or use * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening * socket is associated with so that no new association accepted will be * associated with those addresses. - * + * * SCTP_BIND_ADD_ADDR is defined as 0, so that it becomes the default * behavior for sctp_bindx() when no flags are given. - * + * * Adding and removing addresses from a connected association is optional * functionality. Implementations that do not support this functionality * should return EOPNOTSUPP. @@ -334,51 +322,48 @@ sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) * sctp_bindx() for a lock-protected call. */ -static int -__sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, - int addrcnt, int flags) +static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, + int addrcnt, int flags) { - int retval = 0; + int retval = 0; SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " "flags: %s)\n", sk, addrs, addrcnt, (BINDX_ADD_ADDR == flags)?"ADD": ((BINDX_REM_ADDR == flags)?"REM":"BOGUS")); - - switch (flags) { - case BINDX_ADD_ADDR: - retval = sctp_bindx_add(sk, addrs, addrcnt); - break; - case BINDX_REM_ADDR: - retval = sctp_bindx_rem(sk, addrs, addrcnt); - break; - default: - retval = -EINVAL; - break; - } - return retval; - -} /* __sctp_bindx() */ + switch (flags) { + case BINDX_ADD_ADDR: + retval = sctp_bindx_add(sk, addrs, addrcnt); + break; + + case BINDX_REM_ADDR: + retval = sctp_bindx_rem(sk, addrs, addrcnt); + break; + + default: + retval = -EINVAL; + break; + }; + + return retval; +} /* BINDX with locks. * * NOTE: Currently unused at all ... */ -int -sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, - int flags) +int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, + int flags) { - int retval; - - sctp_lock_sock(sk); - retval = __sctp_bindx(sk, addrs, addrcnt, flags); - sctp_release_sock(sk); + int retval; - return retval; - -} /* sctp_bindx() */ + sctp_lock_sock(sk); + retval = __sctp_bindx(sk, addrs, addrcnt, flags); + sctp_release_sock(sk); + return retval; +} /* Add a list of addresses as bind addresses to local endpoint or * association. @@ -392,44 +377,43 @@ sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, * * Only __sctp_bindx() is supposed to call this function. */ -int -sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) { - int cnt; - int retval = 0; + int retval = 0; int addr_len; SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n", sk, addrs, addrcnt); - - for (cnt = 0; cnt < addrcnt; cnt++) { + + for (cnt = 0; cnt < addrcnt; cnt++) { /* The list may contain either IPv4 or IPv6 address; * determine the address length for walking thru the list. - */ + */ switch (((struct sockaddr *)&addrs[cnt])->sa_family) { - case AF_INET: - addr_len = sizeof(struct sockaddr_in); - break; - case AF_INET6: - addr_len = sizeof(struct sockaddr_in6); - break; - default: - retval = -EINVAL; - goto err_bindx_add; - } + case AF_INET: + addr_len = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + addr_len = sizeof(struct sockaddr_in6); + break; - retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], + default: + retval = -EINVAL; + goto err_bindx_add; + }; + + retval = sctp_do_bind(sk, (sockaddr_storage_t *)&addrs[cnt], addr_len); + err_bindx_add: - if (retval < 0) { + if (retval < 0) { /* Failed. Cleanup the ones that has been added */ - if (cnt > 0) { + if (cnt > 0) sctp_bindx_rem(sk, addrs, cnt); - } return retval; } - } /* Notify the peer(s), assuming we have (an) association(s). @@ -448,16 +432,16 @@ err_bindx_add: * what we have now. In the former case we know the * association already. --piggy * - * This code will be working on either a UDP style or a TCP style - * socket, or say either an endpoint or an association. The socket - * type verification code need to be added later before calling the + * This code will be working on either a UDP style or a TCP style + * socket, or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the * ADDIP code. * --daisy - */ + */ #if CONFIG_IP_SCTP_ADDIP /* Add these addresses to all associations on this endpoint. */ - if ( retval >= 0) { + if (retval >= 0) { list_t *pos; sctp_endpoint_t *ep; sctp_association_t *asoc; @@ -469,15 +453,12 @@ err_bindx_add: sctp_addip_addr_config(asoc, SCTP_PARAM_ADD_IP, addrs, addrcnt); - - } /* for (each association on the endpoint) */ - } + } + } #endif - return retval; - -} /* sctp_bindx_add() */ - + return retval; +} /* Remove a list of addresses from bind addresses list. Do not remove the * last address. @@ -494,89 +475,88 @@ err_bindx_add: * * Only __sctp_bindx() is supposed to call this function. */ -int -sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) { sctp_opt_t *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; int cnt; sctp_bind_addr_t *bp = &ep->base.bind_addr; - int retval = 0; - sockaddr_storage_t saveaddr; + int retval = 0; + sockaddr_storage_t saveaddr; SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", sk, addrs, addrcnt); - for (cnt = 0; cnt < addrcnt; cnt++) { - /* If there is only one bind address, there is nothing more + for (cnt = 0; cnt < addrcnt; cnt++) { + /* If there is only one bind address, there is nothing more * to be removed (we need at least one address here). - */ - + */ if (list_empty(&bp->address_list)) { retval = -EBUSY; goto err_bindx_rem; } - /* The list may contain either IPv4 or IPv6 address; + /* The list may contain either IPv4 or IPv6 address; * determine the address length for walking thru the list. - */ + */ switch (((struct sockaddr *)&addrs[cnt])->sa_family) { - case AF_INET: - saveaddr = *((sockaddr_storage_t *) - &addrs[cnt]); - saveaddr.v4.sin_port = - ntohs(saveaddr.v4.sin_port); - /* verify the port */ - if (saveaddr.v4.sin_port != bp->port) { - retval = -EINVAL; - goto err_bindx_rem; - } - break; - case AF_INET6: - saveaddr = *((sockaddr_storage_t *) - &addrs[cnt]); - saveaddr.v6.sin6_port = - ntohs(saveaddr.v6.sin6_port); - /* verify the port */ - if (saveaddr.v6.sin6_port != bp->port) { - retval = -EINVAL; - goto err_bindx_rem; - } - break; - default: + case AF_INET: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v4.sin_port = + ntohs(saveaddr.v4.sin_port); + /* verify the port */ + if (saveaddr.v4.sin_port != bp->port) { retval = -EINVAL; goto err_bindx_rem; - } + } + break; - /* FIXME - There is probably a need to check if sk->saddr and - * sk->rcv_addr are currently set to one of the addresses to - * be removed. This is something which needs to be looked into - * when we are fixing the outstanding issues with multi-homing - * socket routing and failover schemes. Refer to comments in + case AF_INET6: + saveaddr = *((sockaddr_storage_t *) + &addrs[cnt]); + saveaddr.v6.sin6_port = + ntohs(saveaddr.v6.sin6_port); + /* verify the port */ + if (saveaddr.v6.sin6_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } + break; + + default: + retval = -EINVAL; + goto err_bindx_rem; + }; + + /* FIXME - There is probably a need to check if sk->saddr and + * sk->rcv_addr are currently set to one of the addresses to + * be removed. This is something which needs to be looked into + * when we are fixing the outstanding issues with multi-homing + * socket routing and failover schemes. Refer to comments in * sctp_do_bind(). -daisy */ sctp_local_bh_disable(); sctp_write_lock(&ep->base.addr_lock); - retval = sctp_del_bind_addr(bp, &saveaddr); + retval = sctp_del_bind_addr(bp, &saveaddr); sctp_write_unlock(&ep->base.addr_lock); sctp_local_bh_enable(); + err_bindx_rem: - if (retval < 0) { + if (retval < 0) { /* Failed. Add the ones that has been removed back */ - if (cnt > 0) { + if (cnt > 0) sctp_bindx_add(sk, addrs, cnt); - } return retval; } - - } + } /* - * This code will be working on either a UDP style or a TCP style - * socket, * or say either an endpoint or an association. The socket - * type verification code need to be added later before calling the + * This code will be working on either a UDP style or a TCP style + * socket, * or say either an endpoint or an association. The socket + * type verification code need to be added later before calling the * ADDIP code. * --daisy */ @@ -586,22 +566,17 @@ err_bindx_rem: list_t *pos; sctp_endpoint_t *ep; sctp_association_t *asoc; - ep = sctp_sk(sk)->ep; + ep = sctp_sk(sk)->ep; list_for_each(pos, &ep->asocs) { asoc = list_entry(pos, sctp_association_t, asocs); - sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, addrs, addrcnt); - - } /* for (each association on the endpoint) */ - } + } + } #endif - - return retval; - -} /* sctp_bindx_rem() */ - + return retval; +} /* Helper for tunneling sys_bindx() requests through sctp_setsockopt() * @@ -634,120 +609,111 @@ err_bindx_rem: * * Returns 0 if ok, <0 errno code on error. */ -static int -sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, - int addrssize, int op) +static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, + int addrssize, int op) { struct sockaddr_storage *kaddrs; int err; size_t addrcnt; - + SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" - " addrssize %d opt %d\n", sk, addrs, - addrssize, op); + " addrssize %d opt %d\n", sk, addrs, + addrssize, op); - /* Do we have an integer number of structs sockaddr_storage? */ - if (unlikely(addrssize <= 0 - || addrssize % sizeof(struct sockaddr_storage) != 0)) { + /* Do we have an integer number of structs sockaddr_storage? */ + if (unlikely(addrssize <= 0 || + addrssize % sizeof(struct sockaddr_storage) != 0)) return -EINVAL; - } - /* Check the user passed a healthy pointer. */ - if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize))) { + /* Check the user passed a healthy pointer. */ + if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize))) return -EFAULT; - } - /* Alloc space for the address array in kernel memory. */ + /* Alloc space for the address array in kernel memory. */ kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); - if (unlikely(NULL == kaddrs)) { + if (unlikely(NULL == kaddrs)) return -ENOMEM; + + if (copy_from_user(kaddrs, addrs, addrssize)) { + kfree(kaddrs); + return -EFAULT; } - - __copy_from_user(kaddrs, addrs, addrssize); + addrcnt = addrssize / sizeof(struct sockaddr_storage); err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */ kfree(kaddrs); - return err; - -} /* sctp_setsockopt_bindx() */ + return err; +} /* API 3.1.4 close() - UDP Style Syntax * Applications use close() to perform graceful shutdown (as described in * Section 10.1 of [SCTP]) on ALL the associations currently represented - * by a UDP-style socket. - * + * by a UDP-style socket. + * * The syntax is - * + * * ret = close(int sd); - * + * * sd - the socket descriptor of the associations to be closed. - * + * * To gracefully shutdown a specific association represented by the * UDP-style socket, an application should use the sendmsg() call, * passing no user data, but including the appropriate flag in the * ancillary data (see Section xxxx). - * + * * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. */ - -void -sctp_close(struct sock *sk, long timeout) +void sctp_close(struct sock *sk, long timeout) { - sctp_endpoint_t *ep; - sctp_association_t *asoc; + sctp_endpoint_t *ep; + sctp_association_t *asoc; list_t *pos, *temp; - - SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%x...)\n", - (unsigned int)sk); + SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); sctp_lock_sock(sk); sk->shutdown = SHUTDOWN_MASK; ep = sctp_sk(sk)->ep; - /* Walk all associations on a socket, not on an endpoint. */ + /* Walk all associations on a socket, not on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { asoc = list_entry(pos, sctp_association_t, asocs); sctp_primitive_SHUTDOWN(asoc, NULL); - } + } - - /* Clean up any skbs sitting on the receive queue. - */ + /* Clean up any skbs sitting on the receive queue. */ skb_queue_purge(&sk->receive_queue); - - /* This will run the backlog queue. */ + + /* This will run the backlog queue. */ sctp_release_sock(sk); /* Supposedly, no process has access to the socket, but * the net layers still may. */ - sctp_local_bh_disable(); sctp_bh_lock_sock(sk); /* Hold the sock, since inet_sock_release() will put sock_put() * and we have just a little more cleanup. */ - sock_hold(sk); + sock_hold(sk); inet_sock_release(sk); - + sctp_bh_unlock_sock(sk); sctp_local_bh_enable(); sock_put(sk); - - SCTP_DBG_OBJCNT_DEC(sock); -} /* sctp_close() */ + SCTP_DBG_OBJCNT_DEC(sock); +} /* API 3.1.3 sendmsg() - UDP Style Syntax * * An application uses sendmsg() and recvmsg() calls to transmit data to - * and receive data from its peer. + * and receive data from its peer. * * ssize_t sendmsg(int socket, const struct msghdr *message, * int flags); @@ -757,47 +723,46 @@ sctp_close(struct sock *sk, long timeout) * user message and possibly some ancillary data. * * See Section 5 for complete description of the data - * structures. + * structures. * * flags - flags sent or received with the user message, see Section - * 5 for complete description of the flags. + * 5 for complete description of the flags. * * NB: The argument 'msg' is a user space address. */ /* BUG: We do not implement timeouts. */ /* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ -int -sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) +int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) { sctp_opt_t *sp; - sctp_endpoint_t *ep; - sctp_association_t *asoc = NULL; + sctp_endpoint_t *ep; + sctp_association_t *asoc = NULL; sctp_transport_t *transport; - sctp_chunk_t *chunk = NULL; - sockaddr_storage_t to; + sctp_chunk_t *chunk = NULL; + sockaddr_storage_t to; struct sockaddr *msg_name = NULL; - struct sctp_sndrcvinfo default_sinfo = {0}; + struct sctp_sndrcvinfo default_sinfo = { 0 }; struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = NULL; - sctp_cmsgs_t cmsgs = {0}; - int err; - size_t msg_len; + sctp_cmsgs_t cmsgs = { 0 }; + int err; + size_t msg_len; sctp_scope_t scope; long timeo; - uint16_t sinfo_flags = 0; + __u16 sinfo_flags = 0; - SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, " + SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, " "size: %d)\n", sk, msg, size); - err = 0; + err = 0; sp = sctp_sk(sk); ep = sp->ep; SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); - /* Parse out the SCTP CMSGs. */ + /* Parse out the SCTP CMSGs. */ err = sctp_msghdr_parse(msg, &cmsgs); if (err) { @@ -805,53 +770,55 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) goto out_nounlock; } - /* Fetch the destination address for this packet. This - * address only selects the association--it is not necessarily - * the address we will send to. - * For a peeled-off socket, msg_name is ignored. - */ + /* Fetch the destination address for this packet. This + * address only selects the association--it is not necessarily + * the address we will send to. + * For a peeled-off socket, msg_name is ignored. + */ if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { err = sctp_sendmsg_verify_name(sk, msg); - if (err) { return err; } - - memcpy(&to, msg->msg_name, msg->msg_namelen); + if (err) + return err; + + memcpy(&to, msg->msg_name, msg->msg_namelen); SCTP_DEBUG_PRINTK("Just memcpy'd. msg_name is " "0x%x:%u.\n", to.v4.sin_addr.s_addr, to.v4.sin_port); - + to.v4.sin_port = ntohs(to.v4.sin_port); msg_name = msg->msg_name; - } - + } + msg_len = get_user_iov_size(msg->msg_iov, msg->msg_iovlen); sinfo = cmsgs.info; sinit = cmsgs.init; - /* Did the user specify SNDRCVINFO? */ + /* Did the user specify SNDRCVINFO? */ if (sinfo) { sinfo_flags = sinfo->sinfo_flags; associd = sinfo->sinfo_assoc_id; } - SCTP_DEBUG_PRINTK("msg_len: %d, sinfo_flags: 0x%x\n", + SCTP_DEBUG_PRINTK("msg_len: %d, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); - /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow + /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow * sending 0-length messages when MSG_EOF|MSG_ABORT is not set. */ - if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) - || (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { - err = -EINVAL; + if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) || + (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { + err = -EINVAL; goto out_nounlock; - } + } sctp_lock_sock(sk); transport = NULL; SCTP_DEBUG_PRINTK("About to look up association.\n"); - /* If a msg_name has been specified, assume this is to be used. */ + + /* If a msg_name has been specified, assume this is to be used. */ if (msg_name) { asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); } else { @@ -861,20 +828,19 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) { if (list_empty(&ep->asocs)) { err = -EINVAL; - goto out_unlock; + goto out_unlock; } - asoc = list_entry(ep->asocs.next, sctp_association_t, + asoc = list_entry(ep->asocs.next, sctp_association_t, asocs); } else if (associd) { - asoc = sctp_id2assoc(sk, associd); + asoc = sctp_id2assoc(sk, associd); } if (!asoc) { err = -EINVAL; goto out_unlock; - } - } - - + } + } + if (asoc) { SCTP_DEBUG_PRINTK("Just looked up association: " "%s. \n", asoc->debug_name); @@ -882,7 +848,7 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) SCTP_DEBUG_PRINTK("Shutting down association: %p\n", asoc); sctp_primitive_SHUTDOWN(asoc, NULL); - err = 0; + err = 0; goto out_unlock; } if (sinfo_flags & MSG_ABORT) { @@ -892,52 +858,48 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) goto out_unlock; } } - - /* Do we need to create the association? */ - if (NULL == asoc) { - + /* Do we need to create the association? */ + if (!asoc) { SCTP_DEBUG_PRINTK("There is no association yet.\n"); /* Check for invalid stream against the stream counts, - * either the default or the user specified stream counts. + * either the default or the user specified stream counts. */ if (sinfo) { - - if ((NULL == sinit) || - (sinit && (0 == sinit->sinit_num_ostreams))) { + if (!sinit || + (sinit && !sinit->sinit_num_ostreams)) { /* Check against the defaults. */ - if (sinfo->sinfo_stream >= + if (sinfo->sinfo_stream >= sp->initmsg.sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } - } else { - /* Check against the defaults. */ - if (sinfo->sinfo_stream >= - sp->initmsg.sinit_num_ostreams) { + /* Check against the defaults. */ + if (sinfo->sinfo_stream >= + sp->initmsg.sinit_num_ostreams) { err = -EINVAL; goto out_unlock; } - /* Check against the requested. */ - if (sinfo->sinfo_stream >= + + /* Check against the requested. */ + if (sinfo->sinfo_stream >= sinit->sinit_num_ostreams) { err = -EINVAL; goto out_unlock; - } - + } } } /* - * API 3.1.2 bind() - UDP Style Syntax - * If a bind() or sctp_bindx() is not called prior to a - * sendmsg() call that initiates a new association, the - * system picks an ephemeral port and will choose an address - * set equivalent to binding with a wildcard address. + * API 3.1.2 bind() - UDP Style Syntax + * If a bind() or sctp_bindx() is not called prior to a + * sendmsg() call that initiates a new association, the + * system picks an ephemeral port and will choose an address + * set equivalent to binding with a wildcard address. */ - if (0 == ep->base.bind_addr.port) { + if (!ep->base.bind_addr.port) { if (sctp_autobind(sk)) { err = -EAGAIN; goto out_unlock; @@ -945,50 +907,48 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) } scope = sctp_scope(&to); - asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); - if (NULL == asoc) { - err = -ENOMEM; - goto out_unlock; - } + asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); + if (!asoc) { + err = -ENOMEM; + goto out_unlock; + } /* If the SCTP_INIT ancillary data is specified, set all - * the association init values accordingly. + * the association init values accordingly. */ - if (NULL != sinit) { - if (0 != sinit->sinit_num_ostreams) { - asoc->c.sinit_num_ostreams = + if (sinit) { + if (sinit->sinit_num_ostreams) { + asoc->c.sinit_num_ostreams = sinit->sinit_num_ostreams; } - if (0 != sinit->sinit_max_instreams) { - if (sinit->sinit_max_instreams <= + if (sinit->sinit_max_instreams) { + if (sinit->sinit_max_instreams <= SCTP_MAX_STREAM) { - asoc->c.sinit_max_instreams = - sinit->sinit_max_instreams; + asoc->c.sinit_max_instreams = + sinit->sinit_max_instreams; } else { - asoc->c.sinit_max_instreams = + asoc->c.sinit_max_instreams = SCTP_MAX_STREAM; } } - if (0 != sinit->sinit_max_attempts) { - asoc->max_init_attempts + if (sinit->sinit_max_attempts) { + asoc->max_init_attempts = sinit->sinit_max_attempts; } - if (0 != sinit->sinit_max_init_timeo) { + if (sinit->sinit_max_init_timeo) { asoc->max_init_timeo = sinit->sinit_max_init_timeo * HZ; - } } - /* Prime the peer's transport structures. */ + /* Prime the peer's transport structures. */ transport = sctp_assoc_add_peer(asoc, &to, GFP_KERNEL); - - } /* if (we need an association) */ + } - /* ASSERT: we have a valid association at this point. */ + /* ASSERT: we have a valid association at this point. */ SCTP_DEBUG_PRINTK("We have a valid association. \n"); - /* API 7.1.7, the sndbuf size per association bounds the + /* API 7.1.7, the sndbuf size per association bounds the * maximum size of data that can be sent in a single send call. */ if (msg_len > sk->sndbuf) { @@ -997,36 +957,36 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) } /* FIXME: In the current implementation, a single chunk is created - * for the entire message initially, even if it has to be fragmented - * later. As the length field in the chunkhdr is used to set - * the chunk length, the maximum size of the chunk and hence the - * message is limited by its type(uint16_t). + * for the entire message initially, even if it has to be fragmented + * later. As the length field in the chunkhdr is used to set + * the chunk length, the maximum size of the chunk and hence the + * message is limited by its type(__u16). * The real fix is to fragment the message before creating the chunks. */ - if (msg_len > ((uint16_t)(~(uint16_t)0) - - WORD_ROUND(sizeof(sctp_data_chunk_t)+1))) { + if (msg_len > ((__u16)(~(__u16)0) - + WORD_ROUND(sizeof(sctp_data_chunk_t)+1))) { err = -EMSGSIZE; goto out_free; } /* If fragmentation is disabled and the message length exceeds the * association fragmentation point, return EMSGSIZE. The I-D - * does not specify what this error is, but this looks like - * a great fit. - */ + * does not specify what this error is, but this looks like + * a great fit. + */ if (sctp_sk(sk)->disable_fragments && (msg_len > asoc->frag_point)) { err = -EMSGSIZE; goto out_free; - } - + } + if (sinfo) { /* Check for invalid stream. */ if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { - err = -EINVAL; - goto out_free; + err = -EINVAL; + goto out_free; } } else { - /* If the user didn't specify SNDRCVINFO, make up one with + /* If the user didn't specify SNDRCVINFO, make up one with * some defaults. */ default_sinfo.sinfo_stream = asoc->defaults.stream; @@ -1035,30 +995,26 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) } timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); - if (!sctp_wspace(asoc)) { err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); - if (err) { + if (err) goto out_free; - } } - /* Get enough memory for the whole message. */ - chunk = sctp_make_data_empty(asoc, sinfo, msg_len); - + /* Get enough memory for the whole message. */ + chunk = sctp_make_data_empty(asoc, sinfo, msg_len); if (!chunk) { err = -ENOMEM; goto out_free; } -#if 0 - /* FIXME: This looks wrong so I'll comment out. - * We should be able to use this same technique for +#if 0 + /* FIXME: This looks wrong so I'll comment out. + * We should be able to use this same technique for * primary address override! --jgrimm - */ - + */ /* If the user gave us an address, copy it in. */ - if (NULL != msg->msg_name) { + if (msg->msg_name) { chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); if (!chunk->transport) { err = -EINVAL; @@ -1067,70 +1023,64 @@ sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) } #endif /* 0 */ - /* Copy the message from the user. */ - err = sctp_user_addto_chunk(chunk, msg_len, msg->msg_iov); - - if (err < 0) { + /* Copy the message from the user. */ + err = sctp_user_addto_chunk(chunk, msg_len, msg->msg_iov); + if (err < 0) goto out_free; - } SCTP_DEBUG_PRINTK("Copied message to chunk: %p.\n", chunk); - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (uint8_t *)chunk->chunk_hdr - - (uint8_t *)chunk->skb->data); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); /* Do accounting for the write space. */ sctp_set_owner_w(chunk); - if (SCTP_STATE_CLOSED == asoc->state) { - err = sctp_primitive_ASSOCIATE(asoc, NULL); - if (err < 0) { + if (SCTP_STATE_CLOSED == asoc->state) { + err = sctp_primitive_ASSOCIATE(asoc, NULL); + if (err < 0) goto out_free; - } SCTP_DEBUG_PRINTK("We associated primitively.\n"); - } - + } - /* Send it to the lower layers. */ - err = sctp_primitive_SEND(asoc, chunk); + /* Send it to the lower layers. */ + err = sctp_primitive_SEND(asoc, chunk); SCTP_DEBUG_PRINTK("We sent primitively.\n"); /* BUG: SCTP_CHECK_TIMER(sk); */ - if (0 == err) { - err = msg_len; + if (!err) { + err = msg_len; goto out_unlock; - } - + } + out_free: - if (SCTP_STATE_CLOSED == asoc->state) { + if (SCTP_STATE_CLOSED == asoc->state) sctp_association_free(asoc); - } - if (chunk) { + if (chunk) sctp_free_chunk(chunk); - } + out_unlock: - sctp_release_sock(sk); + sctp_release_sock(sk); + out_nounlock: return err; - + #if 0 do_sock_err: - if (msg_len) { + if (msg_len) err = msg_len; - } else { + else err = sock_error(sk); - } goto out; + do_interrupted: - if (msg_len) { + if (msg_len) err = msg_len; - } goto out; #endif /* 0 */ - -} /* sctp_sendmsg() */ +} /* API 3.1.3 recvmsg() - UDP Style Syntax * @@ -1142,26 +1092,23 @@ do_interrupted: * user message and possibly some ancillary data. * * See Section 5 for complete description of the data - * structures. + * structures. * * flags - flags sent or received with the user message, see Section - * 5 for complete description of the flags. - * + * 5 for complete description of the flags. */ - -int -sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, - int flags, int *addr_len) +int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, + int flags, int *addr_len) { sctp_ulpevent_t *event = NULL; struct sk_buff *skb; int copied; - int err = 0; + int err = 0; SCTP_DEBUG_PRINTK("sctp_recvmsg(" "%s: %p, %s: %p, %s: %d, %s: %d, %s: " "0x%x, %s: %p)\n", - "sk", sk, + "sk", sk, "msghdr", msg, "len", len, "knoblauch", noblock, @@ -1170,56 +1117,52 @@ sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, sctp_lock_sock(sk); skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); - if (!skb){ + if (!skb) goto out; - } - + copied = skb->len; if (skb_shinfo(skb)->frag_list) { struct sk_buff *list; - for (list = skb_shinfo(skb)->frag_list; list; - list=list->next){ + for (list = skb_shinfo(skb)->frag_list; + list; + list = list->next) copied += list->len; - } } if (copied > len) { copied = len; msg->msg_flags |= MSG_TRUNC; - } + } err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - event = (sctp_ulpevent_t *)skb->cb; + event = (sctp_ulpevent_t *) skb->cb; + + if (err) + goto out_free; - if (err) { goto out_free; } - sock_recv_timestamp(msg, sk, skb); - if (sctp_ulpevent_is_notification(event)) { msg->msg_flags |= MSG_NOTIFICATION; } else { - /* Copy the address. */ - if (addr_len && msg->msg_name) { - sctp_sk_memcpy_msgname(sk, msg->msg_name, + /* Copy the address. */ + if (addr_len && msg->msg_name) + sctp_sk_memcpy_msgname(sk, msg->msg_name, addr_len, skb); - } - } - + /* Check if we allow SCTP_SNDRCVINFO. */ - if (sctp_sk(sk)->subscribe.sctp_data_io_event) { + if (sctp_sk(sk)->subscribe.sctp_data_io_event) sctp_ulpevent_read_sndrcvinfo(event, msg); - } - + #if 0 - /* FIXME: we should be calling IP layer too. */ + /* FIXME: we should be calling IP layer too. */ if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); -#endif - +#endif + err = copied; /* FIXME: We need to support MSG_EOR correctly. */ @@ -1230,204 +1173,179 @@ out_free: out: sctp_release_sock(sk); return err; +} -} /* sctp_recvmsg() */ - -static inline int -sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) +static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) { int val; - if (optlen < sizeof(int)) { + if (optlen < sizeof(int)) return -EINVAL; - } - if (get_user(val, (int *)optval)) { + if (get_user(val, (int *)optval)) return -EFAULT; - } sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1; return 0; +} -} /* sctp_setsockopt_disable_fragments() */ - -static inline int -sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) +static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) { - if (optlen != sizeof(struct sctp_event_subscribe)) { + if (optlen != sizeof(struct sctp_event_subscribe)) return -EINVAL; - } - - if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) { + if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) return -EFAULT; - } - return 0; +} -} /* sctp_setsockopt_set_events() */ - -static inline int -sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) +static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) { sctp_opt_t *sp = sctp_sk(sk); - if (optlen != sizeof(int)) { + if (optlen != sizeof(int)) return -EINVAL; - } - - if (copy_from_user(&sp->autoclose, optval, optlen)) { + if (copy_from_user(&sp->autoclose, optval, optlen)) return -EFAULT; - } - - sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; + sp->ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; return 0; - -} /* sctp_setsockopt_autoclose() */ +} /* API 6.2 setsockopt(), getsockopt() - * + * * Applications use setsockopt() and getsockopt() to set or retrieve * socket options. Socket options are used to change the default * behavior of sockets calls. They are described in Section 7. - * + * * The syntax is: - * + * * ret = getsockopt(int sd, int level, int optname, void *optval, - * int *optlen); + * int *optlen); * ret = setsockopt(int sd, int level, int optname, const void *optval, * int optlen); - * + * * sd - the socket descript. * level - set to IPPROTO_SCTP for all SCTP options. * optname - the option name. * optval - the buffer to store the value of the option. * optlen - the size of the buffer. - * */ -int -sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, - int optlen) +int sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, + int optlen) { - int retval = 0; - char * tmp; - sctp_protocol_t *proto = sctp_get_protocol(); + int retval = 0; + char * tmp; + sctp_protocol_t *proto = sctp_get_protocol(); list_t *pos; sctp_func_t *af; - - SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", + SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", sk, optname); - /* I can hardly begin to describe how wrong this is. This is - * so broken as to be worse than useless. The API draft - * REALLY is NOT helpful here... I am not convinced that the - * semantics of setsockopt() with a level OTHER THAN SOL_SCTP - * are at all well-founded. - */ + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of setsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ if (level != SOL_SCTP) { list_for_each(pos, &proto->address_families) { af = list_entry(pos, sctp_func_t, list); - retval = af->setsockopt(sk, level, optname, optval, + retval = af->setsockopt(sk, level, optname, optval, optlen); - if (retval < 0) { goto out_nounlock; } - } - } - - sctp_lock_sock(sk); + if (retval < 0) + goto out_nounlock; + } + } - switch (optname) { - case SCTP_SOCKOPT_DEBUG_NAME: + sctp_lock_sock(sk); + switch (optname) { + case SCTP_SOCKOPT_DEBUG_NAME: /* BUG! we don't ever seem to free this memory. --jgrimm */ - if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { - retval = -ENOMEM; - goto out_unlock; - } - - if (copy_from_user(tmp, optval, optlen)) { - retval = -EFAULT; - goto out_unlock; - } - tmp[optlen] = '\000'; - sctp_sk(sk)->ep->debug_name = tmp; - break; - case SCTP_SOCKOPT_BINDX_ADD: - /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { + retval = -ENOMEM; + goto out_unlock; + } + + if (copy_from_user(tmp, optval, optlen)) { + retval = -EFAULT; + goto out_unlock; + } + tmp[optlen] = '\000'; + sctp_sk(sk)->ep->debug_name = tmp; + break; + + case SCTP_SOCKOPT_BINDX_ADD: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) optval, optlen, BINDX_ADD_ADDR); - break; - case SCTP_SOCKOPT_BINDX_REM: - /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) + break; + + case SCTP_SOCKOPT_BINDX_REM: + /* 'optlen' is the size of the addresses buffer. */ + retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) optval, optlen, BINDX_REM_ADDR); - break; + break; + case SCTP_DISABLE_FRAGMENTS: retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); break; + case SCTP_SET_EVENTS: retval = sctp_setsockopt_set_events(sk, optval, optlen); break; + case SCTP_AUTOCLOSE: retval = sctp_setsockopt_autoclose(sk, optval, optlen); break; + default: retval = -ENOPROTOOPT; break; - } /* switch(optname) */ - - out_unlock: - sctp_release_sock(sk); - out_nounlock: - return retval; + }; -} /* sctp_setsockopt() */ +out_unlock: + sctp_release_sock(sk); +out_nounlock: + return retval; +} /* FIXME: Write comments. */ -int -sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - return -EOPNOTSUPP; /* STUB */ - -} /* sctp_connect() */ + return -EOPNOTSUPP; /* STUB */ +} /* FIXME: Write comments. */ -int -sctp_disconnect(struct sock *sk, int flags) +int sctp_disconnect(struct sock *sk, int flags) { - return -EOPNOTSUPP; /* STUB */ - -} /* sctp_disconnect() */ - + return -EOPNOTSUPP; /* STUB */ +} /* FIXME: Write comments. */ -struct sock * -sctp_accept(struct sock *sk, int flags, int *err) +struct sock *sctp_accept(struct sock *sk, int flags, int *err) { - int error = -EOPNOTSUPP; + int error = -EOPNOTSUPP; *err = error; return NULL; - -} /* sctp_accept() */ +} /* FIXME: Write Comments. */ -int -sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) +int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - return -EOPNOTSUPP; /* STUB */ - -} /* sctp_ioctl() */ + return -EOPNOTSUPP; /* STUB */ +} /* This is the function which gets called during socket creation to - * initialized the SCTP-specific portion of the sock. + * initialized the SCTP-specific portion of the sock. * The sock structure should already be zero-filled memory. */ -int -sctp_init_sock(struct sock *sk) +int sctp_init_sock(struct sock *sk) { sctp_endpoint_t *ep; sctp_protocol_t *proto; @@ -1437,24 +1355,24 @@ sctp_init_sock(struct sock *sk) proto = sctp_get_protocol(); - /* Create a per socket endpoint structure. Even if we + /* Create a per socket endpoint structure. Even if we * change the data structure relationships, this may still * be useful for storing pre-connect address information. */ ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); - - if (NULL == ep) { return -ENOMEM; } - - sp = sctp_sk(sk); + if (!ep) + return -ENOMEM; + + sp = sctp_sk(sk); - /* Initialize the SCTP per socket area. */ + /* Initialize the SCTP per socket area. */ - sp->ep = ep; + sp->ep = ep; sp->type = SCTP_SOCKET_UDP; /* FIXME: The next draft (04) of the SCTP Sockets Extensions - * should include a socket option for manipulating these - * message parameters (and a few others). + * should include a socket option for manipulating these + * message parameters (and a few others). */ sp->default_stream = 0; sp->default_ppid = 0; @@ -1465,82 +1383,75 @@ sctp_init_sock(struct sock *sk) */ sp->initmsg.sinit_num_ostreams = proto->max_outstreams; sp->initmsg.sinit_max_instreams = proto->max_instreams; - sp->initmsg.sinit_max_attempts = proto->max_retrans_init; + sp->initmsg.sinit_max_attempts = proto->max_retrans_init; sp->initmsg.sinit_max_init_timeo = proto->rto_max / HZ; /* Initialize default RTO related parameters. These parameters can * be modified for with the SCTP_RTOINFO socket option. - * FIXME: This are not used yet. + * FIXME: This are not used yet. */ sp->rtoinfo.srto_initial = proto->rto_initial; sp->rtoinfo.srto_max = proto->rto_max; sp->rtoinfo.srto_min = proto->rto_min; - /* Initialize default event subscriptions. + /* Initialize default event subscriptions. * the struct sock is initialized to zero, so only * enable the events needed. By default, UDP-style * sockets enable io and association change notifications. */ - if (SCTP_SOCKET_UDP == sp->type) { + if (SCTP_SOCKET_UDP == sp->type) { sp->subscribe.sctp_data_io_event = 1; sp->subscribe.sctp_association_event = 1; - } + } /* Default Peer Address Parameters. These defaults can * be modified via SCTP_SET_PEER_ADDR_PARAMS - */ + */ sp->paddrparam.spp_hbinterval = proto->hb_interval / HZ; - sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; - + sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; /* If enabled no SCTP message fragmentation will be performed. * Configure through SCTP_DISABLE_FRAGMENTS socket option. */ sp->disable_fragments = 0; - - /* Turn on/off any Nagle-like algorithm. */ + + /* Turn on/off any Nagle-like algorithm. */ sp->nodelay = 0; - /* Auto-close idle associations after the configured + /* Auto-close idle associations after the configured * number of seconds. A value of 0 disables this - * feature. Configure through the SCTP_AUTOCLOSE socket option, - * for UDP-style sockets only. + * feature. Configure through the SCTP_AUTOCLOSE socket option, + * for UDP-style sockets only. */ sp->autoclose = 0; SCTP_DBG_OBJCNT_INC(sock); - return 0; - -} /* sctp_init_sock() */ + return 0; +} -/* Cleanup any SCTP per socket resources. */ -int -sctp_destroy_sock(struct sock *sk) +/* Cleanup any SCTP per socket resources. */ +int sctp_destroy_sock(struct sock *sk) { - sctp_endpoint_t *ep; - SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); + SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); /* Release our hold on the endpoint. */ ep = sctp_sk(sk)->ep; - sctp_endpoint_free(ep); - - return 0; - -} /* sctp_destroy_sock() */ + sctp_endpoint_free(ep); + return 0; +} -/* FIXME: Comments needed. */ +/* FIXME: Comments needed. */ void sctp_shutdown(struct sock *sk, int how) { /* UDP-style sockets do not support shutdown. */ - /* STUB */ -} /* sctp_shutdown() */ + /* STUB */ +} -static int -sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, - int *optlen) +static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, + int *optlen) { struct sctp_status status; sctp_endpoint_t *ep; @@ -1551,12 +1462,12 @@ sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, if (len != sizeof(status)) { retval = -EINVAL; - goto out_nounlock; + goto out_nounlock; } if (copy_from_user(&status, optval, sizeof(status))) { retval = -EFAULT; - goto out_nounlock; + goto out_nounlock; } sctp_lock_sock(sk); @@ -1566,15 +1477,15 @@ sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, assoc = sctp_id2assoc(sk, associd); if (!assoc) { retval = -EINVAL; - goto out_unlock; + goto out_unlock; } - } else { + } else { ep = sctp_sk(sk)->ep; if (list_empty(&ep->asocs)) { retval = -EINVAL; - goto out_unlock; + goto out_unlock; } - + assoc = list_entry(ep->asocs.next, sctp_association_t, asocs); } @@ -1589,8 +1500,8 @@ sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_outstrms = assoc->c.sinit_num_ostreams; status.sstat_fragmentation_point = assoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); - memcpy(&status.sstat_primary.spinfo_address, - &(transport->ipaddr), sizeof(sockaddr_storage_t)); + memcpy(&status.sstat_primary.spinfo_address, + &(transport->ipaddr), sizeof(sockaddr_storage_t)); status.sstat_primary.spinfo_state = transport->state.active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; @@ -1602,8 +1513,8 @@ sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, goto out_unlock; } - SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", - len, status.sstat_state, status.sstat_rwnd, + SCTP_DEBUG_PRINTK("sctp_getsockopt_sctp_status(%d): %d %d %p\n", + len, status.sstat_state, status.sstat_rwnd, status.sstat_assoc_id); if (copy_to_user(optval, &status, len)) { @@ -1612,72 +1523,49 @@ sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, } out_unlock: - sctp_release_sock(sk); + sctp_release_sock(sk); + out_nounlock: return (retval); +} -} /* sctp_getsockopt_sctp_status() */ - -static inline int -sctp_getsockopt_disable_fragments(struct sock *sk, int len, - char *optval, int *optlen) +static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, + char *optval, int *optlen) { int val; - if (len < sizeof(int)) { + if (len < sizeof(int)) return -EINVAL; - } len = sizeof(int); - - val = (sctp_sk(sk)->disable_fragments == 1); - - if (put_user(len, optlen)) { + val = (sctp_sk(sk)->disable_fragments == 1); + if (put_user(len, optlen)) return -EFAULT; - } - - if (copy_to_user(optval, &val, len)) { + if (copy_to_user(optval, &val, len)) return -EFAULT; - } - - return (0); - -} /* sctp_getsockopt_disable_fragments() */ + return 0; +} -static inline int -sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) { - if (len != sizeof(struct sctp_event_subscribe)) { + if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; - } - - if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) { + if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) return -EFAULT; - } - return 0; +} -} /* sctp_getsockopt_set_events() */ - -static inline int -sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) +static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) { - if (len != sizeof(int)) { + if (len != sizeof(int)) return -EINVAL; - } - - if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) { + if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) return -EFAULT; - } - return 0; - -} /* sctp_getsockopt_autoclose() */ - +} /* Helper routine to branch off an association to a new socket. */ -int -sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) { struct sock *oldsk = assoc->base.sk; struct sock *newsk; @@ -1687,37 +1575,35 @@ sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) sctp_opt_t *newsp; int err = 0; - /* An association cannot be branched off from an already peeled-off - * socket. + /* An association cannot be branched off from an already peeled-off + * socket. */ - if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type) { + if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type) return -EINVAL; - } - /* Create a new socket. */ + /* Create a new socket. */ err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock); - if (err < 0) { - return (err); - } + if (err < 0) + return err; newsk = tmpsock->sk; newsp = sctp_sk(newsk); newep = newsp->ep; - /* Migrate socket buffer sizes and all the socket level options to the - * new socket. - */ + /* Migrate socket buffer sizes and all the socket level options to the + * new socket. + */ newsk->sndbuf = oldsk->sndbuf; newsk->rcvbuf = oldsk->rcvbuf; *newsp = *oldsp; /* Restore the ep value that was overwritten with the above structure - * copy. + * copy. */ newsp->ep = newep; /* Set the type of socket to indicate that it is peeled off from the - * original socket. + * original socket. */ newsp->type = SCTP_SOCKET_UDP_HIGH_BANDWIDTH; @@ -1726,123 +1612,117 @@ sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) *newsock = tmpsock; - return (err); - -} /* sctp_do_peeloff() */ + return err; +} -static inline int -sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) +static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) { sctp_peeloff_arg_t peeloff; struct socket *newsock; int err, sd; sctp_association_t *assoc; - if (len != sizeof(sctp_peeloff_arg_t)) { + if (len != sizeof(sctp_peeloff_arg_t)) return -EINVAL; - } - - if (copy_from_user(&peeloff, optval, len)) { + if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - } - assoc = sctp_id2assoc(sk, peeloff.associd); - if (NULL == assoc) { + if (NULL == assoc) return -EINVAL; - } SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); err = sctp_do_peeloff(assoc, &newsock); - if (err < 0) { - return (err); - } + if (err < 0) + return err; - /* Map the socket to an unused fd that can be returned to the user. */ - sd = sock_map_fd(newsock); + /* Map the socket to an unused fd that can be returned to the user. */ + sd = sock_map_fd(newsock); if (sd < 0) { sock_release(newsock); - return (sd); + return sd; } - SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", + SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", __FUNCTION__, sk, assoc, newsock->sk, sd); - /* Return the fd mapped to the new socket. */ + /* Return the fd mapped to the new socket. */ peeloff.sd = sd; - if (copy_to_user(optval, &peeloff, len)) { + if (copy_to_user(optval, &peeloff, len)) return -EFAULT; - } return 0; +} -} /* sctp_getsockopt_peeloff() */ - -int -sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, - int *optlen) +int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, + int *optlen) { - int retval = 0; - sctp_protocol_t *proto = sctp_get_protocol(); - sctp_func_t *af; + int retval = 0; + sctp_protocol_t *proto = sctp_get_protocol(); + sctp_func_t *af; list_t *pos; int len; - + SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); - /* I can hardly begin to describe how wrong this is. This is - * so broken as to be worse than useless. The API draft - * REALLY is NOT helpful here... I am not convinced that the - * semantics of getsockopt() with a level OTHER THAN SOL_SCTP - * are at all well-founded. - */ + /* I can hardly begin to describe how wrong this is. This is + * so broken as to be worse than useless. The API draft + * REALLY is NOT helpful here... I am not convinced that the + * semantics of getsockopt() with a level OTHER THAN SOL_SCTP + * are at all well-founded. + */ if (level != SOL_SCTP) { list_for_each(pos, &proto->address_families) { af = list_entry(pos, sctp_func_t, list); - - retval = af->getsockopt(sk, level, optname, + retval = af->getsockopt(sk, level, optname, optval, optlen); - if (retval < 0) { return retval; } - } - } + if (retval < 0) + return retval; + } + } - if (get_user(len, optlen)) { return -EFAULT;} + if (get_user(len, optlen)) + return -EFAULT; switch (optname) { case SCTP_STATUS: retval = sctp_getsockopt_sctp_status(sk, len, optval, optlen); break; + case SCTP_DISABLE_FRAGMENTS: retval = sctp_getsockopt_disable_fragments(sk, len, optval, optlen); break; + case SCTP_SET_EVENTS: retval = sctp_getsockopt_set_events(sk, len, optval, optlen); break; + case SCTP_AUTOCLOSE: retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); break; + case SCTP_SOCKOPT_PEELOFF: retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; + default: retval = -ENOPROTOOPT; break; - } + }; - return retval; - -} /* sctp_getsockopt() */ + return retval; +} void sctp_hash(struct sock *sk) { - /* STUB */ -} /* void sctp_hash(struct sock *sk) */ + /* STUB */ +} void sctp_unhash(struct sock *sk) { - /* STUB */ -} /* void sctp_unhash(struct sock *sk) */ + /* STUB */ +} /* Check if port is acceptable. Possibly find first available port. * @@ -1856,8 +1736,7 @@ void sctp_unhash(struct sock *sk) * link to the socket (struct sock) that uses it, the port number and * a fastreuse flag (FIXME: NPI ipg). */ - -int sctp_get_port(struct sock *sk, unsigned short snum) +long sctp_get_port(struct sock *sk, unsigned short snum) { sctp_bind_hashbucket_t *head; /* hash list */ sctp_bind_bucket_t *pp; /* hash list port iterator */ @@ -1869,7 +1748,6 @@ int sctp_get_port(struct sock *sk, unsigned short snum) sctp_local_bh_disable(); if (snum == 0) { - /* Search for an available port. * * 'sctp->port_rover' was the last port assigned, so @@ -1878,13 +1756,12 @@ int sctp_get_port(struct sock *sk, unsigned short snum) * already in the hash table; if not, we use that; if * it is, we try next. */ - int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; int rover; int index; - + sctp_spin_lock(&sctp->port_alloc_lock); rover = sctp->port_rover; do { @@ -1906,9 +1783,8 @@ int sctp_get_port(struct sock *sk, unsigned short snum) /* Exhausted local port range during search? */ ret = 1; - if (remaining <= 0) { + if (remaining <= 0) goto fail; - } /* OK, here is the one we will use. HEAD (the port * hash table list entry) is non-NULL and we hold it's @@ -1916,9 +1792,7 @@ int sctp_get_port(struct sock *sk, unsigned short snum) */ snum = rover; pp = NULL; - } else { - /* We are given an specific port number; we verify * that it is not being used. If it is used, we will * exahust the search in the hash list corresponding @@ -1928,50 +1802,47 @@ int sctp_get_port(struct sock *sk, unsigned short snum) head = &sctp->port_hashtable[sctp_phashfn(snum)]; sctp_spin_lock(&head->lock); for (pp = head->chain; pp; pp = pp->next) { - if (pp->port == snum) { + if (pp->port == snum) break; - } } } if (pp != NULL && pp->sk != NULL) { - /* We had a port hash table hit - there is an * available port (pp != NULL) and it is being * used by other socket (pp->sk != NULL); that other - * socket is going to be sk2. + * socket is going to be sk2. */ - int sk_reuse = sk->reuse; sockaddr_storage_t tmpaddr; struct sock *sk2 = pp->sk; SCTP_DEBUG_PRINTK("sctp_get_port() found a " "possible match\n"); - if (pp->fastreuse != 0 && sk->reuse != 0) { + if (pp->fastreuse != 0 && sk->reuse != 0) goto success; - } /* FIXME - multiple addresses need to be supported * later. - */ - + */ switch (sk->family) { case PF_INET: tmpaddr.v4.sin_family = AF_INET; tmpaddr.v4.sin_port = snum; tmpaddr.v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; break; + case PF_INET6: SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; tmpaddr.v6.sin6_port = snum; - tmpaddr.v6.sin6_addr - = inet6_sk(sk)->rcv_saddr; + tmpaddr.v6.sin6_addr = + inet6_sk(sk)->rcv_saddr; ) break; + default: break; - } + }; /* Run through the list of sockets bound to the port * (pp->port) [via the pointers bind_next and @@ -1981,7 +1852,7 @@ int sctp_get_port(struct sock *sk, unsigned short snum) * comparing each of the addresses with the address of * the socket sk. If we find a match, then that means * that this port/socket (sk) combination are already - * in an endpoint. + * in an endpoint. */ for( ; sk2 != NULL; sk2 = sk2->bind_next) { sctp_endpoint_t *ep2; @@ -1992,30 +1863,27 @@ int sctp_get_port(struct sock *sk, unsigned short snum) &ep2->base.bind_addr, &tmpaddr)) { goto found; } - - } /* if (neither socket slated for reuse) */ + } + } - } /* for (every socket in this port hash bucket) */ found: - - /* If we found a conflict, fail. */ + /* If we found a conflict, fail. */ if (sk2 != NULL) { - ret = (int)sk2; + ret = (long) sk2; goto fail_unlock; } SCTP_DEBUG_PRINTK("sctp_get_port(): Found a match\n"); - } /* if (we had a port hash-table hit) */ + } - /* If there was a hash table miss, create a new port. */ + /* If there was a hash table miss, create a new port. */ ret = 1; - if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) { + if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) goto fail_unlock; - } /* In either case (hit or miss), make sure fastreuse is 1 only * if sk->reuse is too (that is, if the caller requested - * SO_REUSEADDR on this socket -sk-). + * SO_REUSEADDR on this socket -sk-). */ if (pp->sk == NULL) { pp->fastreuse = sk->reuse? 1 : 0; @@ -2025,14 +1893,13 @@ int sctp_get_port(struct sock *sk, unsigned short snum) /* We are set, so fill up all the data in the hash table * entry, tie the socket list information with the rest of the - * sockets FIXME: Blurry, NPI (ipg). + * sockets FIXME: Blurry, NPI (ipg). */ success: inet_sk(sk)->num = snum; if (sk->prev == NULL) { - if ((sk->bind_next = pp->sk) != NULL) { + if ((sk->bind_next = pp->sk) != NULL) pp->sk->bind_pprev = &sk->bind_next; - } pp->sk = sk; sk->bind_pprev = &pp->sk; sk->prev = (struct sock *) pp; @@ -2041,14 +1908,13 @@ success: fail_unlock: sctp_spin_unlock(&head->lock); + fail: sctp_local_bh_enable(); SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret); return ret; - -} /* sctp_get_port() */ - +} /* * 3.1.3 listen() - UDP Style Syntax @@ -2056,46 +1922,39 @@ fail: * By default, new associations are not accepted for UDP style sockets. * An application uses listen() to mark a socket as being able to * accept new associations. - * */ int sctp_seqpacket_listen(struct sock *sk, int backlog) { sctp_opt_t *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; - /* Only UDP style sockets that are not peeled off are allowed to - * listen(). - */ - if (SCTP_SOCKET_UDP != sp->type) { - return (-EINVAL); - } + /* Only UDP style sockets that are not peeled off are allowed to + * listen(). + */ + if (SCTP_SOCKET_UDP != sp->type) + return -EINVAL; /* * If a bind() or sctp_bindx() is not called prior to a listen() - * call that allows new associations to be accepted, the system - * picks an ephemeral port and will choose an address set equivalent - * to binding with a wildcard address. + * call that allows new associations to be accepted, the system + * picks an ephemeral port and will choose an address set equivalent + * to binding with a wildcard address. * - * This is not currently spelled out in the SCTP sockets + * This is not currently spelled out in the SCTP sockets * extensions draft, but follows the practice as seen in TCP - * sockets. + * sockets. */ - if (0 == ep->base.bind_addr.port) { - if (sctp_autobind(sk)) { - return (-EAGAIN); - } + if (!ep->base.bind_addr.port) { + if (sctp_autobind(sk)) + return -EAGAIN; } - - sk->state = SCTP_SS_LISTENING; sctp_hash_endpoint(ep); - return 0; +} -} /* sctp_seqpacket_listen() */ - -/* - * Move a socket to LISTENING state. +/* + * Move a socket to LISTENING state. */ int sctp_inet_listen(struct socket *sock, int backlog) { @@ -2105,42 +1964,40 @@ int sctp_inet_listen(struct socket *sock, int backlog) sctp_lock_sock(sk); err = -EINVAL; - if (sock->state != SS_UNCONNECTED) { + if (sock->state != SS_UNCONNECTED) goto out; - } - switch (sock->type) { case SOCK_SEQPACKET: err = sctp_seqpacket_listen(sk, backlog); break; + case SOCK_STREAM: /* FIXME for TCP-style sockets. */ err = -EOPNOTSUPP; + default: goto out; - } + }; out: sctp_release_sock(sk); return err; +} -} /* sctp_inet_listen() */ - -/* - * This function is done by modeling the current datagram_poll() and the - * tcp_poll(). Note that, based on these implementations, we don't - * lock the socket in this function, even though it seems that, - * ideally, locking or some other mechanisms can be used to ensure - * the integrity of the counters (sndbuf and wmem_queued) used +/* + * This function is done by modeling the current datagram_poll() and the + * tcp_poll(). Note that, based on these implementations, we don't + * lock the socket in this function, even though it seems that, + * ideally, locking or some other mechanisms can be used to ensure + * the integrity of the counters (sndbuf and wmem_queued) used * in this place. We assume that we don't need locks either until proven - * otherwise. - * - * Another thing to note is that we include the Async I/O support - * here, again, by modeling the current TCP/UDP code. We don't have - * a good way to test with it yet. + * otherwise. + * + * Another thing to note is that we include the Async I/O support + * here, again, by modeling the current TCP/UDP code. We don't have + * a good way to test with it yet. */ -unsigned int -sctp_poll(struct file *file, struct socket *sock, poll_table *wait) +unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask; @@ -2148,55 +2005,47 @@ sctp_poll(struct file *file, struct socket *sock, poll_table *wait) poll_wait(file, sk->sleep, wait); mask = 0; - /* Is there any exceptional events? */ - if (sk->err || !skb_queue_empty(&sk->error_queue)) { + /* Is there any exceptional events? */ + if (sk->err || !skb_queue_empty(&sk->error_queue)) mask |= POLLERR; - } - if (sk->shutdown == SHUTDOWN_MASK) { + if (sk->shutdown == SHUTDOWN_MASK) mask |= POLLHUP; - } /* Is it readable? Reconsider this code with TCP-style support. */ - if (!skb_queue_empty(&sk->receive_queue) - || (sk->shutdown & RCV_SHUTDOWN)) { + if (!skb_queue_empty(&sk->receive_queue) || + (sk->shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - } /* * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and * peeled off sockets. Additionally, TCP-style needs to consider - * other establishment conditions. + * other establishment conditions. */ if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { /* The association is going away. */ - if (SCTP_SS_DISCONNECTING == sk->state) { + if (SCTP_SS_DISCONNECTING == sk->state) mask |= POLLHUP; - } /* The association is either gone or not ready. */ - if (SCTP_SS_CLOSED == sk->state) { + if (SCTP_SS_CLOSED == sk->state) return mask; - } } - /* Is it writable? */ + /* Is it writable? */ if (sctp_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - /* - * Since the socket is not locked, the buffer - * might be made available after the writeable check and - * before the bit is set. This could cause a lost I/O + /* + * Since the socket is not locked, the buffer + * might be made available after the writeable check and + * before the bit is set. This could cause a lost I/O * signal. tcp_poll() has a race breaker for this race - * condition. Based on their implementation, we put + * condition. Based on their implementation, we put * in the following code to cover it as well. */ - if (sctp_writeable(sk)) { + if (sctp_writeable(sk)) mask |= POLLOUT | POLLWRNORM; - } } - - return mask; } @@ -2204,15 +2053,13 @@ sctp_poll(struct file *file, struct socket *sock, poll_table *wait) * 2nd Level Abstractions ********************************************************************/ - -static sctp_bind_bucket_t * -sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) +static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) { sctp_bind_bucket_t *pp; SCTP_DEBUG_PRINTK( "sctp_bucket_create() begins, snum=%d\n", snum); pp = kmalloc(sizeof(sctp_bind_bucket_t), GFP_ATOMIC); - if (pp != NULL) { + if (pp) { pp->port = snum; pp->fastreuse = 0; pp->sk = NULL; @@ -2220,17 +2067,16 @@ sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) pp->next->pprev = &pp->next; head->chain= pp; pp->pprev = &head->chain; - } + } SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); return pp; - -} /* sctp_bucket_create() */ +} /* FIXME: Commments! */ __inline__ void __sctp_put_port(struct sock *sk) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); - sctp_bind_hashbucket_t *head = + sctp_bind_hashbucket_t *head = &sctp_proto->port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; sctp_bind_bucket_t *pp; @@ -2241,77 +2087,73 @@ __inline__ void __sctp_put_port(struct sock *sk) *(sk->bind_pprev) = sk->bind_next; sk->prev = NULL; inet_sk(sk)->num = 0; - if (pp->sk == NULL) { + if (pp->sk) { if (pp->next) pp->next->pprev = pp->pprev; *(pp->pprev) = pp->next; kfree(pp); } sctp_spin_unlock(&head->lock); +} -} /* __sctp_put_port() */ - -void -sctp_put_port(struct sock *sk) +void sctp_put_port(struct sock *sk) { sctp_local_bh_disable(); __sctp_put_port(sk); sctp_local_bh_enable(); - -} /* sctp_put_port() */ +} /* - * The system picks an ephemeral port and choose an address set equivalent - * to binding with a wildcard address. - * One of those addresses will be the primary address for the association. + * The system picks an ephemeral port and choose an address set equivalent + * to binding with a wildcard address. + * One of those addresses will be the primary address for the association. * This automatically enables the multihoming capability of SCTP. */ -int -sctp_autobind(struct sock *sk) +int sctp_autobind(struct sock *sk) { sockaddr_storage_t autoaddr; - int addr_len=0; + int addr_len = 0; memset(&autoaddr, 0, sizeof(sockaddr_storage_t)); - - switch(sk->family){ + + switch (sk->family) { case PF_INET: - autoaddr.v4.sin_family = AF_INET; - autoaddr.v4.sin_addr.s_addr = INADDR_ANY; - autoaddr.v4.sin_port = htons(inet_sk(sk)->num); + autoaddr.v4.sin_family = AF_INET; + autoaddr.v4.sin_addr.s_addr = INADDR_ANY; + autoaddr.v4.sin_port = htons(inet_sk(sk)->num); addr_len = sizeof(struct sockaddr_in); break; + case PF_INET6: SCTP_V6( - /* FIXME: Write me for v6! */ - BUG(); + /* FIXME: Write me for v6! */ + BUG(); autoaddr.v6.sin6_family = AF_INET6; autoaddr.v6.sin6_port = htons(inet_sk(sk)->num); addr_len = sizeof(struct sockaddr_in6); ); break; - default: /* This should not happen. */ + + default: /* This should not happen. */ break; - } /* switch(family) */ + }; return sctp_do_bind(sk, &autoaddr, addr_len); - -} /* sctp_autobind() */ - +} /* Parse out IPPROTO_SCTP CMSG headers. Perform only minimal validation. - * + * * From RFC 2292 * 4.2 The cmsghdr Structure * * - * When ancillary data is sent or received, any number of ancillary data - * objects can be specified by the msg_control and msg_controllen members of + * When ancillary data is sent or received, any number of ancillary data + * objects can be specified by the msg_control and msg_controllen members of * the msghdr structure, because each object is preceded by - * a cmsghdr structure defining the object's length (the cmsg_len member). - * Historically Berkeley-derived implementations have passed only one object + * a cmsghdr structure defining the object's length (the cmsg_len member). + * Historically Berkeley-derived implementations have passed only one object * at a time, but this API allows multiple objects to be - * passed in a single call to sendmsg() or recvmsg(). The following example - * shows two ancillary data objects in a control buffer. + * passed in a single call to sendmsg() or recvmsg(). The following example + * shows two ancillary data objects in a control buffer. * * |<--------------------------- msg_controllen -------------------------->| * | | @@ -2337,39 +2179,34 @@ sctp_autobind(struct sock *sk) * * msg_control * points here - * */ -int -sctp_msghdr_parse(const struct msghdr *msg, - sctp_cmsgs_t *cmsgs) +int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) { struct cmsghdr *cmsg; - for (cmsg = CMSG_FIRSTHDR(msg); - cmsg != NULL; + for (cmsg = CMSG_FIRSTHDR(msg); + cmsg != NULL; cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { - - /* Check for minimum length. The SCM code has this check. */ + /* Check for minimum length. The SCM code has this check. */ if (cmsg->cmsg_len < sizeof(struct cmsghdr) || (unsigned long)(((char*)cmsg - (char*)msg->msg_control) + cmsg->cmsg_len) > msg->msg_controllen) { return -EINVAL; } - /* Should we parse this header or ignore? */ - if (cmsg->cmsg_level != IPPROTO_SCTP) { + /* Should we parse this header or ignore? */ + if (cmsg->cmsg_level != IPPROTO_SCTP) continue; - } - /* Strictly check lengths following example in SCM code. */ + /* Strictly check lengths following example in SCM code. */ switch (cmsg->cmsg_type) { case SCTP_INIT: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension (draft 1) * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * - * This cmsghdr structure provides information for - * initializing new SCTP associations with sendmsg(). - * The SCTP_INITMSG socket option uses this same data + * This cmsghdr structure provides information for + * initializing new SCTP associations with sendmsg(). + * The SCTP_INITMSG socket option uses this same data * structure. This structure is not used for * recvmsg(). * @@ -2377,67 +2214,59 @@ sctp_msghdr_parse(const struct msghdr *msg, * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg */ - - if (cmsg->cmsg_len - != CMSG_LEN(sizeof(struct sctp_initmsg))) + if (cmsg->cmsg_len != + CMSG_LEN(sizeof(struct sctp_initmsg))) return -EINVAL; cmsgs->init = (struct sctp_initmsg *)CMSG_DATA(cmsg); - break; case SCTP_SNDRCV: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension (draft 1) * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * - * This cmsghdr structure specifies SCTP options for - * sendmsg() and describes SCTP header information + * This cmsghdr structure specifies SCTP options for + * sendmsg() and describes SCTP header information * about a received message through recvmsg(). * * cmsg_level cmsg_type cmsg_data[] * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo - */ - if (cmsg->cmsg_len - != CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) { + */ + if (cmsg->cmsg_len != + CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) return -EINVAL; - } - cmsgs->info = (struct sctp_sndrcvinfo*)CMSG_DATA(cmsg); + cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); /* Minimally, validate the sinfo_flags. */ - if (cmsgs->info->sinfo_flags - & ~(MSG_UNORDERED|MSG_ADDR_OVER - |MSG_ABORT|MSG_EOF)){ - + if (cmsgs->info->sinfo_flags & + ~(MSG_UNORDERED | MSG_ADDR_OVER | + MSG_ABORT | MSG_EOF)) return -EINVAL; - } - break; + default: return -EINVAL; - - } /* switch(cmsg_type) */ + }; } return 0; +} -} /* sctp_msghdr_parse()*/ - - -/* Setup sk->rcv_saddr before calling get_port(). */ -static inline void -sctp_sk_addr_set(struct sock *sk, - const sockaddr_storage_t *newaddr, - sockaddr_storage_t *saveaddr) +/* Setup sk->rcv_saddr before calling get_port(). */ +static inline void sctp_sk_addr_set(struct sock *sk, + const sockaddr_storage_t *newaddr, + sockaddr_storage_t *saveaddr) { struct inet_opt *inet = inet_sk(sk); saveaddr->sa.sa_family = newaddr->sa.sa_family; - switch(newaddr->sa.sa_family){ + switch (newaddr->sa.sa_family) { case AF_INET: saveaddr->v4.sin_addr.s_addr = inet->rcv_saddr; - inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr; - break; + inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr; + break; + case AF_INET6: SCTP_V6({ struct ipv6_pinfo *np = inet6_sk(sk); @@ -2446,23 +2275,22 @@ sctp_sk_addr_set(struct sock *sk, np->rcv_saddr = np->saddr = newaddr->v6.sin6_addr; break; }) + default: break; - } - -} /* sctp_sk_addr_store() */ - + }; +} -/* Restore sk->rcv_saddr after failing get_port(). */ -static inline void -sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) +/* Restore sk->rcv_saddr after failing get_port(). */ +static inline void sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) { struct inet_opt *inet = inet_sk(sk); - switch(addr->sa.sa_family){ + switch (addr->sa.sa_family) { case AF_INET: - inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr; - break; + inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr; + break; + case AF_INET6: SCTP_V6({ struct ipv6_pinfo *np = inet6_sk(sk); @@ -2470,22 +2298,20 @@ sctp_sk_addr_restore(struct sock *sk, const sockaddr_storage_t *addr) np->rcv_saddr = np->saddr = addr->v6.sin6_addr; break; }) + default: break; - } - -} /* sctp_sk_addr_restore() */ + }; +} /* * Wait for a packet.. * Note: This function is the same function as in core/datagram.c * with a few modifications to make lksctp work. */ -static int -sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) +static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) { int error; - DECLARE_WAITQUEUE(wait, current); __set_current_state(TASK_INTERRUPTIBLE); @@ -2493,39 +2319,34 @@ sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) /* Socket errors? */ error = sock_error(sk); - if (error) { + if (error) goto out; - } - if (!skb_queue_empty(&sk->receive_queue)) { + if (!skb_queue_empty(&sk->receive_queue)) goto ready; - } - /* Socket shut down? */ - if (sk->shutdown & RCV_SHUTDOWN) { + /* Socket shut down? */ + if (sk->shutdown & RCV_SHUTDOWN) goto out; - } - /* Sequenced packets can come disconnected. If so we report the + /* Sequenced packets can come disconnected. If so we report the * problem. */ error = -ENOTCONN; - /* Is there a good reason to think that we may receive some data? */ - if ((list_empty(&sctp_sk(sk)->ep->asocs)) - && (sk->state != SCTP_SS_LISTENING)) { + /* Is there a good reason to think that we may receive some data? */ + if ((list_empty(&sctp_sk(sk)->ep->asocs)) && + (sk->state != SCTP_SS_LISTENING)) goto out; - } /* Handle signals. */ - if (signal_pending(current)) { + if (signal_pending(current)) goto interrupted; - } - - /* Let another process have a go. Since we are going to sleep + + /* Let another process have a go. Since we are going to sleep * anyway. Note: This may cause odd behaviors if the message * does not fit in the user's buffer, but this seems to be the - * only way to honor MSG_DONTWAIT realistically. + * only way to honor MSG_DONTWAIT realistically. */ sctp_release_sock(sk); *timeo_p = schedule_timeout(*timeo_p); @@ -2538,31 +2359,28 @@ ready: interrupted: error = sock_intr_errno(*timeo_p); + out: remove_wait_queue(sk->sleep, &wait); __set_current_state(TASK_RUNNING); *err = error; return error; - -} /* sctp_wait_for_packet() */ - +} /* Receive a datagram. * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -struct sk_buff * -sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) { int error; struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + /* Caller is allowed not to check sk->err before skb_recv_datagram() */ error = sock_error(sk); - if (error) { + if (error) goto no_packet; - } timeo = sock_rcvtimeo(sk, noblock); @@ -2570,34 +2388,34 @@ sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) timeo, MAX_SCHEDULE_TIMEOUT); do { - /* Again only user level code calls this function, + /* Again only user level code calls this function, * so nothing interrupt level * will suddenly eat the receive_queue. - * + * * Look at current nfs client by the way... * However, this function was corrent in any case. 8) */ if (flags & MSG_PEEK) { unsigned long cpu_flags; - sctp_spin_lock_irqsave(&sk->receive_queue.lock, + sctp_spin_lock_irqsave(&sk->receive_queue.lock, cpu_flags); skb = skb_peek(&sk->receive_queue); - if (skb!=NULL) + if (skb) atomic_inc(&skb->users); - sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, + sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, cpu_flags); } else { skb = skb_dequeue(&sk->receive_queue); } - if (skb) { return skb; } + if (skb) + return skb; - /* User doesn't want to wait */ + /* User doesn't want to wait. */ error = -EAGAIN; if (!timeo) goto no_packet; - } while (sctp_wait_for_packet(sk, err, &timeo) == 0); return NULL; @@ -2605,146 +2423,124 @@ sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) no_packet: *err = error; return NULL; +} -} /* sctp_skb_recv_datagram() */ - - -/* Copy an approriately formatted address for msg_name. */ -static inline void -sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, int *addr_len, - struct sk_buff *skb) +/* Copy an approriately formatted address for msg_name. */ +static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, + int *addr_len, struct sk_buff *skb) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6 __attribute__ ((unused)); struct sctphdr *sh; - /* The sockets layer handles copying this out to user space. */ - + /* The sockets layer handles copying this out to user space. */ switch (sk->family) { case PF_INET: - sin = (struct sockaddr_in *)msgname; - if (addr_len) { + if (addr_len) *addr_len = sizeof(struct sockaddr_in); - } sin->sin_family = AF_INET; - - sh = (struct sctphdr *)skb->h.raw; + sh = (struct sctphdr *) skb->h.raw; sin->sin_port = sh->source; sin->sin_addr.s_addr = skb->nh.iph->saddr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); break; + case PF_INET6: SCTP_V6( - /* FIXME: Need v6 code here. We should convert - * V4 addresses to PF_INET6 format. See ipv6/udp.c + * V4 addresses to PF_INET6 format. See ipv6/udp.c * for an example. --jgrimm */ ); break; + default: /* Should not get here. */ break; - } - -} /* sctp_sk_memcpy_msgname() */ - + }; +} -static inline int -sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) +static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) { sockaddr_storage_t *sa; - if (msg->msg_namelen < sizeof (struct sockaddr) ) { + if (msg->msg_namelen < sizeof (struct sockaddr)) return -EINVAL; - } - sa = (sockaddr_storage_t *)(msg->msg_name); + + sa = (sockaddr_storage_t *) msg->msg_name; switch (sa->sa.sa_family) { case AF_INET: - if (msg->msg_namelen < sizeof(struct sockaddr_in)) { + if (msg->msg_namelen < sizeof(struct sockaddr_in)) return -EINVAL; - } break; + case AF_INET6: - if (PF_INET == sk->family) { + if (PF_INET == sk->family) return -EINVAL; - } - SCTP_V6( - if (msg->msg_namelen < sizeof(struct sockaddr_in6)) { + SCTP_V6( + if (msg->msg_namelen < sizeof(struct sockaddr_in6)) return -EINVAL; - } break; ); + default: return -EINVAL; - } + }; /* Disallow any illegal addresses to be used as destinations. */ - if (!sctp_addr_is_valid(sa)) { + if (!sctp_addr_is_valid(sa)) return -EINVAL; - } return 0; - -} /* sctp_sendmsg_verify_name() */ - +} /* Get the sndbuf space available at the time on the association. */ -static inline int -sctp_wspace(sctp_association_t *asoc) +static inline int sctp_wspace(sctp_association_t *asoc) { struct sock *sk = asoc->base.sk; int amt = 0; amt = sk->sndbuf - asoc->sndbuf_used; - if (amt < 0) { + if (amt < 0) amt = 0; - } return amt; - -} /* sctp_wspace() */ - +} /* Increment the used sndbuf space count of the corresponding association by * the size of the outgoing data chunk. - * Also, set the skb destructor for sndbuf accounting later. + * Also, set the skb destructor for sndbuf accounting later. * - * Since it is always 1-1 between chunk and skb, and also a new skb is always - * allocated for chunk bundling in sctp_packet_transmit(), we can use the + * Since it is always 1-1 between chunk and skb, and also a new skb is always + * allocated for chunk bundling in sctp_packet_transmit(), we can use the * destructor in the data chunk skb for the purpose of the sndbuf space - * tracking. + * tracking. */ -static inline void -sctp_set_owner_w(sctp_chunk_t *chunk) +static inline void sctp_set_owner_w(sctp_chunk_t *chunk) { sctp_association_t *asoc = chunk->asoc; struct sock *sk = asoc->base.sk; - - /* The sndbuf space is tracked per association. */ + /* The sndbuf space is tracked per association. */ sctp_association_hold(asoc); chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); - -} /* sctp_set_owner_w() */ +} /* Do accounting for the sndbuf space. * Decrement the used sndbuf space of the corresponding association by the * data size which was just transmitted(freed). */ -static void -sctp_wfree(struct sk_buff *skb) +static void sctp_wfree(struct sk_buff *skb) { sctp_association_t *asoc; sctp_chunk_t *chunk; struct sock *sk; - /* Get the saved chunk pointer. */ chunk = *((sctp_chunk_t **)(skb->cb)); asoc = chunk->asoc; @@ -2754,64 +2550,47 @@ sctp_wfree(struct sk_buff *skb) __sctp_write_space(asoc); sctp_association_put(asoc); +} -} /* sctp_wfree() */ - - -/* Helper function to wait for space in the sndbuf. */ -static int -sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len) +/* Helper function to wait for space in the sndbuf. */ +static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; DECLARE_WAITQUEUE(wait, current); - SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", + SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", asoc, (long)(*timeo_p), msg_len); - + /* Wait on the association specific sndbuf space. */ add_wait_queue_exclusive(&asoc->wait, &wait); /* Increment the association's refcnt. */ sctp_association_hold(asoc); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - - if (!*timeo_p) { + if (!*timeo_p) goto do_nonblock; - } - if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || - asoc->base.dead) { + asoc->base.dead) goto do_error; - } - - if (signal_pending(current)) { + if (signal_pending(current)) goto do_interrupted; - } - - if (msg_len <= sctp_wspace(asoc)) { + if (msg_len <= sctp_wspace(asoc)) break; - } - - /* Let another process have a go. Since we are going - * to sleep anyway. - */ + /* Let another process have a go. Since we are going + * to sleep anyway. + */ sctp_release_sock(sk); - current_timeo = schedule_timeout(current_timeo); - sctp_lock_sock(sk); - + *timeo_p = current_timeo; } out: - remove_wait_queue(&asoc->wait, &wait); /* Release the association's refcnt. */ @@ -2831,42 +2610,35 @@ do_interrupted: do_nonblock: err = -EAGAIN; goto out; +} -} /* sctp_wait_for_sndbuf() */ - - -/* If sndbuf has changed, wake up per association sndbuf waiters. */ -static void -__sctp_write_space(sctp_association_t *asoc) +/* If sndbuf has changed, wake up per association sndbuf waiters. */ +static void __sctp_write_space(sctp_association_t *asoc) { struct sock *sk = asoc->base.sk; struct socket *sock = sk->socket; - + if ((sctp_wspace(asoc) > 0) && sock) { - if (waitqueue_active(&asoc->wait)) { + if (waitqueue_active(&asoc->wait)) wake_up_interruptible(&asoc->wait); - } + if (sctp_writeable(sk)) { - if (sk->sleep && waitqueue_active(sk->sleep)) { + if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); - } - /* Note that we try to include the Async I/O support - * here by modeling from the current TCP/UDP code. - * We have not tested with it yet. + + /* Note that we try to include the Async I/O support + * here by modeling from the current TCP/UDP code. + * We have not tested with it yet. */ - if (sock->fasync_list - && !(sk->shutdown & SEND_SHUTDOWN)) { + if (sock->fasync_list && + !(sk->shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); - } } } +} -} /* __sctp_write_space() */ - - -/* If socket sndbuf has changed, wake up all per association waiters. */ -void -sctp_write_space(struct sock *sk) +/* If socket sndbuf has changed, wake up all per association waiters. */ +void sctp_write_space(struct sock *sk) { sctp_association_t *asoc; list_t *pos; @@ -2876,52 +2648,47 @@ sctp_write_space(struct sock *sk) asoc = list_entry(pos, sctp_association_t, asocs); __sctp_write_space(asoc); } - -} /* sctp_write_space() */ +} /* Is there any sndbuf space available on the socket? - * - * Note that wmem_queued is the sum of the send buffers on all of the - * associations on the same socket. For a UDP-style socket with - * multiple associations, it is possible for it to be "unwriteable" + * + * Note that wmem_queued is the sum of the send buffers on all of the + * associations on the same socket. For a UDP-style socket with + * multiple associations, it is possible for it to be "unwriteable" * prematurely. I assume that this is acceptable because - * a premature "unwriteable" is better than an accidental "writeable" which - * would cause an unwanted block under certain circumstances. For the 1-1 + * a premature "unwriteable" is better than an accidental "writeable" which + * would cause an unwanted block under certain circumstances. For the 1-1 * UDP-style sockets or TCP-style sockets, this code should work. * - Daisy */ -static int -sctp_writeable(struct sock *sk) +static int sctp_writeable(struct sock *sk) { - int amt = 0; amt = sk->sndbuf - sk->wmem_queued; - if (amt < 0) { + if (amt < 0) amt = 0; - } return amt; - -} /* sctp_writeable() */ +} /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { - .name = "SCTP", - .close = sctp_close, - .connect = sctp_connect, - .disconnect = sctp_disconnect, - .accept = sctp_accept, - .ioctl = sctp_ioctl, - .init = sctp_init_sock, - .destroy = sctp_destroy_sock, - .shutdown = sctp_shutdown, - .setsockopt = sctp_setsockopt, - .getsockopt = sctp_getsockopt, - .sendmsg = sctp_sendmsg, - .recvmsg = sctp_recvmsg, - .bind = sctp_bind, - .backlog_rcv = sctp_backlog_rcv, - .hash = sctp_hash, - .unhash = sctp_unhash, - .get_port = sctp_get_port, + .name = "SCTP", + .close = sctp_close, + .connect = sctp_connect, + .disconnect = sctp_disconnect, + .accept = sctp_accept, + .ioctl = sctp_ioctl, + .init = sctp_init_sock, + .destroy = sctp_destroy_sock, + .shutdown = sctp_shutdown, + .setsockopt = sctp_setsockopt, + .getsockopt = sctp_getsockopt, + .sendmsg = sctp_sendmsg, + .recvmsg = sctp_recvmsg, + .bind = sctp_bind, + .backlog_rcv = sctp_backlog_rcv, + .hash = sctp_hash, + .unhash = sctp_unhash, + .get_port = sctp_get_port, }; diff --git a/net/sctp/sctp_sysctl.c b/net/sctp/sctp_sysctl.c index fb9f8ffaff30..951e66784547 100644 --- a/net/sctp/sctp_sysctl.c +++ b/net/sctp/sctp_sysctl.c @@ -46,65 +46,62 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_sysctl.c,v 1.2 2002/07 extern sctp_protocol_t sctp_proto; static ctl_table sctp_table[] = { - {NET_SCTP_RTO_INITIAL, "rto_initial", - &sctp_proto.rto_initial, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies, &sysctl_jiffies}, - {NET_SCTP_RTO_MIN, "rto_min", - &sctp_proto.rto_min, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies, &sysctl_jiffies}, - {NET_SCTP_RTO_MAX, "rto_max", - &sctp_proto.rto_max, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies, &sysctl_jiffies}, - {NET_SCTP_VALID_COOKIE_LIFE, "valid_cookie_life", - &sctp_proto.valid_cookie_life, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies, &sysctl_jiffies}, - {NET_SCTP_MAX_BURST, "max_burst", - &sctp_proto.max_burst, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_SCTP_ASSOCIATION_MAX_RETRANS, "association_max_retrans", - &sctp_proto.max_retrans_association, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_SCTP_PATH_MAX_RETRANS, "path_max_retrans", - &sctp_proto.max_retrans_path, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_SCTP_MAX_INIT_RETRANSMITS, "max_init_retransmits", - &sctp_proto.max_retrans_init, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_SCTP_HB_INTERVAL, "hb_interval", - &sctp_proto.hb_interval, sizeof(int), 0644, NULL, - &proc_dointvec_jiffies, &sysctl_jiffies}, - {NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor", - &sctp_proto.rto_alpha, sizeof(int), 0644, NULL, - &proc_dointvec}, - {NET_SCTP_RTO_BETA, "rto_beta_exp_divisor", - &sctp_proto.rto_beta, sizeof(int), 0644, NULL, - &proc_dointvec}, - {0} + { NET_SCTP_RTO_INITIAL, "rto_initial", + &sctp_proto.rto_initial, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_MIN, "rto_min", + &sctp_proto.rto_min, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_MAX, "rto_max", + &sctp_proto.rto_max, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_VALID_COOKIE_LIFE, "valid_cookie_life", + &sctp_proto.valid_cookie_life, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_MAX_BURST, "max_burst", + &sctp_proto.max_burst, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_ASSOCIATION_MAX_RETRANS, "association_max_retrans", + &sctp_proto.max_retrans_association, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_PATH_MAX_RETRANS, "path_max_retrans", + &sctp_proto.max_retrans_path, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_MAX_INIT_RETRANSMITS, "max_init_retransmits", + &sctp_proto.max_retrans_init, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_HB_INTERVAL, "hb_interval", + &sctp_proto.hb_interval, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies }, + { NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor", + &sctp_proto.rto_alpha, sizeof(int), 0644, NULL, + &proc_dointvec }, + { NET_SCTP_RTO_BETA, "rto_beta_exp_divisor", + &sctp_proto.rto_beta, sizeof(int), 0644, NULL, + &proc_dointvec }, + { 0 } }; static ctl_table sctp_net_table[] = { - {NET_SCTP, "sctp", NULL, 0, 0555, sctp_table}, - {0} + { NET_SCTP, "sctp", NULL, 0, 0555, sctp_table }, + { 0 } }; static ctl_table sctp_root_table[] = { - {CTL_NET, "net", NULL, 0, 0555, sctp_net_table}, - {0} + { CTL_NET, "net", NULL, 0, 0555, sctp_net_table }, + { 0 } }; static struct ctl_table_header * sctp_sysctl_header; -/* Sysctl registration. */ +/* Sysctl registration. */ void sctp_sysctl_register(void) { sctp_sysctl_header = register_sysctl_table(sctp_root_table, 0); +} -} /* sctp_sysctl_register() */ - -/* Sysctl deregistration. */ +/* Sysctl deregistration. */ void sctp_sysctl_unregister(void) { unregister_sysctl_table(sctp_sysctl_header); - -} /* sctp_sysctl_unregister() */ - +} diff --git a/net/sctp/sctp_transport.c b/net/sctp/sctp_transport.c index 407c9aa71b07..fcfa7c5ed75f 100644 --- a/net/sctp/sctp_transport.c +++ b/net/sctp/sctp_transport.c @@ -50,60 +50,54 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_transport.c,v 1.11 2002/06/20 05:57:01 samudrala Exp $"; -#include #include #include -/* 1st Level Abstractions. */ +/* 1st Level Abstractions. */ -/* Allocate and initialize a new transport. */ -sctp_transport_t * -sctp_transport_new(const sockaddr_storage_t *addr, int priority) +/* Allocate and initialize a new transport. */ +sctp_transport_t *sctp_transport_new(const sockaddr_storage_t *addr, int priority) { sctp_transport_t *transport; transport = t_new(sctp_transport_t, priority); - if (NULL == transport) { + if (!transport) goto fail; - } - if (NULL == sctp_transport_init(transport, addr, priority)) { + if (!sctp_transport_init(transport, addr, priority)) goto fail_init; - } transport->malloced = 1; SCTP_DBG_OBJCNT_INC(transport); return transport; - + fail_init: kfree(transport); + fail: return NULL; +} -} /* sctp_transport_new() */ - - -/* Intialize a new transport from provided memory. */ -sctp_transport_t * -sctp_transport_init(sctp_transport_t *peer, - const sockaddr_storage_t *addr, - int priority) +/* Intialize a new transport from provided memory. */ +sctp_transport_t *sctp_transport_init(sctp_transport_t *peer, + const sockaddr_storage_t *addr, + int priority) { - sctp_protocol_t *proto = sctp_get_protocol(); + sctp_protocol_t *proto = sctp_get_protocol(); - /* Copy in the address. */ + /* Copy in the address. */ peer->ipaddr = *addr; - peer->af_specific = sctp_get_af_specific(addr); - peer->asoc = NULL; - peer->pmtu = peer->af_specific->get_dst_mtu(addr); + peer->af_specific = sctp_get_af_specific(addr); + peer->asoc = NULL; + peer->pmtu = peer->af_specific->get_dst_mtu(addr); - /* From 6.3.1 RTO Calculation: - * + /* From 6.3.1 RTO Calculation: + * * C1) Until an RTT measurement has been made for a packet sent to the * given destination transport address, set RTO to the protocol * parameter 'RTO.Initial'. - */ + */ peer->rtt = 0; peer->rto = proto->rto_initial; peer->rttvar = 0; @@ -113,17 +107,17 @@ sctp_transport_init(sctp_transport_t *peer, peer->last_time_heard = jiffies; peer->last_time_used = jiffies; peer->last_time_ecne_reduced = jiffies; - + peer->state.active = 1; - peer->state.hb_allowed = 0; - - /* Initialize the default path max_retrans. */ + peer->state.hb_allowed = 0; + + /* Initialize the default path max_retrans. */ peer->max_retrans = proto->max_retrans_path; peer->error_threshold = 0; - peer->error_count = 0; + peer->error_count = 0; + + peer->debug_name = "unnamedtransport"; - peer->debug_name = "unnamedtransport"; - INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); @@ -133,248 +127,222 @@ sctp_transport_init(sctp_transport_t *peer, peer->T3_rtx_timer.function = sctp_generate_t3_rtx_event; peer->T3_rtx_timer.data = (unsigned long)peer; - /* Set up the heartbeat timer. */ - init_timer(&peer->hb_timer); - peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - peer->hb_timer.function = sctp_generate_heartbeat_event; - peer->hb_timer.data = (unsigned long)peer; + /* Set up the heartbeat timer. */ + init_timer(&peer->hb_timer); + peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + peer->hb_timer.function = sctp_generate_heartbeat_event; + peer->hb_timer.data = (unsigned long)peer; - atomic_set(&peer->refcnt, 1); + atomic_set(&peer->refcnt, 1); peer->dead = 0; peer->malloced = 0; - return peer; - -} /* sctp_transport_init() */ + return peer; +} /* This transport is no longer needed. Free up if possible, or - * delay until it last reference count. + * delay until it last reference count. */ -void -sctp_transport_free(sctp_transport_t *transport) +void sctp_transport_free(sctp_transport_t *transport) { transport->dead = 1; - /* Try to delete the heartbeat timer. */ - if (del_timer(&transport->hb_timer)) { + /* Try to delete the heartbeat timer. */ + if (del_timer(&transport->hb_timer)) sctp_transport_put(transport); - } - - sctp_transport_put(transport); - -} /* sctp_transport_free() */ + sctp_transport_put(transport); +} -/* Destroy the transport data structure. - * Assumes there are no more users of this structure. -*/ -void -sctp_transport_destroy(sctp_transport_t *transport) +/* Destroy the transport data structure. + * Assumes there are no more users of this structure. + */ +void sctp_transport_destroy(sctp_transport_t *transport) { SCTP_ASSERT(transport->dead, "Transport is not dead", return); - if (transport->asoc) { + if (transport->asoc) sctp_association_put(transport->asoc); - } kfree(transport); SCTP_DBG_OBJCNT_DEC(transport); +} -} /* sctp_transport_destroy() */ - - -/* Start T3_rtx timer if it is not already running and update the heartbeat - * timer. This routine is called everytime a DATA chunk is sent. - */ -void -sctp_transport_reset_timers(sctp_transport_t *transport) +/* Start T3_rtx timer if it is not already running and update the heartbeat + * timer. This routine is called everytime a DATA chunk is sent. + */ +void sctp_transport_reset_timers(sctp_transport_t *transport) { /* RFC 2960 6.3.2 Retransmission Timer Rules * - * R1) Every time a DATA chunk is sent to any address(including a - * retransmission), if the T3-rtx timer of that address is not running + * R1) Every time a DATA chunk is sent to any address(including a + * retransmission), if the T3-rtx timer of that address is not running * start it running so that it will expire after the RTO of that * address. */ if (!timer_pending(&transport->T3_rtx_timer)) { if (!mod_timer(&transport->T3_rtx_timer, - jiffies + transport->rto)) { + jiffies + transport->rto)) sctp_transport_hold(transport); - } } - /* When a data chunk is sent, reset the heartbeat interval. */ - if (!mod_timer(&transport->hb_timer, - transport->hb_interval + transport->rto + jiffies)) { + /* When a data chunk is sent, reset the heartbeat interval. */ + if (!mod_timer(&transport->hb_timer, + transport->hb_interval + transport->rto + jiffies)) sctp_transport_hold(transport); - } +} -} /* sctp_transport_reset_timers() */ - -/* This transport has been assigned to an association. - * Initialize fields from the association or from the sock itself. - * Register the reference count in the association. +/* This transport has been assigned to an association. + * Initialize fields from the association or from the sock itself. + * Register the reference count in the association. */ -void sctp_transport_set_owner(sctp_transport_t *transport, +void sctp_transport_set_owner(sctp_transport_t *transport, sctp_association_t *asoc) { transport->asoc = asoc; sctp_association_hold(asoc); +} -} /* sctp_transport_set_owner() */ - -/* Hold a reference to a transport. */ +/* Hold a reference to a transport. */ void sctp_transport_hold(sctp_transport_t *transport) { atomic_inc(&transport->refcnt); - -} /* sctp_transport_hold() */ +} /* Release a reference to a transport and clean up - * if there are no more references. + * if there are no more references. */ void sctp_transport_put(sctp_transport_t *transport) { - if (atomic_dec_and_test(&transport->refcnt)) { + if (atomic_dec_and_test(&transport->refcnt)) sctp_transport_destroy(transport); - } - -} /* sctp_transport_put() */ +} /* Update transport's RTO based on the newly calculated RTT. */ -void -sctp_transport_update_rto(sctp_transport_t *tp, uint32_t rtt) +void sctp_transport_update_rto(sctp_transport_t *tp, __u32 rtt) { sctp_protocol_t *proto = sctp_get_protocol(); - /* Check for valid transport. */ + /* Check for valid transport. */ SCTP_ASSERT(tp, "NULL transport", return); - /* We should not be doing any RTO updates unless rto_pending is set. */ + /* We should not be doing any RTO updates unless rto_pending is set. */ SCTP_ASSERT(tp->rto_pending, "rto_pending not set", return); if (tp->rttvar || tp->srtt) { /* 6.3.1 C3) When a new RTT measurement R' is made, set - * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| + * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' */ - /* Note: The above algorithm has been rewritten to + /* Note: The above algorithm has been rewritten to * express rto_beta and rto_alpha as inverse powers - * of two. + * of two. * For example, assuming the default value of RTO.Alpha of - * 1/8, rto_alpha would be expressed as 3. + * 1/8, rto_alpha would be expressed as 3. */ - tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) + tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) + ((abs(tp->srtt - rtt)) >> proto->rto_beta); - tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) + tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) + (rtt >> proto->rto_alpha); - } else { - /* 6.3.1 C2) When the first RTT measurement R is made, set + /* 6.3.1 C2) When the first RTT measurement R is made, set * SRTT <- R, RTTVAR <- R/2. */ tp->srtt = rtt; tp->rttvar = rtt >> 1; } - /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then + /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then * adjust RTTVAR <- G, where G is the CLOCK GRANULARITY. */ - if (tp->rttvar == 0) { + if (tp->rttvar == 0) tp->rttvar = SCTP_CLOCK_GRANULARITY; - } - /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ + /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ tp->rto = tp->srtt + (tp->rttvar << 2); - /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min - * seconds then it is rounded up to RTO.Min seconds. + /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min + * seconds then it is rounded up to RTO.Min seconds. */ - if (tp->rto < tp->asoc->rto_min) { + if (tp->rto < tp->asoc->rto_min) tp->rto = tp->asoc->rto_min; - } - /* 6.3.1 C7) A maximum value may be placed on RTO provided it is + /* 6.3.1 C7) A maximum value may be placed on RTO provided it is * at least RTO.max seconds. */ - if (tp->rto > tp->asoc->rto_max) { + if (tp->rto > tp->asoc->rto_max) tp->rto = tp->asoc->rto_max; - } tp->rtt = rtt; - /* Reset rto_pending so that a new RTT measurement is started when a + /* Reset rto_pending so that a new RTT measurement is started when a * new data chunk is sent. */ tp->rto_pending = 0; SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p, rtt: %d, srtt: %d " - "rttvar: %d, rto: %d\n", + "rttvar: %d, rto: %d\n", tp, rtt, tp->srtt, tp->rttvar, tp->rto); +} -} /* sctp_transport_update_rto() */ - -/* This routine updates the transport's cwnd and partial_bytes_acked +/* This routine updates the transport's cwnd and partial_bytes_acked * parameters based on the bytes acked in the received SACK. - */ -void -sctp_transport_raise_cwnd(sctp_transport_t *transport, uint32_t sack_ctsn, - uint32_t bytes_acked) + */ +void sctp_transport_raise_cwnd(sctp_transport_t *transport, __u32 sack_ctsn, + __u32 bytes_acked) { - uint32_t cwnd, ssthresh, flight_size, pba, pmtu; + __u32 cwnd, ssthresh, flight_size, pba, pmtu; cwnd = transport->cwnd; flight_size = transport->flight_size; - /* The appropriate cwnd increase algorithm is performed if, and only - * if the cumulative TSN has advanced and the congestion window is - * being fully utilized. + /* The appropriate cwnd increase algorithm is performed if, and only + * if the cumulative TSN has advanced and the congestion window is + * being fully utilized. */ - if ((transport->asoc->ctsn_ack_point >= sack_ctsn) - || (flight_size < cwnd)) { + if ((transport->asoc->ctsn_ack_point >= sack_ctsn) || + (flight_size < cwnd)) return; - } ssthresh = transport->ssthresh; pba = transport->partial_bytes_acked; pmtu = transport->asoc->pmtu; if (cwnd <= ssthresh) { - /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less - * than or equal to ssthresh an SCTP endpoint MUST use the - * slow start algorithm to increase cwnd only if the current - * congestion window is being fully utilized and an incoming - * SACK advances the Cumulative TSN Ack Point. Only when these + /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less + * than or equal to ssthresh an SCTP endpoint MUST use the + * slow start algorithm to increase cwnd only if the current + * congestion window is being fully utilized and an incoming + * SACK advances the Cumulative TSN Ack Point. Only when these * two conditions are met can the cwnd be increased otherwise - * the cwnd MUST not be increased. If these conditions are met - * then cwnd MUST be increased by at most the lesser of - * 1) the total size of the previously outstanding DATA chunk(s) - * acknowledged, and 2) the destination's path MTU. + * the cwnd MUST not be increased. If these conditions are met + * then cwnd MUST be increased by at most the lesser of + * 1) the total size of the previously outstanding DATA chunk(s) + * acknowledged, and 2) the destination's path MTU. */ - if (bytes_acked > pmtu) { + if (bytes_acked > pmtu) cwnd += pmtu; - } else { + else cwnd += bytes_acked; - } SCTP_DEBUG_PRINTK(__FUNCTION__ ": SLOW START: transport: %p, " - "bytes_acked: %d, cwnd: %d, ssthresh: %d, " - "flight_size: %d, pba: %d\n", - transport, bytes_acked, cwnd, + "bytes_acked: %d, cwnd: %d, ssthresh: %d, " + "flight_size: %d, pba: %d\n", + transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } else { - /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, upon - * each SACK arrival that advances the Cumulative TSN Ack Point, - * increase partial_bytes_acked by the total number of bytes of - * all new chunks acknowledged in that SACK including chunks - * acknowledged by the new Cumulative TSN Ack and by Gap Ack + /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, upon + * each SACK arrival that advances the Cumulative TSN Ack Point, + * increase partial_bytes_acked by the total number of bytes of + * all new chunks acknowledged in that SACK including chunks + * acknowledged by the new Cumulative TSN Ack and by Gap Ack * Blocks. - * + * * When partial_bytes_acked is equal to or greater than cwnd and - * before the arrival of the SACK the sender had cwnd or more - * bytes of data outstanding (i.e., before arrival of the SACK, - * flightsize was greater than or equal to cwnd), increase cwnd - * by MTU, and reset partial_bytes_acked to + * before the arrival of the SACK the sender had cwnd or more + * bytes of data outstanding (i.e., before arrival of the SACK, + * flightsize was greater than or equal to cwnd), increase cwnd + * by MTU, and reset partial_bytes_acked to * (partial_bytes_acked - cwnd). */ pba += bytes_acked; @@ -384,36 +352,35 @@ sctp_transport_raise_cwnd(sctp_transport_t *transport, uint32_t sack_ctsn, } SCTP_DEBUG_PRINTK(__FUNCTION__ ": CONGESTION AVOIDANCE: " "transport: %p, bytes_acked: %d, cwnd: %d, " - "ssthresh: %d, flight_size: %d, pba: %d\n", - transport, bytes_acked, cwnd, + "ssthresh: %d, flight_size: %d, pba: %d\n", + transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } transport->cwnd = cwnd; transport->partial_bytes_acked = pba; +} -} /* sctp_transport_raise_cwnd() */ - -/* This routine is used to lower the transport's cwnd when congestion is - * detected. +/* This routine is used to lower the transport's cwnd when congestion is + * detected. */ -void -sctp_transport_lower_cwnd(sctp_transport_t *transport, - sctp_lower_cwnd_t reason) -{ - switch(reason) { +void sctp_transport_lower_cwnd(sctp_transport_t *transport, + sctp_lower_cwnd_t reason) +{ + switch (reason) { case SCTP_LOWER_CWND_T3_RTX: - /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 - * When the T3-rtx timer expires on an address, SCTP should + /* RFC 2960 Section 7.2.3, sctpimpguide-05 Section 2.9.2 + * When the T3-rtx timer expires on an address, SCTP should * perform slow start by: - * ssthresh = max(cwnd/2, 2*MTU) - * cwnd = 1*MTU - * partial_bytes_acked = 0 - */ - transport->ssthresh = max(transport->cwnd/2, + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = 1*MTU + * partial_bytes_acked = 0 + */ + transport->ssthresh = max(transport->cwnd/2, 2*transport->asoc->pmtu); transport->cwnd = transport->asoc->pmtu; break; + case SCTP_LOWER_CWND_FAST_RTX: /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the * destination address(es) to which the missing DATA chunks @@ -423,54 +390,53 @@ sctp_transport_lower_cwnd(sctp_transport_t *transport, * RFC 2960 7.2.3, sctpimpguide-05 2.9.2 Upon detection of * packet losses from SACK (see Section 7.2.4), An endpoint * should do the following: - * ssthresh = max(cwnd/2, 2*MTU) - * cwnd = ssthresh + * ssthresh = max(cwnd/2, 2*MTU) + * cwnd = ssthresh * partial_bytes_acked = 0 - */ - transport->ssthresh = max(transport->cwnd/2, + */ + transport->ssthresh = max(transport->cwnd/2, 2*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; break; + case SCTP_LOWER_CWND_ECNE: - /* RFC 2481 Section 6.1.2. + /* RFC 2481 Section 6.1.2. * If the sender receives an ECN-Echo ACK packet * then the sender knows that congestion was encountered in the * network on the path from the sender to the receiver. The - * indication of congestion should be treated just as a - * congestion loss in non-ECN Capable TCP. That is, the TCP + * indication of congestion should be treated just as a + * congestion loss in non-ECN Capable TCP. That is, the TCP * source halves the congestion window "cwnd" and reduces the * slow start threshold "ssthresh". - * A critical condition is that TCP does not react to - * congestion indications more than once every window of + * A critical condition is that TCP does not react to + * congestion indications more than once every window of * data (or more loosely more than once every round-trip time). */ - if ((jiffies - transport->last_time_ecne_reduced) - > transport->rtt) { - transport->ssthresh = max(transport->cwnd/2, + if ((jiffies - transport->last_time_ecne_reduced) > + transport->rtt) { + transport->ssthresh = max(transport->cwnd/2, 2*transport->asoc->pmtu); transport->cwnd = transport->ssthresh; transport->last_time_ecne_reduced = jiffies; } break; + case SCTP_LOWER_CWND_INACTIVE: - /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2 - * When the association does not transmit data on a given - * transport address within an RTO, the cwnd of the transport - * address should be adjusted to 2*MTU. - * NOTE: Although the draft recommends that this check needs - * to be done every RTO interval, we do it every hearbeat - * interval. + /* RFC 2960 Section 7.2.1, sctpimpguide-05 Section 2.14.2 + * When the association does not transmit data on a given + * transport address within an RTO, the cwnd of the transport + * address should be adjusted to 2*MTU. + * NOTE: Although the draft recommends that this check needs + * to be done every RTO interval, we do it every hearbeat + * interval. */ - if ((jiffies - transport->last_time_used) > transport->rto) { + if ((jiffies - transport->last_time_used) > transport->rto) transport->cwnd = 2*transport->asoc->pmtu; - } break; - } + }; transport->partial_bytes_acked = 0; - SCTP_DEBUG_PRINTK(__FUNCTION__ ": transport: %p reason: %d cwnd: " - "%d ssthresh: %d\n", transport, reason, + "%d ssthresh: %d\n", transport, reason, transport->cwnd, transport->ssthresh); - -} /* sctp_transport_lower_cwnd() */ +} diff --git a/net/sctp/sctp_tsnmap.c b/net/sctp/sctp_tsnmap.c index 70a38e9934c3..52523c80289f 100644 --- a/net/sctp/sctp_tsnmap.c +++ b/net/sctp/sctp_tsnmap.c @@ -44,74 +44,62 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_tsnmap.c,v 1.8 2002/07/26 22:52:32 jgrimm Exp $"; -#include #include #include #include -static inline void _sctp_tsnmap_update(sctp_tsnmap_t *map); -static inline void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map); -static inline void _sctp_tsnmap_find_gap_ack(uint8_t *map, uint16_t off, - uint16_t len, uint16_t base, - int *started, uint16_t *start, - int *ended, uint16_t *end); - +static void _sctp_tsnmap_update(sctp_tsnmap_t *map); +static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map); +static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, + __u16 len, __u16 base, + int *started, __u16 *start, + int *ended, __u16 *end); /* Create a new sctp_tsnmap. * Allocate room to store at least 'len' contiguous TSNs. */ -sctp_tsnmap_t * -sctp_tsnmap_new(uint16_t len, uint32_t initial_tsn, int priority) +sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) { sctp_tsnmap_t *retval; - - retval = kmalloc(sizeof(sctp_tsnmap_t) - + sctp_tsnmap_storage_size(len), + + retval = kmalloc(sizeof(sctp_tsnmap_t) + + sctp_tsnmap_storage_size(len), priority); - if (NULL == retval) { + if (!retval) goto fail; - } - if (NULL == sctp_tsnmap_init(retval, len, initial_tsn)) { + if (!sctp_tsnmap_init(retval, len, initial_tsn)) goto fail_map; - } retval->malloced = 1; - return(retval); + return retval; + +fail_map: + kfree retval; - fail_map: - kfree(retval); - fail: +fail: return NULL; - -} /* sctp_tsnmap_new() */ +} /* Initialize a block of memory as a tsnmap. */ -sctp_tsnmap_t * -sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, uint32_t initial_tsn) +sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn) { map->tsn_map = map->raw_map; map->overflow_map = map->tsn_map + len; - map->len = len; /* Clear out a TSN ack status. */ memset(map->tsn_map, 0x00, map->len + map->len); - + /* Keep track of TSNs represented by tsn_map. */ map->base_tsn = initial_tsn; map->overflow_tsn = initial_tsn + map->len; - map->cumulative_tsn_ack_point = initial_tsn - 1; map->max_tsn_seen = map->cumulative_tsn_ack_point; - map->malloced = 0; - map->pending_data = 0; - return map; - -} /* sctp_tsnmap_init() */ - + return map; +} /* Test the tracking state of this TSN. * Returns: @@ -119,13 +107,13 @@ sctp_tsnmap_init(sctp_tsnmap_t *map, uint16_t len, uint32_t initial_tsn) * >0 if the TSN has been seen (duplicate) * <0 if the TSN is invalid (too large to track) */ -int -sctp_tsnmap_check(const sctp_tsnmap_t *map, uint32_t tsn) +int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn) { - int32_t gap; + __s32 gap; int dup; - /* Calculate the index into the mapping arrays. */ - gap = tsn - map->base_tsn; + + /* Calculate the index into the mapping arrays. */ + gap = tsn - map->base_tsn; /* Verify that we can hold this TSN. */ if (gap >= (/* base */ map->len + /* overflow */ map->len)) { @@ -134,132 +122,101 @@ sctp_tsnmap_check(const sctp_tsnmap_t *map, uint32_t tsn) } /* Honk if we've already seen this TSN. - * We have three cases: + * We have three cases: * 1. The TSN is ancient or belongs to a previous tsn_map. * 2. The TSN is already marked in the tsn_map. * 3. The TSN is already marked in the tsn_map_overflow. */ - - if ( gap < 0 - || (gap < map->len && map->tsn_map[gap]) - || (gap >= map->len && map->overflow_map[gap - map->len])) { + if (gap < 0 || + (gap < map->len && map->tsn_map[gap]) || + (gap >= map->len && map->overflow_map[gap - map->len])) dup = 1; - } else { + else dup = 0; - } - - out: - return(dup); - -} /* sctp_tsnmap_check() */ +out: + return dup; +} -/* Is there a gap in the TSN map? */ -int -sctp_tsnmap_has_gap(const sctp_tsnmap_t *map) +/* Is there a gap in the TSN map? */ +int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map) { int has_gap; has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen); return has_gap; - -} /* sctp_tsnmap_has_gap() */ - +} /* Mark this TSN as seen. */ -void -sctp_tsnmap_mark(sctp_tsnmap_t *map, uint32_t tsn) +void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn) { - int32_t gap; - + __s32 gap; + /* Vacuously mark any TSN which precedes the map base or * exceeds the end of the map. */ - if (TSN_lt(tsn, map->base_tsn)) { + if (TSN_lt(tsn, map->base_tsn)) return; - } - - if (!TSN_lt(tsn, map->base_tsn + map->len + map->len)) { + if (!TSN_lt(tsn, map->base_tsn + map->len + map->len)) return; - } /* Bump the max. */ - if (TSN_lt(map->max_tsn_seen, tsn)) { + if (TSN_lt(map->max_tsn_seen, tsn)) map->max_tsn_seen = tsn; - } - /* Assert: TSN is in range. */ + /* Assert: TSN is in range. */ gap = tsn - map->base_tsn; - /* Mark the TSN as received. */ - if (gap < map->len) { - map->tsn_map[gap]++; - } else { - map->overflow_map[gap - map->len]++; - } - - /* Go fixup any internal TSN mapping variables including + /* Mark the TSN as received. */ + if (gap < map->len) + map->tsn_map[gap]++; + else + map->overflow_map[gap - map->len]++; + + /* Go fixup any internal TSN mapping variables including * cumulative_tsn_ack_point. - */ + */ _sctp_tsnmap_update(map); - -} /* sctp_tsnmap_mark() */ +} /* Retrieve the Cumulative TSN Ack Point. */ -uint32_t -sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map) +__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map) { - return(map->cumulative_tsn_ack_point); - -} /* sctp_tsnmap_get_ctsn() */ + return map->cumulative_tsn_ack_point; +} /* Retrieve the highest TSN we've seen. */ -uint32_t -sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map) +__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map) { - return(map->max_tsn_seen); - -} /* sctp_tsnmap_get_max_tsn_seen() */ - + return map->max_tsn_seen; +} /* Dispose of a tsnmap. */ -void -sctp_tsnmap_free(sctp_tsnmap_t *map) +void sctp_tsnmap_free(sctp_tsnmap_t *map) { - if (map->malloced) { + if (map->malloced) kfree(map); - } -} /* sctp_tsnmap_free() */ - +} /* Initialize a Gap Ack Block iterator from memory being provided. */ -void -sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter) +void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter) { /* Only start looking one past the Cumulative TSN Ack Point. */ iter->start = map->cumulative_tsn_ack_point + 1; +} -} /* sctp_tsnmap_iter_init() */ - - - - - -/* Get the next Gap Ack Blocks. Returns 0 if there was not +/* Get the next Gap Ack Blocks. Returns 0 if there was not * another block to get. */ -int -sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, - uint16_t *start, uint16_t *end) +int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, + __u16 *start, __u16 *end) { int started, ended; - uint16_t _start, _end, offset; - + __u16 _start, _end, offset; - /* We haven't found a gap yet. */ + /* We haven't found a gap yet. */ started = ended = 0; - /* Search the first mapping array. */ if (iter->start - map->base_tsn < map->len) { offset = iter->start - map->base_tsn; @@ -268,22 +225,17 @@ sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, map->len, 0, &started, &_start, &ended, &_end); - } - + } /* Do we need to check the overflow map? */ - if (!ended) { - /* Fix up where we'd like to start searching in the * overflow map. */ - if (iter->start - map->base_tsn < map->len) { + if (iter->start - map->base_tsn < map->len) offset = 0; - } else { + else offset = iter->start - map->base_tsn - map->len; - } - /* Search the overflow map. */ _sctp_tsnmap_find_gap_ack(map->overflow_map, @@ -291,7 +243,7 @@ sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, map->len, map->len, &started, &_start, - &ended, &_end); + &ended, &_end); } /* The Gap Ack Block happens to end at the end of the @@ -306,22 +258,21 @@ sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, * bump the iterator forward. */ if (ended) { - /* Fix up the start and end based on the + /* Fix up the start and end based on the * Cumulative TSN Ack offset into the map. */ - int gap = map->cumulative_tsn_ack_point - - map->base_tsn; - + int gap = map->cumulative_tsn_ack_point - + map->base_tsn; + *start = _start - gap; *end = _end - gap; - + /* Move the iterator forward. */ iter->start = map->cumulative_tsn_ack_point + *end + 1; } - return(ended); - -} /* sctp_tsnmap_next_gap_ack() */ + return ended; +} /******************************************************************** * 2nd Level Abstractions @@ -330,67 +281,63 @@ sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, /* This private helper function updates the tsnmap buffers and * the Cumulative TSN Ack Point. */ -static inline void -_sctp_tsnmap_update(sctp_tsnmap_t *map) +static void _sctp_tsnmap_update(sctp_tsnmap_t *map) { - uint32_t ctsn; + __u32 ctsn; ctsn = map->cumulative_tsn_ack_point; do { ctsn++; - if ( ctsn == map->overflow_tsn ) { - + if (ctsn == map->overflow_tsn) { /* Now tsn_map must have been all '1's, * so we swap the map and check the overflow table */ - - uint8_t *tmp = map->tsn_map; - memset(tmp, 0, map->len); - map->tsn_map = map->overflow_map; - map->overflow_map = tmp; + __u8 *tmp = map->tsn_map; + memset(tmp, 0, map->len); + map->tsn_map = map->overflow_map; + map->overflow_map = tmp; /* Update the tsn_map boundaries. */ - map->base_tsn += map->len; - map->overflow_tsn += map->len; + map->base_tsn += map->len; + map->overflow_tsn += map->len; } - } while ( map->tsn_map[ctsn - map->base_tsn] ); + } while (map->tsn_map[ctsn - map->base_tsn]); map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ - _sctp_tsnmap_update_pending_data(map); +} -} /* _sctp_tsnmap_update() */ - -static inline void -_sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) +static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) { - uint32_t cum_tsn = map->cumulative_tsn_ack_point; - uint32_t max_tsn = map->max_tsn_seen; - uint32_t base_tsn = map->base_tsn; - uint16_t pending_data; - int32_t gap, start, end, i; + __u32 cum_tsn = map->cumulative_tsn_ack_point; + __u32 max_tsn = map->max_tsn_seen; + __u32 base_tsn = map->base_tsn; + __u16 pending_data; + __s32 gap, start, end, i; pending_data = max_tsn - cum_tsn; gap = max_tsn - base_tsn; - if (gap <= 0 || gap >= (map->len + map->len)) { + if (gap <= 0 || gap >= (map->len + map->len)) goto out; - } start = ((cum_tsn >= base_tsn) ? (cum_tsn - base_tsn + 1) : 0); - end = ((gap > map->len ) ? map->len : gap + 1); + end = ((gap > map->len ) ? map->len : gap + 1); - for (i = start; i < end; i++) { - if (map->tsn_map[i]) { pending_data--; } + for (i = start; i < end; i++) { + if (map->tsn_map[i]) + pending_data--; } - if (gap >= map->len) { + if (gap >= map->len) { start = 0; end = gap - map->len + 1; - for (i = start; i < end; i++) { - if (map->overflow_map[i]) { pending_data--; } - } + for (i = start; i < end; i++) { + if (map->overflow_map[i]) + pending_data--; + } } + out: map->pending_data = pending_data; } @@ -400,17 +347,14 @@ out: * * The flags "started" and "ended" tell is if we found the beginning * or (respectively) the end of a Gap Ack Block. - * */ - -static inline void -_sctp_tsnmap_find_gap_ack(uint8_t *map, uint16_t off, - uint16_t len, uint16_t base, - int *started, uint16_t *start, - int *ended, uint16_t *end) +static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, + __u16 len, __u16 base, + int *started, __u16 *start, + int *ended, __u16 *end) { int i = off; - + /* Let's look through the entire array, but break out * early if we have found the end of the Gap Ack Block. */ @@ -425,19 +369,18 @@ _sctp_tsnmap_find_gap_ack(uint8_t *map, uint16_t off, } } } + /* Look for the end. */ if (*started) { /* We have found the start, let's find the * end. If we find the end, break out. */ for (; i < len; i++) { - - if (!map[i]){ + if (!map[i]) { (*ended)++; *end = base + i - 1; break; } } } - -} /* _sctp_tsnmap_next_gap_ack() */ +} diff --git a/net/sctp/sctp_ulpevent.c b/net/sctp/sctp_ulpevent.c index 9b1bd47d7f8f..5bbb91b2c910 100644 --- a/net/sctp/sctp_ulpevent.c +++ b/net/sctp/sctp_ulpevent.c @@ -43,194 +43,161 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpevent.c,v 1.16 2002/08/21 18:34:04 jgrimm Exp $"; -#include #include #include #include #include #include +static void sctp_rcvmsg_rfree(struct sk_buff *skb); +static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, + sctp_association_t *asoc); -static void -sctp_rcvmsg_rfree(struct sk_buff *skb); -static inline void -sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc); - - -/* Create a new sctp_ulpevent. - */ -sctp_ulpevent_t * -sctp_ulpevent_new(int size, int msg_flags, int priority) +/* Create a new sctp_ulpevent. */ +sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority) { sctp_ulpevent_t *event; struct sk_buff *skb; - - skb = alloc_skb(size, priority); - if (NULL == skb) { + skb = alloc_skb(size, priority); + if (!skb) goto fail; - } - event = (sctp_ulpevent_t *)skb->cb; + event = (sctp_ulpevent_t *) skb->cb; event = sctp_ulpevent_init(event, skb, msg_flags); - - if (NULL == event) { + if (!event) goto fail_init; - } event->malloced = 1; return event; - fail_init: +fail_init: kfree_skb(event->parent); - fail: + +fail: return NULL; - -} /* sctp_ulpevent_new() */ - -/* Initialize an ULP event from an given skb. */ -sctp_ulpevent_t * -sctp_ulpevent_init(sctp_ulpevent_t *event, - struct sk_buff *parent, - int msg_flags) +} + +/* Initialize an ULP event from an given skb. */ +sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, + struct sk_buff *parent, + int msg_flags) { memset(event, sizeof(sctp_ulpevent_t), 0x00); - event->msg_flags = msg_flags; event->parent = parent; event->malloced = 0; return event; +} -} /* sctp_ulpevent_init() */ - - - -/* Dispose of an event. */ -void -sctp_ulpevent_free(sctp_ulpevent_t *event) +/* Dispose of an event. */ +void sctp_ulpevent_free(sctp_ulpevent_t *event) { - if (event->malloced) { + if (event->malloced) kfree_skb(event->parent); - } +} -} /* sctp_ulpevent_free() */ - -/* Is this a MSG_NOTIFICATION? */ -int -sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) +/* Is this a MSG_NOTIFICATION? */ +int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) { return event->msg_flags & MSG_NOTIFICATION; +} -} /* sctp_ulpevent_is_notification() */ - - -/* Create and initialize an SCTP_ASSOC_CHANGE event. - * +/* Create and initialize an SCTP_ASSOC_CHANGE event. + * * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * Communication notifications inform the ULP that an SCTP association * has either begun or ended. The identifier for a new association is * provided by this notification. - * + * * Note: There is no field checking here. If a field is unused it will be * zero'd out. */ -sctp_ulpevent_t * -sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, - uint16_t flags, - uint16_t state, - uint16_t error, - uint16_t outbound, - uint16_t inbound, - int priority) +sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, + __u16 flags, + __u16 state, + __u16 error, + __u16 outbound, + __u16 inbound, + int priority) { - sctp_ulpevent_t *event; - struct sctp_assoc_change *sac; + struct sctp_assoc_change *sac; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), MSG_NOTIFICATION, priority); - - if (NULL == event) { + if (!event) goto fail; - } sac = (struct sctp_assoc_change *) - skb_put(event->parent, + skb_put(event->parent, sizeof(struct sctp_assoc_change)); - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * sac_type: * It should be SCTP_ASSOC_CHANGE. */ - sac->sac_type = SCTP_ASSOC_CHANGE; - - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * sac_state: 32 bits (signed integer) * This field holds one of a number of values that communicate the - * event that happened to the association. + * event that happened to the association. */ - sac->sac_state = state; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * sac_flags: 16 bits (unsigned integer) * Currently unused. - * */ sac->sac_flags = 0; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * - * sac_length: sizeof (uint32_t) + * + * sac_length: sizeof (__u32) * This field is the total length of the notification data, including * the notification header. */ - sac->sac_length = sizeof(struct sctp_assoc_change); - - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * sac_error: 32 bits (signed integer) - * + * * If the state was reached due to a error condition (e.g. * COMMUNICATION_LOST) any relevant error information is available in * this field. This corresponds to the protocol error codes defined in * [SCTP]. */ - sac->sac_error = error; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE - * + * * sac_outbound_streams: 16 bits (unsigned integer) * sac_inbound_streams: 16 bits (unsigned integer) - * + * * The maximum number of streams allowed in each direction are * available in sac_outbound_streams and sac_inbound streams. */ sac->sac_outbound_streams = outbound; sac->sac_inbound_streams = inbound; - - - /* Socket Extensions for SCTP + + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_assoc_id: sizeof (sctp_assoc_t) - * + * * The association id field, holds the identifier for the association. * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. @@ -238,11 +205,10 @@ sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, sac->sac_assoc_id = sctp_assoc2id(asoc); return event; -fail: - return NULL; - -} /* sctp_ulpevent_make_assoc_change() */ +fail: + return NULL; +} /* Create and initialize an SCTP_PEER_ADDR_CHANGE event. * @@ -250,52 +216,49 @@ fail: * 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * When a destination address on a multi-homed peer encounters a change - * an interface details event is sent. - * + * an interface details event is sent. */ -sctp_ulpevent_t * -sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, - const struct sockaddr_storage *aaddr, - int flags, - int state, - int error, - int priority) +sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( + const sctp_association_t *asoc, + const struct sockaddr_storage *aaddr, + int flags, + int state, + int error, + int priority) { sctp_ulpevent_t *event; struct sctp_paddr_change *spc; - + event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), MSG_NOTIFICATION, priority); - - if (NULL == event) { + if (!event) goto fail; - } - + spc = (struct sctp_paddr_change *) - skb_put(event->parent, - sizeof(struct sctp_paddr_change)); - - /* Sockets API Extensions for SCTP + skb_put(event->parent, + sizeof(struct sctp_paddr_change)); + + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE - * + * * spc_type: - * + * * It should be SCTP_PEER_ADDR_CHANGE. */ spc->spc_type = SCTP_PEER_ADDR_CHANGE; - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * - * spc_length: sizeof (uint32_t) - * + * spc_length: sizeof (__u32) + * * This field is the total length of the notification data, including * the notification header. */ - spc->spc_length = sizeof(struct sctp_paddr_change); + spc->spc_length = sizeof(struct sctp_paddr_change); - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * spc_flags: 16 bits (unsigned integer) @@ -303,7 +266,7 @@ sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, */ spc->spc_flags = 0; - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * spc_state: 32 bits (signed integer) @@ -313,7 +276,7 @@ sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, */ spc->spc_state = state; - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * spc_error: 32 bits (signed integer) @@ -324,18 +287,18 @@ sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, */ spc->spc_error = error; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.1 SCTP_ASSOC_CHANGE * * sac_assoc_id: sizeof (sctp_assoc_t) - * + * * The association id field, holds the identifier for the association. * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ spc->spc_assoc_id = sctp_assoc2id(asoc); - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * spc_aaddr: sizeof (struct sockaddr_storage) @@ -345,20 +308,19 @@ sctp_ulpevent_make_peer_addr_change(const sctp_association_t *asoc, */ memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); - return event; + fail: return NULL; - -} /* sctp_ulpevent_make_peer_addr_change() */ +} /* Create and initialize an SCTP_REMOTE_ERROR notification. - * + * * Note: This assumes that the chunk->skb->data already points to the - * operation error payload. + * operation error payload. * * Socket Extensions for SCTP - draft-01 - * 5.3.1.3 SCTP_REMOTE_ERROR + * 5.3.1.3 SCTP_REMOTE_ERROR * * A remote peer may send an Operational Error message to its peer. * This message indicates a variety of error conditions on an @@ -366,193 +328,180 @@ fail: * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP * specification [SCTP] and any extensions for a list of possible * error formats. - * */ -sctp_ulpevent_t * -sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, - sctp_chunk_t *chunk, - uint16_t flags, - int priority) +sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + __u16 flags, + int priority) { sctp_ulpevent_t *event; - struct sctp_remote_error *sre; + struct sctp_remote_error *sre; struct sk_buff *skb; sctp_errhdr_t *ch; - uint16_t cause; + __u16 cause; int elen; - + ch = (sctp_errhdr_t *)(chunk->skb->data); cause = ch->cause; elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); - /* Pull off the ERROR header. */ + /* Pull off the ERROR header. */ skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); - - /* Copy the skb to a new skb with room for us to prepend - * notification with. */ - skb = skb_copy_expand(chunk->skb, + + /* Copy the skb to a new skb with room for us to prepend + * notification with. + */ + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), /* headroom */ 0, /* tailroom */ priority); - /* Pull off the rest of the cause TLV from the chunk. */ + /* Pull off the rest of the cause TLV from the chunk. */ skb_pull(chunk->skb, elen); - - if (NULL == skb) { + if (!skb) goto fail; - } - /* Embed the event fields inside the cloned skb. */ - event = (sctp_ulpevent_t *)skb->cb; - event = sctp_ulpevent_init(event, + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; + event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); - if (NULL == event) { + if (!event) goto fail; - } - + event->malloced = 1; - sre = (struct sctp_remote_error *) skb_push(skb, sizeof(struct sctp_remote_error)); - /* Trim the buffer to the right length. */ + /* Trim the buffer to the right length. */ skb_trim(skb, sizeof(struct sctp_remote_error) + elen); - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * * sre_type: * It should be SCTP_REMOTE_ERROR. */ sre->sre_type = SCTP_REMOTE_ERROR; - /* - * Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * + /* + * Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * * sre_flags: 16 bits (unsigned integer) * Currently unused. */ sre->sre_flags = 0; - /* Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_length: sizeof (uint32_t) - * - * This field is the total length of the notification data, + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * sre_length: sizeof (__u32) + * + * This field is the total length of the notification data, * including the notification header. */ sre->sre_length = skb->len; - /* - * Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR + * * sre_error: 16 bits (unsigned integer) * This value represents one of the Operational Error causes defined in * the SCTP specification, in network byte order. */ - sre->sre_error = cause; + sre->sre_error = cause; - - /* - * Socket Extensions for SCTP - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * sre_assoc_id: sizeof (sctp_assoc_t) + /* Socket Extensions for SCTP + * 5.3.1.3 SCTP_REMOTE_ERROR * + * sre_assoc_id: sizeof (sctp_assoc_t) * * The association id field, holds the identifier for the association. * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - - sre->sre_assoc_id = sctp_assoc2id(asoc); + sre->sre_assoc_id = sctp_assoc2id(asoc); + return event; - return event; fail: - return NULL; - -} /* sctp_ulpevent_make_remote_error () */ + return NULL; +} /* Create and initialize a SCTP_SEND_FAILED notification. - * + * * Socket Extensions for SCTP - draft-01 * 5.3.1.4 SCTP_SEND_FAILED */ -sctp_ulpevent_t * -sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, - sctp_chunk_t *chunk, - uint16_t flags, - uint32_t error, - int priority) +sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, + sctp_chunk_t *chunk, + __u16 flags, + __u32 error, + int priority) { sctp_ulpevent_t *event; - struct sctp_send_failed *ssf; + struct sctp_send_failed *ssf; struct sk_buff *skb; - /* Make skb with more room so we can prepend notification. */ - skb = skb_copy_expand(chunk->skb, + /* Make skb with more room so we can prepend notification. */ + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_send_failed), /* headroom */ 0, /* tailroom */ priority); - - if (NULL == skb) { + if (!skb) goto fail; - } - /* Pull off the common chunk header and DATA header. */ + /* Pull off the common chunk header and DATA header. */ skb_pull(skb, sizeof(sctp_data_chunk_t)); - /* Embed the event fields inside the cloned skb. */ - event = (sctp_ulpevent_t *)skb->cb; + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); - if (NULL == event) { goto fail; } + if (!event) + goto fail; - /* Mark as malloced, even though the constructor was not - * called. + /* Mark as malloced, even though the constructor was not + * called. */ event->malloced = 1; - + ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_type: - * It should be SCTP_SEND_FAILED. + * It should be SCTP_SEND_FAILED. */ ssf->ssf_type = SCTP_SEND_FAILED; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED - * + * * ssf_flags: 16 bits (unsigned integer) * The flag value will take one of the following values * * SCTP_DATA_UNSENT - Indicates that the data was never put on - * the wire. - * + * the wire. + * * SCTP_DATA_SENT - Indicates that the data was put on the wire. - * Note that this does not necessarily mean that the - * data was (or was not) successfully delivered. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. */ ssf->ssf_flags = flags; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * - * ssf_length: sizeof (uint32_t) + * ssf_length: sizeof (__u32) * This field is the total length of the notification data, including * the notification header. */ ssf->ssf_length = skb->len; - - /* Socket Extensions for SCTP + + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_error: 16 bits (unsigned integer) @@ -562,18 +511,18 @@ sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, */ ssf->ssf_error = error; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_info: sizeof (struct sctp_sndrcvinfo) * The original send information associated with the undelivered - * message. + * message. */ - memcpy(&ssf->ssf_info, - &chunk->sinfo, + memcpy(&ssf->ssf_info, + &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); - - /* Socket Extensions for SCTP + + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * * ssf_assoc_id: sizeof (sctp_assoc_t) @@ -583,65 +532,61 @@ sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, * ignored. */ ssf->ssf_assoc_id = sctp_assoc2id(asoc); - - + return event; -fail: + +fail: return NULL; +} -} /* sctp_ulpevent_make_send_failed () */ - /* Create and initialize a SCTP_SHUTDOWN_EVENT notification. - * + * * Socket Extensions for SCTP - draft-01 * 5.3.1.5 SCTP_SHUTDOWN_EVENT */ -sctp_ulpevent_t * -sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, - uint16_t flags, - int priority) +sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, + __u16 flags, + int priority) { sctp_ulpevent_t *event; - struct sctp_shutdown_event *sse; + struct sctp_shutdown_event *sse; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), MSG_NOTIFICATION, priority); - - if (NULL == event) { + if (!event) goto fail; - } sse = (struct sctp_shutdown_event *) - skb_put(event->parent, + skb_put(event->parent, sizeof(struct sctp_shutdown_event)); - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.5 SCTP_SHUTDOWN_EVENT - * + * * sse_type * It should be SCTP_SHUTDOWN_EVENT */ sse->sse_type = SCTP_SHUTDOWN_EVENT; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.5 SCTP_SHUTDOWN_EVENT - * + * * sse_flags: 16 bits (unsigned integer) * Currently unused. */ sse->sse_flags = 0; - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.5 SCTP_SHUTDOWN_EVENT * - * sse_length: sizeof (uint32_t) + * sse_length: sizeof (__u32) * This field is the total length of the notification data, including * the notification header. */ sse->sse_length = sizeof(struct sctp_shutdown_event); - /* Socket Extensions for SCTP + /* Socket Extensions for SCTP * 5.3.1.5 SCTP_SHUTDOWN_EVENT * * sse_assoc_id: sizeof (sctp_assoc_t) @@ -652,42 +597,36 @@ sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, sse->sse_assoc_id = sctp_assoc2id(asoc); return event; -fail: - return NULL; - -} /* sctp_ulpevent_make_shutdown_event () */ +fail: + return NULL; +} /* A message has been received. Package this message as a notification * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo * even if filtered out later. - * + * * Socket Extensions for SCTP - draft-01 * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) - * - */ -sctp_ulpevent_t * -sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, - sctp_chunk_t *chunk, - int priority) + */ +sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, + sctp_chunk_t *chunk, + int priority) { - sctp_ulpevent_t *event; struct sctp_sndrcvinfo *info; struct sk_buff *skb; - size_t padding, len; + size_t padding, len; - /* Clone the original skb, sharing the data. */ + /* Clone the original skb, sharing the data. */ skb = skb_clone(chunk->skb, priority); - if (NULL == skb) { + if (!skb) goto fail; - } - - /* First calculate the padding, so we don't inadvertently + /* First calculate the padding, so we don't inadvertently * pass up the wrong length to the user. * - * RFC 2960 - Section 3.2 Chunk Field Descriptions + * RFC 2960 - Section 3.2 Chunk Field Descriptions * * The total length of a chunk(including Type, Length and Value fields) * MUST be a multiple of 4 bytes. If the length of the chunk is not a @@ -695,32 +634,29 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, * bytes and this padding is not included in the chunk length field. * The sender should never pad with more than 3 bytes. The receiver * MUST ignore the padding bytes. - * - */ + */ len = ntohs(chunk->chunk_hdr->length); padding = WORD_ROUND(len) - len; /* Fixup cloned skb with just this chunks data. */ skb_trim(skb, chunk->chunk_end - padding - skb->data); - /* Set up a destructor to do rwnd accounting. */ + /* Set up a destructor to do rwnd accounting. */ sctp_ulpevent_set_owner_r(skb, asoc); - /* Embed the event fields inside the cloned skb. */ - event = (sctp_ulpevent_t *)skb->cb; - /* Initialize event with flags 0. */ - event = sctp_ulpevent_init(event, skb, 0); + /* Embed the event fields inside the cloned skb. */ + event = (sctp_ulpevent_t *) skb->cb; - if (NULL == event) { + /* Initialize event with flags 0. */ + event = sctp_ulpevent_init(event, skb, 0); + if (!event) goto fail_init; - } event->malloced = 1; - info = (struct sctp_sndrcvinfo *)&event->sndrcvinfo; - - /* - * Sockets API Extensions for SCTP + info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; + + /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * * sinfo_stream: 16 bits (unsigned integer) @@ -728,10 +664,9 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, * For recvmsg() the SCTP stack places the message's stream number in * this value. */ - - info->sinfo_stream = ntohs(chunk->subh.data_hdr->stream); + info->sinfo_stream = ntohs(chunk->subh.data_hdr->stream); - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * * sinfo_ssn: 16 bits (unsigned integer) @@ -741,13 +676,12 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, * messages this is the same number for all deliveries of the message * (if more than one recvmsg() is needed to read the message). */ + info->sinfo_ssn = ntohs(chunk->subh.data_hdr->ssn); - info->sinfo_ssn = ntohs(chunk->subh.data_hdr->ssn); - - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * - * sinfo_ppid:32 bits (unsigned integer) + * sinfo_ppid: 32 bits (unsigned integer) * * In recvmsg() this value is * the same information that was passed by the upper layer in the peer @@ -757,23 +691,21 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, */ info->sinfo_ppid = ntohl(chunk->subh.data_hdr->ppid); - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * - * sinfo_flags: 16 bits (unsigned integer) - * + * sinfo_flags: 16 bits (unsigned integer) + * * This field may contain any of the following flags and is composed of * a bitwise OR of these values. - * + * * recvmsg() flags: - * + * * MSG_UNORDERED - This flag is present when the message was sent - * non-ordered. + * non-ordered. */ - - if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { + if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) info->sinfo_flags |= MSG_UNORDERED; - } /* FIXME: For reassembly, we need to have the fragmentation bits. * This really does not belong in the event structure, but @@ -783,79 +715,69 @@ sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, */ event->chunk_flags = chunk->chunk_hdr->flags; - /* With -04 draft, tsn moves into sndrcvinfo. */ + /* With -04 draft, tsn moves into sndrcvinfo. */ info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn); - + /* Context is not used on receive. */ - info->sinfo_context = 0; + info->sinfo_context = 0; - /* Sockets API Extensions for SCTP + /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) - * + * * sinfo_assoc_id: sizeof (sctp_assoc_t) - * + * * The association handle field, sinfo_assoc_id, holds the identifier * for the association announced in the COMMUNICATION_UP notification. * All notifications for a given association have the same identifier. * Ignored for TCP-style sockets. */ - - info->sinfo_assoc_id = sctp_assoc2id(asoc); + info->sinfo_assoc_id = sctp_assoc2id(asoc); return event; fail_init: kfree_skb(skb); -fail: - return NULL; - -} /* sctp_ulpevent_make_rcvmsg() */ + +fail: + return NULL; +} /* Return the notification type, assuming this is a notification * event. */ -uint16_t -sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) +__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) { union sctp_notification *notification; - notification = (union sctp_notification *)event->parent->data; - + notification = (union sctp_notification *) event->parent->data; return notification->h.sn_type; - -} /* sctp_ulpevent_get_notification_type() */ +} /* Copy out the sndrcvinfo into a msghdr. */ -void -sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, - struct msghdr *msghdr) +void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, + struct msghdr *msghdr) { - if (!sctp_ulpevent_is_notification(event)) { - put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, - sizeof(struct sctp_sndrcvinfo), - (void *)&event->sndrcvinfo); + put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, + sizeof(struct sctp_sndrcvinfo), + (void *) &event->sndrcvinfo); } +} -} /* sctp_ulpevent_read_sndrcvinfo() */ - -/* Do accounting for bytes just read by user. */ -static void -sctp_rcvmsg_rfree(struct sk_buff *skb) +/* Do accounting for bytes just read by user. */ +static void sctp_rcvmsg_rfree(struct sk_buff *skb) { sctp_association_t *asoc; - sctp_ulpevent_t *event; + sctp_ulpevent_t *event; - /* Current stack structures assume that the rcv buffer is - * per socket. For UDP style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * Use the local private area of the skb to track the owning + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * Use the local private area of the skb to track the owning * association. */ - - event = (sctp_ulpevent_t *)skb->cb; + event = (sctp_ulpevent_t *) skb->cb; asoc = event->asoc; - if (asoc->rwnd_over) { if (asoc->rwnd_over >= skb->len) { asoc->rwnd_over -= skb->len; @@ -867,29 +789,26 @@ sctp_rcvmsg_rfree(struct sk_buff *skb) asoc->rwnd += skb->len; } - SCTP_DEBUG_PRINTK("rwnd increased by %d to (%u, %u)\n", - skb->len, asoc->rwnd, asoc->rwnd_over); + SCTP_DEBUG_PRINTK("rwnd increased by %d to (%u, %u)\n", + skb->len, asoc->rwnd, asoc->rwnd_over); sctp_association_put(asoc); - -} /* sctp_rcvmsg_rfree() */ - +} /* Charge receive window for bytes recieved. */ -static inline void -sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) +static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) { sctp_ulpevent_t *event; - /* The current stack structures assume that the rcv buffer is - * per socket. For UDP-style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * We use the local private area of the skb to track the owning + /* The current stack structures assume that the rcv buffer is + * per socket. For UDP-style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * We use the local private area of the skb to track the owning * association. */ sctp_association_hold(asoc); skb->sk = asoc->base.sk; - event = (sctp_ulpevent_t *)skb->cb; + event = (sctp_ulpevent_t *) skb->cb; event->asoc = asoc; skb->destructor = sctp_rcvmsg_rfree; @@ -903,12 +822,9 @@ sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) asoc->rwnd = 0; } - SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n", - skb->len, asoc->rwnd, asoc->rwnd_over); - -} /* sctp_ulpevent_set_owner_r() */ - - + SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n", + skb->len, asoc->rwnd, asoc->rwnd_over); +} diff --git a/net/sctp/sctp_ulpqueue.c b/net/sctp/sctp_ulpqueue.c index 3d7b86f45ed4..ed1e700acdfa 100644 --- a/net/sctp/sctp_ulpqueue.c +++ b/net/sctp/sctp_ulpqueue.c @@ -44,7 +44,6 @@ */ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpqueue.c,v 1.14 2002/08/21 18:34:04 jgrimm Exp $"; -#include #include #include #include @@ -52,55 +51,48 @@ static char *cvs_id __attribute__ ((unused)) = "$Id: sctp_ulpqueue.c,v 1.14 2002 #include #include -/* Forward declarations for internal helpers. */ -static inline sctp_ulpevent_t * -sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event); -static inline sctp_ulpevent_t * -sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event); - +/* Forward declarations for internal helpers. */ +static inline sctp_ulpevent_t * sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event); +static inline sctp_ulpevent_t *sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event); /* 1st Level Abstractions */ -/* Create a new ULP queue. - */ -sctp_ulpqueue_t * -sctp_ulpqueue_new(sctp_association_t *asoc, uint16_t inbound, int priority) +/* Create a new ULP queue. */ +sctp_ulpqueue_t *sctp_ulpqueue_new(sctp_association_t *asoc, + __u16 inbound, int priority) { sctp_ulpqueue_t *ulpq; size_t size; - + /* Today, there is only a fixed size of storage needed for - * stream support, but make the interfaces acceptable for + * stream support, but make the interfaces acceptable for * the future. - */ + */ size = sizeof(sctp_ulpqueue_t)+sctp_ulpqueue_storage_size(inbound); ulpq = kmalloc(size, priority); - - if (NULL == ulpq) { + if (!ulpq) goto fail; - } - - if (NULL == sctp_ulpqueue_init(ulpq, asoc, inbound)) { + if (!sctp_ulpqueue_init(ulpq, asoc, inbound)) goto fail_init; - } - ulpq->malloced = 1; return ulpq; - + fail_init: kfree(ulpq); + fail: return NULL; - -} /* sctp_ulpqueue_new() */ +} -/* Initialize a ULP queue from a block of memory. */ -sctp_ulpqueue_t * -sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, sctp_association_t *asoc, - uint16_t inbound) +/* Initialize a ULP queue from a block of memory. */ +sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, + sctp_association_t *asoc, + __u16 inbound) { - memset(ulpq, - sizeof(sctp_ulpqueue_t) + sctp_ulpqueue_storage_size(inbound), + memset(ulpq, + sizeof(sctp_ulpqueue_t) + sctp_ulpqueue_storage_size(inbound), 0x00); ulpq->asoc = asoc; @@ -110,173 +102,142 @@ sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq, sctp_association_t *asoc, ulpq->malloced = 0; return ulpq; +} -} /* sctp_ulpqueue_init() */ - -/* Flush the reassembly and ordering queues. */ -void -sctp_ulpqueue_flush(sctp_ulpqueue_t *ulpq) +/* Flush the reassembly and ordering queues. */ +void sctp_ulpqueue_flush(sctp_ulpqueue_t *ulpq) { struct sk_buff *skb; sctp_ulpevent_t *event; - - while((skb = skb_dequeue(&ulpq->lobby))) { - event = (sctp_ulpevent_t *)skb->cb; - sctp_ulpevent_free(event); - } - while((skb = skb_dequeue(&ulpq->reasm))) { - event = (sctp_ulpevent_t *)skb->cb; - sctp_ulpevent_free(event); + while ((skb = skb_dequeue(&ulpq->lobby))) { + event = (sctp_ulpevent_t *) skb->cb; + sctp_ulpevent_free(event); } -} /* sctp_ulpqueue_flush() */ - + while ((skb = skb_dequeue(&ulpq->reasm))) { + event = (sctp_ulpevent_t *) skb->cb; + sctp_ulpevent_free(event); + } +} -/* Dispose of a ulpqueue. */ -void -sctp_ulpqueue_free(sctp_ulpqueue_t *ulpq) +/* Dispose of a ulpqueue. */ +void sctp_ulpqueue_free(sctp_ulpqueue_t *ulpq) { - sctp_ulpqueue_flush(ulpq); - if (ulpq->malloced) { + if (ulpq->malloced) kfree(ulpq); - } +} -} /* sctp_ulpqueue_free() */ - - -/* Process an incoming DATA chunk. */ -int -sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk, - int priority) +/* Process an incoming DATA chunk. */ +int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *ulpq, sctp_chunk_t *chunk, + int priority) { struct sk_buff_head temp; sctp_data_chunk_t *hdr; sctp_ulpevent_t *event; - hdr = (sctp_data_chunk_t *)chunk->chunk_hdr; - - /* FIXME: Instead of event being the skb clone, we really should - * have a new skb based chunk structure that we can convert to + hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; + + /* FIXME: Instead of event being the skb clone, we really should + * have a new skb based chunk structure that we can convert to * an event. Temporarily, I'm carrying a few chunk fields in * the event to allow reassembly. Its too painful to change * everything at once. --jgrimm */ - event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); - - if (!event) { + if (!event) return -ENOMEM; - } - /* Do reassembly if needed. */ + /* Do reassembly if needed. */ event = sctp_ulpqueue_reasm(ulpq, event); - /* Do ordering if needed. */ - if (NULL != event) { - /* Create a temporary list to collect chunks on. */ + /* Do ordering if needed. */ + if (event) { + /* Create a temporary list to collect chunks on. */ skb_queue_head_init(&temp); skb_queue_tail(&temp, event->parent); event = sctp_ulpqueue_order(ulpq, event); } - /* Send event to the ULP. */ - if (NULL != event) { - sctp_ulpqueue_tail_event(ulpq, event); - } + /* Send event to the ULP. */ + if (event) + sctp_ulpqueue_tail_event(ulpq, event); return 0; +} -} /* sctp_ulpqueue_tail_data() */ - - -/* Add a new event for propogation to the ULP. */ -int -sctp_ulpqueue_tail_event(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +/* Add a new event for propogation to the ULP. */ +int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) { - struct sock *sk; - sk = ulpq->asoc->base.sk; + struct sock *sk = ulpq->asoc->base.sk; /* If the socket is just going to throw this away, do not * even try to deliver it. */ - if (sk->dead || (sk->shutdown & RCV_SHUTDOWN)) { + if (sk->dead || (sk->shutdown & RCV_SHUTDOWN)) goto out_free; - } - /* Check if the user wishes to receive this event. */ - if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) { + /* Check if the user wishes to receive this event. */ + if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) goto out_free; - } - - /* If we are harvesting multiple skbs they will be - * collected on a list. + + /* If we are harvesting multiple skbs they will be + * collected on a list. */ - if (event->parent->list) { + if (event->parent->list) sctp_skb_list_tail(event->parent->list, &sk->receive_queue); - } else { + else skb_queue_tail(&sk->receive_queue, event->parent); - } - - wake_up_interruptible(sk->sleep); + wake_up_interruptible(sk->sleep); return 1; out_free: - if (event->parent->list) { + if (event->parent->list) skb_queue_purge(event->parent->list); - } else { + else kfree_skb(event->parent); - } - return 0; - -} /* sctp_ulpqueue_tail_event() */ - - +} /* 2nd Level Abstractions */ -/* Helper function to store chunks that need to be reassembled. */ -static inline void -sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +/* Helper function to store chunks that need to be reassembled. */ +static inline void sctp_ulpqueue_store_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) { struct sk_buff *pos, *tmp; sctp_ulpevent_t *cevent; - uint32_t tsn, ctsn; - int flags __attribute ((unused)); - + __u32 tsn, ctsn; + unsigned long flags __attribute ((unused)); + tsn = event->sndrcvinfo.sinfo_tsn; sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); - /* Find the right place in this list. We store them by TSN. */ + /* Find the right place in this list. We store them by TSN. */ sctp_skb_for_each(pos, &ulpq->reasm, tmp) { - cevent = (sctp_ulpevent_t *)pos->cb; + cevent = (sctp_ulpevent_t *)pos->cb; ctsn = cevent->sndrcvinfo.sinfo_tsn; - if (TSN_lt(tsn, ctsn)) { break; } + if (TSN_lt(tsn, ctsn)) + break; } - - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->reasm)) { + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->reasm)) __skb_insert(event->parent, pos->prev, pos, &ulpq->reasm); - } - else { + else __skb_queue_tail(&ulpq->reasm, event->parent); - } sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); +} -} /* sctp_ulpqueue_store_reasm() */ - -/* Helper function to return an event corresponding to the reassembled - * datagram. +/* Helper function to return an event corresponding to the reassembled + * datagram. */ -static inline sctp_ulpevent_t * -sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) +static inline sctp_ulpevent_t *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; sctp_ulpevent_t *event; @@ -284,181 +245,174 @@ sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) pos = f_frag->next; - /* Set the first fragment's frag_list to point to the 2nd fragment. */ - skb_shinfo(f_frag)->frag_list = pos; + /* Set the first fragment's frag_list to point to the 2nd fragment. */ + skb_shinfo(f_frag)->frag_list = pos; - /* Remove the first fragment from the reassembly queue. */ + /* Remove the first fragment from the reassembly queue. */ __skb_unlink(f_frag, f_frag->list); - - do { + do { pnext = pos->next; - /* Remove the fragment from the reassembly queue. */ + /* Remove the fragment from the reassembly queue. */ __skb_unlink(pos, pos->list); - /* Break if we have reached the last fragment. */ - if (pos == l_frag) { break; } + /* Break if we have reached the last fragment. */ + if (pos == l_frag) + break; pos->next = pnext; pos = pnext; } while (1); - event = (sctp_ulpevent_t *)f_frag->cb; - - return (event); + event = (sctp_ulpevent_t *) f_frag->cb; -} /* sctp_make_reassembled_event() */ + return event; +} -/* Helper function to check if an incoming chunk has filled up the last - * missing fragment in a SCTP datagram and return the corresponding event. +/* Helper function to check if an incoming chunk has filled up the last + * missing fragment in a SCTP datagram and return the corresponding event. */ -static inline sctp_ulpevent_t * -sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_t *ulpq) +static inline sctp_ulpevent_t *sctp_ulpqueue_retrieve_reassembled(sctp_ulpqueue_t *ulpq) { struct sk_buff *pos, *tmp; sctp_ulpevent_t *cevent; struct sk_buff *first_frag = NULL; - uint32_t ctsn, next_tsn; - int flags __attribute ((unused)); + __u32 ctsn, next_tsn; + unsigned long flags __attribute ((unused)); sctp_ulpevent_t *retval = NULL; /* Initialized to 0 just to avoid compiler warning message. Will - * never be used with this value. It is referenced only after it + * never be used with this value. It is referenced only after it * is set when we find the first fragment of a message. */ next_tsn = 0; sctp_spin_lock_irqsave(&ulpq->reasm.lock, flags); - /* The chunks are held in the reasm queue sorted by TSN. + + /* The chunks are held in the reasm queue sorted by TSN. * Walk through the queue sequentially and look for a sequence of - * fragmented chunks that complete a datagram. + * fragmented chunks that complete a datagram. * 'first_frag' and next_tsn are reset when we find a chunk which * is the first fragment of a datagram. Once these 2 fields are set * we expect to find the remaining middle fragments and the last * fragment in order. If not, first_frag is reset to NULL and we - * start the next pass when we find another first fragment. + * start the next pass when we find another first fragment. */ sctp_skb_for_each(pos, &ulpq->reasm, tmp) { - cevent = (sctp_ulpevent_t *)pos->cb; + cevent = (sctp_ulpevent_t *) pos->cb; ctsn = cevent->sndrcvinfo.sinfo_tsn; switch (cevent->chunk_flags & SCTP_DATA_FRAG_MASK) { case SCTP_DATA_FIRST_FRAG: first_frag = pos; - next_tsn = ctsn+1; + next_tsn = ctsn + 1; break; + case SCTP_DATA_MIDDLE_FRAG: - if ((first_frag) && (ctsn == next_tsn)) { + if ((first_frag) && (ctsn == next_tsn)) next_tsn++; - } else { + else first_frag = NULL; - } break; + case SCTP_DATA_LAST_FRAG: - if ((first_frag) && (ctsn == next_tsn)) { + if ((first_frag) && (ctsn == next_tsn)) retval = sctp_make_reassembled_event( - first_frag, pos); - } else { + first_frag, pos); + else first_frag = NULL; - } break; - } - - /* We have the reassembled event. There is no need to look - * further. + }; + + /* We have the reassembled event. There is no need to look + * further. */ - if (retval) { break; } - } + if (retval) + break; + } sctp_spin_unlock_irqrestore(&ulpq->reasm.lock, flags); - return (retval); - -} /* sctp_ulpqueue_retrieve_reassembled() */ + return retval; +} -/* Helper function to reassemble chunks. Hold chunks on the reasm queue that - * need reassembling. +/* Helper function to reassemble chunks. Hold chunks on the reasm queue that + * need reassembling. */ -static inline sctp_ulpevent_t * -sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +static inline sctp_ulpevent_t *sctp_ulpqueue_reasm(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) { sctp_ulpevent_t *retval = NULL; - /* FIXME: We should be using some new chunk structure here + /* FIXME: We should be using some new chunk structure here * instead of carrying chunk fields in the event structure. - * This is temporary as it is too painful to change everything + * This is temporary as it is too painful to change everything * at once. */ - /* Check if this is part of a fragmented message. */ - if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) { + /* Check if this is part of a fragmented message. */ + if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) return event; - } sctp_ulpqueue_store_reasm(ulpq, event); retval = sctp_ulpqueue_retrieve_reassembled(ulpq); return retval; - -} /* sctp_ulpqueue_reasm() */ - +} /* Helper function to gather skbs that have possibly become - * ordered by an an incoming chunk. + * ordered by an an incoming chunk. */ -static inline void -sctp_ulpqueue_retrieve_ordered(sctp_ulpqueue_t *ulpq, - sctp_ulpevent_t *event) +static inline void sctp_ulpqueue_retrieve_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) { struct sk_buff *pos, *tmp; sctp_ulpevent_t *cevent; - uint16_t sid, csid; - uint16_t ssn, cssn; - int flags __attribute ((unused)); + __u16 sid, csid; + __u16 ssn, cssn; + unsigned long flags __attribute ((unused)); sid = event->sndrcvinfo.sinfo_stream; ssn = event->sndrcvinfo.sinfo_ssn; - /* We are holding the chunks by stream, by SSN. */ + /* We are holding the chunks by stream, by SSN. */ sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); sctp_skb_for_each(pos, &ulpq->lobby, tmp) { - cevent = (sctp_ulpevent_t *)pos->cb; + cevent = (sctp_ulpevent_t *) pos->cb; csid = cevent->sndrcvinfo.sinfo_stream; cssn = cevent->sndrcvinfo.sinfo_ssn; - - /* Have we gone too far? */ - if (csid > sid) { break; } - /* Have we not gone far enough? */ - if (csid < sid) { continue; } + /* Have we gone too far? */ + if (csid > sid) + break; + + /* Have we not gone far enough? */ + if (csid < sid) + continue; + + if (cssn != ulpq->ssn[sid]) + break; - if (cssn != ulpq->ssn[sid]) { break; } - ulpq->ssn[sid]++; __skb_unlink(pos, pos->list); - - /* Attach all gathered skbs to the event. */ + + /* Attach all gathered skbs to the event. */ __skb_queue_tail(event->parent->list, pos); - - } + } sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); - -} /* sctp_ulpqueue_retrieve_ordered() */ - +} /* Helper function to store chunks needing ordering. */ -static inline void -sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq, - sctp_ulpevent_t *event) +static inline void sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) { struct sk_buff *pos, *tmp; sctp_ulpevent_t *cevent; - uint16_t sid, csid; - uint16_t ssn, cssn; - int flags __attribute ((unused)); - - + __u16 sid, csid; + __u16 ssn, cssn; + unsigned long flags __attribute ((unused)); + sid = event->sndrcvinfo.sinfo_stream; - ssn = event->sndrcvinfo.sinfo_ssn; + ssn = event->sndrcvinfo.sinfo_ssn; sctp_spin_lock_irqsave(&ulpq->lobby.lock, flags); @@ -466,77 +420,60 @@ sctp_ulpqueue_store_ordered(sctp_ulpqueue_t *ulpq, * stream ID and then by SSN. */ sctp_skb_for_each(pos, &ulpq->lobby, tmp) { - cevent = (sctp_ulpevent_t *)pos->cb; + cevent = (sctp_ulpevent_t *) pos->cb; csid = cevent->sndrcvinfo.sinfo_stream; cssn = cevent->sndrcvinfo.sinfo_ssn; - if (csid > sid) { break; } - if (csid == sid && SSN_lt(ssn, cssn)) { break;} - + if (csid > sid) + break; + if (csid == sid && SSN_lt(ssn, cssn)) + break; } - - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->lobby)) { + + /* If the queue is empty, we have a different function to call. */ + if (skb_peek(&ulpq->lobby)) __skb_insert(event->parent, pos->prev, pos, &ulpq->lobby); - } - else { + else __skb_queue_tail(&ulpq->lobby, event->parent); - } - sctp_spin_unlock_irqrestore(&ulpq->lobby.lock, flags); +} -} /* sctp_ulpqueue_store_ordered() */ - -static inline sctp_ulpevent_t * -sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, sctp_ulpevent_t *event) +static inline sctp_ulpevent_t *sctp_ulpqueue_order(sctp_ulpqueue_t *ulpq, + sctp_ulpevent_t *event) { - uint16_t sid; - uint16_t ssn; - + __u16 sid, ssn; - /* FIXME: We should be using some new chunk structure here + /* FIXME: We should be using some new chunk structure here * instead of carrying chunk fields in the event structure. - * This is temporary as it is too painful to change everything + * This is temporary as it is too painful to change everything * at once. - */ - - - /* Check if this message needs ordering. */ - if (SCTP_DATA_UNORDERED & event->chunk_flags) { - return event; - } - - /* Note: The stream ID must be verified before this routine. */ - sid = event->sndrcvinfo.sinfo_stream; - ssn = event->sndrcvinfo.sinfo_ssn; - - /* Is this the expected SSN for this stream ID? */ - - if (ssn != ulpq->ssn[sid]) { - - /* We've received something out of order, so find where it - * needs to be placed. We order by stream and then by SSN. - */ - - sctp_ulpqueue_store_ordered(ulpq, event); - - return NULL; - } - - /* Mark that the next chunk has been found. */ - ulpq->ssn[sid]++; + */ - /* Go find any other chunks that were waiting for - * ordering. - */ - - sctp_ulpqueue_retrieve_ordered(ulpq, event); + /* Check if this message needs ordering. */ + if (SCTP_DATA_UNORDERED & event->chunk_flags) + return event; - return event; - -} /* sctp_ulpqueue_order() */ + /* Note: The stream ID must be verified before this routine. */ + sid = event->sndrcvinfo.sinfo_stream; + ssn = event->sndrcvinfo.sinfo_ssn; + /* Is this the expected SSN for this stream ID? */ + if (ssn != ulpq->ssn[sid]) { + /* We've received something out of order, so find where it + * needs to be placed. We order by stream and then by SSN. + */ + sctp_ulpqueue_store_ordered(ulpq, event); + return NULL; + } + /* Mark that the next chunk has been found. */ + ulpq->ssn[sid]++; + /* Go find any other chunks that were waiting for + * ordering. + */ + sctp_ulpqueue_retrieve_ordered(ulpq, event); + return event; +} -- cgit v1.2.3 From c8885cbb798fe54d6f935121560393b2e228b03a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:00:24 -0700 Subject: net/sctp/sctp_sm_statefuns.c: Remove bogus use of unused attribute with a label. --- net/sctp/sctp_sm_statefuns.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/sctp/sctp_sm_statefuns.c b/net/sctp/sctp_sm_statefuns.c index 3542119f998c..49cf5c4aa09c 100644 --- a/net/sctp/sctp_sm_statefuns.c +++ b/net/sctp/sctp_sm_statefuns.c @@ -786,9 +786,6 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, SCTP_TRANSPORT(link)); return SCTP_DISPOSITION_CONSUME; - -nomem:__attribute__((unused)) - return SCTP_DISPOSITION_NOMEM; } /* Populate the verification/tie tags based on overlapping INIT @@ -1962,7 +1959,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, datalen -= sizeof(sctp_data_chunk_t); if (!asoc->rwnd || (datalen > asoc->frag_point)) { - SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %d, " + SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %Zd, " "rwnd: %d\n", tsn, datalen, asoc->rwnd); goto discard_noforce; } -- cgit v1.2.3 From fb2a8dcdbe6e63fb55f082efbd4d234a82a3d30d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:09:49 -0700 Subject: net/sctp/sctp_protocol.c: Fix typo from cleanups. --- net/sctp/sctp_protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sctp_protocol.c b/net/sctp/sctp_protocol.c index 920af0ddf077..bf39984248b8 100644 --- a/net/sctp/sctp_protocol.c +++ b/net/sctp/sctp_protocol.c @@ -200,7 +200,7 @@ static void sctp_get_local_addr_list(sctp_protocol_t *proto) /* Free the existing local addresses. */ static void __sctp_free_local_addr_list(sctp_protocol_t *proto) { - astruct sockaddr_storage_list *addr; + struct sockaddr_storage_list *addr; list_t *pos, *temp; list_for_each_safe(pos, temp, &proto->local_addr_list) { -- cgit v1.2.3 From c5b40502cc5e215aa9b14126352f63063a5d9d45 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:11:12 -0700 Subject: net/sctp/sctp_sm_sideeffect.c: Kill unusued variable in sctp_side_effects. --- net/sctp/sctp_sm_sideeffect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sctp/sctp_sm_sideeffect.c b/net/sctp/sctp_sm_sideeffect.c index 5f568dd877c3..e206b83675e6 100644 --- a/net/sctp/sctp_sm_sideeffect.c +++ b/net/sctp/sctp_sm_sideeffect.c @@ -167,7 +167,6 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, sctp_cmd_seq_t *commands, int priority) { - sctp_chunk_t *chunk = (sctp_chunk_t *) event_arg; int error; /* FIXME - Most of the dispositions left today would be categorized -- cgit v1.2.3 From 47fb96e7c81ac2073a3f8bb7037d33c371b0f763 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:15:09 -0700 Subject: net/sctp/sctp_tsnmap.c: Fix typo from cleanups. --- net/sctp/sctp_tsnmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sctp_tsnmap.c b/net/sctp/sctp_tsnmap.c index 52523c80289f..c4d1970ad70d 100644 --- a/net/sctp/sctp_tsnmap.c +++ b/net/sctp/sctp_tsnmap.c @@ -74,7 +74,7 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) return retval; fail_map: - kfree retval; + kfree(retval); fail: return NULL; -- cgit v1.2.3 From 3ec411f9bfd386a30f88c5530b56a8594adfd3f8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:15:49 -0700 Subject: net/sctp/sctp_sm_make_chunk.c: Kill unused variable in sctp_make_data_empty. --- net/sctp/sctp_sm_make_chunk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sctp/sctp_sm_make_chunk.c b/net/sctp/sctp_sm_make_chunk.c index de999bd8a54b..51850cbf77bb 100644 --- a/net/sctp/sctp_sm_make_chunk.c +++ b/net/sctp/sctp_sm_make_chunk.c @@ -588,7 +588,6 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len) { - sctp_chunk_t *retval; __u16 ssn; __u8 flags = SCTP_DATA_NOT_FRAG; -- cgit v1.2.3 From 403307c4a28f841059080da2e7576a978685348a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:19:10 -0700 Subject: net/sctp/sctp_socket.c: Fix printf string for size_t. - also fix sctp.h declaration type of sctp_get_port --- include/net/sctp/sctp.h | 2 +- net/sctp/sctp_socket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 8c8abb0251a5..c23ff6488edf 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -123,7 +123,7 @@ extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, */ extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); extern int sctp_inet_listen(struct socket *sock, int backlog); -extern int sctp_get_port(struct sock *sk, unsigned short snum); +extern long sctp_get_port(struct sock *sk, unsigned short snum); extern void sctp_write_space(struct sock *sk); extern unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index e65150cf2933..07b2b137a4a0 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -800,7 +800,7 @@ int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) associd = sinfo->sinfo_assoc_id; } - SCTP_DEBUG_PRINTK("msg_len: %d, sinfo_flags: 0x%x\n", + SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); /* If MSG_EOF|MSG_ABORT is set, no data can be sent. Disallow -- cgit v1.2.3 From 35650676890c2c0c11b73e51d6a1a642d33f3d02 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:33:48 -0700 Subject: net/sctp/sctp_socket.c: Fix sctp_get_port types, static private funcs. --- include/net/sctp/sctp.h | 1 - include/net/sctp/sctp_structs.h | 3 -- net/sctp/sctp_socket.c | 63 ++++++++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c23ff6488edf..185e39ee064c 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -123,7 +123,6 @@ extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, */ extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); extern int sctp_inet_listen(struct socket *sock, int backlog); -extern long sctp_get_port(struct sock *sk, unsigned short snum); extern void sctp_write_space(struct sock *sk); extern unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); diff --git a/include/net/sctp/sctp_structs.h b/include/net/sctp/sctp_structs.h index aa44b8da165f..bb7715795c81 100644 --- a/include/net/sctp/sctp_structs.h +++ b/include/net/sctp/sctp_structs.h @@ -1534,9 +1534,6 @@ typedef struct sctp_cmsgs { struct sctp_sndrcvinfo *info; } sctp_cmsgs_t; -int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs); - - /* Structure for tracking memory objects */ typedef struct { char *label; diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index 07b2b137a4a0..92842858ad26 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -136,6 +136,8 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) return retval; } +static long sctp_get_port_local(struct sock *, unsigned short); + /* Bind a local address either to an endpoint or to an association. */ static int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_len) { @@ -223,10 +225,10 @@ static int sctp_do_bind(struct sock *sk, sockaddr_storage_t *newaddr, int addr_l sctp_sk_addr_set(sk, &tmpaddr, &saveaddr); /* Make sure we are allowed to bind here. - * The function sctp_get_port() does duplicate address + * The function sctp_get_port_local() does duplicate address * detection. */ - if ((ret = sctp_get_port(sk, *snum))) { + if ((ret = sctp_get_port_local(sk, *snum))) { sctp_sk_addr_restore(sk, &saveaddr); if (ret == (long) sk) { /* This endpoint has a conflicting address. */ @@ -665,7 +667,7 @@ static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. */ -void sctp_close(struct sock *sk, long timeout) +static void sctp_close(struct sock *sk, long timeout) { sctp_endpoint_t *ep; sctp_association_t *asoc; @@ -733,7 +735,9 @@ void sctp_close(struct sock *sk, long timeout) /* BUG: We do not implement timeouts. */ /* BUG: We do not implement the equivalent of wait_for_tcp_memory(). */ -int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) +static int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); + +static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) { sctp_opt_t *sp; sctp_endpoint_t *ep; @@ -1097,8 +1101,8 @@ do_interrupted: * flags - flags sent or received with the user message, see Section * 5 for complete description of the flags. */ -int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, - int flags, int *addr_len) +static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, + int noblock, int flags, int *addr_len) { sctp_ulpevent_t *event = NULL; struct sk_buff *skb; @@ -1231,8 +1235,8 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int o * optval - the buffer to store the value of the option. * optlen - the size of the buffer. */ -int sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, - int optlen) +static int sctp_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) { int retval = 0; char * tmp; @@ -1315,19 +1319,19 @@ out_nounlock: } /* FIXME: Write comments. */ -int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +static int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { return -EOPNOTSUPP; /* STUB */ } /* FIXME: Write comments. */ -int sctp_disconnect(struct sock *sk, int flags) +static int sctp_disconnect(struct sock *sk, int flags) { return -EOPNOTSUPP; /* STUB */ } /* FIXME: Write comments. */ -struct sock *sctp_accept(struct sock *sk, int flags, int *err) +static struct sock *sctp_accept(struct sock *sk, int flags, int *err) { int error = -EOPNOTSUPP; @@ -1336,7 +1340,7 @@ struct sock *sctp_accept(struct sock *sk, int flags, int *err) } /* FIXME: Write Comments. */ -int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { return -EOPNOTSUPP; /* STUB */ } @@ -1345,7 +1349,7 @@ int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) * initialized the SCTP-specific portion of the sock. * The sock structure should already be zero-filled memory. */ -int sctp_init_sock(struct sock *sk) +static int sctp_init_sock(struct sock *sk) { sctp_endpoint_t *ep; sctp_protocol_t *proto; @@ -1430,7 +1434,7 @@ int sctp_init_sock(struct sock *sk) } /* Cleanup any SCTP per socket resources. */ -int sctp_destroy_sock(struct sock *sk) +static int sctp_destroy_sock(struct sock *sk) { sctp_endpoint_t *ep; @@ -1444,7 +1448,7 @@ int sctp_destroy_sock(struct sock *sk) } /* FIXME: Comments needed. */ -void sctp_shutdown(struct sock *sk, int how) +static void sctp_shutdown(struct sock *sk, int how) { /* UDP-style sockets do not support shutdown. */ /* STUB */ @@ -1565,7 +1569,7 @@ static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optv } /* Helper routine to branch off an association to a new socket. */ -int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +static int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) { struct sock *oldsk = assoc->base.sk; struct sock *newsk; @@ -1654,8 +1658,8 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval return 0; } -int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, - int *optlen) +static int sctp_getsockopt(struct sock *sk, int level, int optname, + char *optval, int *optlen) { int retval = 0; sctp_protocol_t *proto = sctp_get_protocol(); @@ -1714,12 +1718,12 @@ int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, return retval; } -void sctp_hash(struct sock *sk) +static void sctp_hash(struct sock *sk) { /* STUB */ } -void sctp_unhash(struct sock *sk) +static void sctp_unhash(struct sock *sk) { /* STUB */ } @@ -1736,7 +1740,7 @@ void sctp_unhash(struct sock *sk) * link to the socket (struct sock) that uses it, the port number and * a fastreuse flag (FIXME: NPI ipg). */ -long sctp_get_port(struct sock *sk, unsigned short snum) +static long sctp_get_port_local(struct sock *sk, unsigned short snum) { sctp_bind_hashbucket_t *head; /* hash list */ sctp_bind_bucket_t *pp; /* hash list port iterator */ @@ -1916,6 +1920,13 @@ fail: return ret; } +static int sctp_get_port(struct sock *sk, unsigned short snum) +{ + long ret = sctp_get_port_local(sk, snum); + + return (ret ? 1 : 0); +} + /* * 3.1.3 listen() - UDP Style Syntax * @@ -1923,7 +1934,7 @@ fail: * An application uses listen() to mark a socket as being able to * accept new associations. */ -int sctp_seqpacket_listen(struct sock *sk, int backlog) +static int sctp_seqpacket_listen(struct sock *sk, int backlog) { sctp_opt_t *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; @@ -2073,7 +2084,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi } /* FIXME: Commments! */ -__inline__ void __sctp_put_port(struct sock *sk) +static __inline__ void __sctp_put_port(struct sock *sk) { sctp_protocol_t *sctp_proto = sctp_get_protocol(); sctp_bind_hashbucket_t *head = @@ -2109,7 +2120,7 @@ void sctp_put_port(struct sock *sk) * One of those addresses will be the primary address for the association. * This automatically enables the multihoming capability of SCTP. */ -int sctp_autobind(struct sock *sk) +static int sctp_autobind(struct sock *sk) { sockaddr_storage_t autoaddr; int addr_len = 0; @@ -2180,7 +2191,7 @@ int sctp_autobind(struct sock *sk) * msg_control * points here */ -int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) +static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) { struct cmsghdr *cmsg; @@ -2371,7 +2382,7 @@ out: * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) { int error; struct sk_buff *skb; -- cgit v1.2.3 From 2d00927b8152781e0bbb7e23a5afd761325a736d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Aug 2002 11:37:25 -0700 Subject: net/sctp/sctp_socket.c: Mark sctp_skb_recv_datagram static. --- net/sctp/sctp_socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sctp/sctp_socket.c b/net/sctp/sctp_socket.c index 92842858ad26..a619bd4d3cde 100644 --- a/net/sctp/sctp_socket.c +++ b/net/sctp/sctp_socket.c @@ -85,8 +85,6 @@ static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); -struct sk_buff * sctp_skb_recv_datagram(struct sock *sk, int flags, - int noblock, int *err); static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname, int *addr_len, struct sk_buff *skb); static inline void sctp_sk_addr_set(struct sock *, @@ -1101,6 +1099,8 @@ do_interrupted: * flags - flags sent or received with the user message, see Section * 5 for complete description of the flags. */ +static struct sk_buff * sctp_skb_recv_datagram(struct sock *, int, int, int *); + static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags, int *addr_len) { -- cgit v1.2.3