diff options
| author | David S. Miller <davem@nuts.ninka.net> | 2003-07-18 11:29:13 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-07-18 11:29:13 -0700 |
| commit | c09d36c8dc765fb1558a9f529a9c1ace2403c50d (patch) | |
| tree | 992602fbce463eb1cc3860f337a37813e1059699 | |
| parent | 1d02c2c0dfe098493f1359da83f1f2ba551f40a6 (diff) | |
| parent | 9bb688143058b9eae52d2f77219dd4fdd612ccb0 (diff) | |
Merge http://linux-lksctp.bkbits.net/lksctp-2.5
into nuts.ninka.net:/home/davem/src/BK/sctp-2.5
| -rw-r--r-- | include/net/sctp/sctp.h | 20 | ||||
| -rw-r--r-- | include/net/sctp/sm.h | 3 | ||||
| -rw-r--r-- | include/net/sctp/structs.h | 9 | ||||
| -rw-r--r-- | include/net/sctp/ulpevent.h | 5 | ||||
| -rw-r--r-- | include/net/sctp/user.h | 300 | ||||
| -rw-r--r-- | net/sctp/associola.c | 6 | ||||
| -rw-r--r-- | net/sctp/chunk.c | 4 | ||||
| -rw-r--r-- | net/sctp/input.c | 2 | ||||
| -rw-r--r-- | net/sctp/ipv6.c | 135 | ||||
| -rw-r--r-- | net/sctp/output.c | 37 | ||||
| -rw-r--r-- | net/sctp/outqueue.c | 14 | ||||
| -rw-r--r-- | net/sctp/protocol.c | 22 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 10 | ||||
| -rw-r--r-- | net/sctp/sm_sideeffect.c | 2 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 4 | ||||
| -rw-r--r-- | net/sctp/socket.c | 180 | ||||
| -rw-r--r-- | net/sctp/transport.c | 1 | ||||
| -rw-r--r-- | net/sctp/ulpevent.c | 232 | ||||
| -rw-r--r-- | net/sctp/ulpqueue.c | 9 |
19 files changed, 553 insertions, 442 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 3793352764c0..506fd2cb1305 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -588,6 +588,7 @@ struct sctp6_sock { #endif /* CONFIG_IPV6 */ #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) +#define sctp_opt2sk(__sp) &container_of(__sp, struct sctp_sock, sctp)->sk /* Is a socket of this style? */ #define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) @@ -611,4 +612,23 @@ int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) return sk->sk_state == state; } +/* Map v4-mapped v6 address back to v4 address */ +static inline void sctp_v6_map_v4(union sctp_addr *addr) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = addr->v6.sin6_port; + addr->v4.sin_addr.s_addr = addr->v6.sin6_addr.s6_addr32[3]; +} + +/* Map v4 address to v4-mapped v6 address */ +static inline void sctp_v4_map_v6(union sctp_addr *addr) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = addr->v4.sin_port; + addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + addr->v6.sin6_addr.s6_addr32[0] = 0; + addr->v6.sin6_addr.s6_addr32[1] = 0; + addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); +} + #endif /* __net_sctp_h__ */ diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index e9814d30bd46..a779754deaf6 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -231,7 +231,8 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *, struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, const __u32); struct sctp_chunk *sctp_make_sack(const struct sctp_association *); -struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk); struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, const struct sctp_chunk *); struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 94bebc0b7ce0..aae255de586b 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -260,11 +260,13 @@ struct sctp_af { struct sock *sk); void (*to_sk_daddr) (union sctp_addr *, struct sock *sk); - int (*addr_valid) (union sctp_addr *); + int (*addr_valid) (union sctp_addr *, + struct sctp_opt *); sctp_scope_t (*scope) (union sctp_addr *); void (*inaddr_any) (union sctp_addr *, unsigned short); int (*is_any) (const union sctp_addr *); - int (*available) (const union sctp_addr *); + int (*available) (union sctp_addr *, + struct sctp_opt *); int (*skb_iif) (const struct sk_buff *sk); int (*is_ce) (const struct sk_buff *sk); void (*seq_dump_addr)(struct seq_file *seq, @@ -282,7 +284,7 @@ int sctp_register_af(struct sctp_af *); struct sctp_pf { void (*event_msgname)(struct sctp_ulpevent *, char *, int *); void (*skb_msgname) (struct sk_buff *, char *, int *); - int (*af_supported) (sa_family_t); + int (*af_supported) (sa_family_t, struct sctp_opt *); int (*cmp_addr) (const union sctp_addr *, const union sctp_addr *, struct sctp_opt *); @@ -291,6 +293,7 @@ struct sctp_pf { int (*supported_addrs)(const struct sctp_opt *, __u16 *); struct sock *(*create_accept_sk) (struct sock *sk, struct sctp_association *asoc); + void (*addr_v4map) (struct sctp_opt *, union sctp_addr *); struct sctp_af *af; }; diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index d3ad0c86583d..949a23835584 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -40,6 +40,7 @@ * Jon Grimm <jgrimm@us.ibm.com> * La Monte H.P. Yarroll <piggy@acm.org> * Karl Knutson <karl@athena.chicago.il.us> + * Sridhar Samudrala <sri@us.ibm.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -53,7 +54,6 @@ * growing this structure as it is at the maximum limit now. */ struct sctp_ulpevent { - struct sctp_association *asoc; struct sctp_sndrcvinfo sndrcvinfo; int msg_flags; int iif; @@ -72,9 +72,10 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) } struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); +void sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); +void sctp_queue_purge_ulpevents(struct sk_buff_head *list); struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 284ef27894ca..da96859dba92 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -1,38 +1,39 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. - * + * Copyright (c) 2001-2003 International Business Machines, Corp. + * Copyright (c) 2002 Intel Corp. + * * This file is part of the SCTP kernel reference Implementation - * + * * 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 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 + * + * 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. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <lksctp-developers@lists.sourceforge.net> - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll <piggy@acm.org> * R. Stewart <randall@sctp.chicago.il.us> * K. Morneau <kmorneau@cisco.com> @@ -41,61 +42,62 @@ * Jon Grimm <jgrimm@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> * Ryan Layer <rmlayer@us.ibm.com> - * - * + * Ardelle Fan <ardelle.fan@intel.com> + * Sridhar Samudrala <sri@us.ibm.com> + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -#include <linux/types.h> -#include <linux/socket.h> #ifndef __net_sctp_user_h__ #define __net_sctp_user_h__ +#include <linux/types.h> +#include <linux/socket.h> typedef void * sctp_assoc_t; /* The following symbols come from the Sockets API Extensions for - * SCTP <draft-ietf-tsvwg-sctpsocket-04.txt>. + * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>. */ enum sctp_optname { SCTP_RTOINFO, #define SCTP_RTOINFO SCTP_RTOINFO - SCTP_ASSOCRTXINFO, -#define SCTP_ASSOCRTXINFO SCTP_ASSOCRTXINFO + SCTP_ASSOCINFO, +#define SCTP_ASSOCINFO SCTP_ASSOCINFO 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_NODELAY, /* Get/set nodelay option. */ +#define SCTP_NODELAY SCTP_NODELAY + SCTP_AUTOCLOSE, +#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE 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_PRIMARY_ADDR, +#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR + SCTP_ADAPTION_LAYER, +#define SCTP_ADAPTION_LAYER SCTP_ADAPTION_LAYER 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_PEER_ADDR_PARAMS, +#define SCTP_PEER_ADDR_PARAMS SCTP_PEER_ADDR_PARAMS + SCTP_DEFAULT_SEND_PARAM, +#define SCTP_DEFAULT_SEND_PARAM SCTP_DEFAULT_SEND_PARAM + SCTP_EVENTS, +#define SCTP_EVENTS SCTP_EVENTS + SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ +#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG, /* Get/set maximum fragment. */ +#define SCTP_MAXSEG SCTP_MAXSEG 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. */ + /* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ + SCTP_SOCKOPT_BINDX_ADD = 100,/* 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 @@ -109,29 +111,8 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS - SCTP_NODELAY, /* Get/set nodelay option. */ -#define SCTP_NODELAY SCTP_NODELAY - SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ -#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR - SCTP_MAXSEG, /* Get/set maximum fragment. */ -#define SCTP_MAXSEG SCTP_MAXSEG }; - -/* - * 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) * @@ -152,7 +133,6 @@ struct sctp_initmsg { __u16 sinit_max_init_timeo; }; - /* * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * @@ -214,7 +194,6 @@ typedef enum sctp_cmsg_type { * following format: * */ - struct sctp_assoc_change { __u16 sac_type; __u16 sac_flags; @@ -267,11 +246,11 @@ struct sctp_paddr_change { * event that happened to the address. They include: */ enum sctp_spc_state { - ADDRESS_AVAILABLE, - ADDRESS_UNREACHABLE, - ADDRESS_REMOVED, - ADDRESS_ADDED, - ADDRESS_MADE_PRIM, + SCTP_ADDR_REACHABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, }; @@ -290,7 +269,6 @@ struct sctp_remote_error { __u16 sre_flags; __u32 sre_length; __u16 sre_error; - __u16 sre_len; sctp_assoc_t sre_assoc_id; __u8 sre_data[0]; }; @@ -324,7 +302,6 @@ struct sctp_send_failed { * 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, @@ -336,7 +313,6 @@ enum sctp_ssf_flags { * When a peer sends a SHUTDOWN, SCTP delivers this notification to * inform the application that it should cease sending data. */ - struct sctp_shutdown_event { __u16 sse_type; __u16 sse_flags; @@ -355,8 +331,8 @@ struct sctp_adaption_event { __u16 sai_type; __u16 sai_flags; __u32 sai_length; - __u32 sai_adaptation_bits; - sctp_assoc_t sse_assoc_id; + __u32 sai_adaption_ind; + sctp_assoc_t sai_assoc_id; }; /* @@ -366,8 +342,7 @@ struct sctp_adaption_event { * message this notification will be used to inidicate * various events. */ - -struct sctp_rcv_pdapi_event { +struct sctp_pdapi_event { __u16 pdapi_type; __u16 pdapi_flags; __u32 pdapi_length; @@ -404,14 +379,14 @@ union sctp_notification { __u16 sn_type; /* Notification type. */ __u16 sn_flags; __u32 sn_length; - } h; + } sn_header; struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_padr_change; + struct sctp_paddr_change sn_paddr_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; + struct sctp_pdapi_event sn_pdapi_event; }; /* Section 5.3.1 @@ -448,75 +423,25 @@ typedef enum sctp_sn_error { } 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; - __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 - * 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; - __s32 spinfo_state; - __u32 spinfo_cwnd; - __u32 spinfo_srtt; - __u32 spinfo_rto; - __u32 spinfo_mtu; -}; - -/* Peer addresses's state. */ -enum sctp_spinfo_state { - SCTP_INACTIVE, - SCTP_ACTIVE, -}; - -/* * 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. + * these parameters are used in RTO calculation. */ - struct sctp_rtoinfo { + 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) + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) * - * 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. + * This option is used to both examine and set various association and + * endpoint parameters. */ - struct sctp_assocparams { sctp_assoc_t sasoc_assoc_id; __u16 sasoc_asocmaxrxt; @@ -527,31 +452,81 @@ struct sctp_assocparams { }; /* - * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_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; +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; }; /* - * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * 7.1.10 Set Primary Address (SCTP_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_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +}; -struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; +/* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaption { + __u32 ssb_adaption_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * 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 { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; +}; + +/* + * 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; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +}; + +/* Peer addresses's state. */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_ACTIVE, }; /* @@ -575,34 +550,8 @@ struct sctp_status { 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 { - __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; - __u32 ssto_timeout; - __u16 ssto_streamid_start; - __u16 ssto_streamid_end; -}; - /* - * 8.3 8.5 get all peer/local addresses on a socket + * 8.3, 8.5 get all peer/local addresses on a socket * This parameter struct is for getsockopt */ struct sctp_getaddrs { @@ -624,8 +573,8 @@ enum sctp_msg_flags { * 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 +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 /* This is the structure that is passed as an argument(optval) to * getsockopt(SCTP_SOCKOPT_PEELOFF). @@ -636,6 +585,3 @@ typedef struct { } sctp_peeloff_arg_t; #endif /* __net_sctp_user_h__ */ - - - diff --git a/net/sctp/associola.c b/net/sctp/associola.c index aabeeae601a0..fa9ecdd2d856 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -556,12 +556,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, switch (command) { case SCTP_TRANSPORT_UP: transport->active = SCTP_ACTIVE; - spc_state = ADDRESS_AVAILABLE; + spc_state = SCTP_ADDR_REACHABLE; break; case SCTP_TRANSPORT_DOWN: transport->active = SCTP_INACTIVE; - spc_state = ADDRESS_UNREACHABLE; + spc_state = SCTP_ADDR_UNREACHABLE; break; default: @@ -877,7 +877,7 @@ void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk) /* Delete the association from the old endpoint's list of * associations. */ - list_del(&assoc->asocs); + list_del_init(&assoc->asocs); /* Decrement the backlog value for a TCP-style socket. */ if (sctp_style(oldsk, TCP)) diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 421561cabe4f..8e23ef559fad 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -85,7 +85,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) /* Release all references. */ list_for_each_safe(pos, temp, &msg->chunks) { - list_del(pos); + list_del_init(pos); chunk = list_entry(pos, struct sctp_chunk, frag_list); /* Check whether we _really_ need to notify. */ if (notify < 0) { @@ -294,7 +294,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, errout: list_for_each_safe(pos, temp, &msg->chunks) { - list_del(pos); + list_del_init(pos); chunk = list_entry(pos, struct sctp_chunk, frag_list); sctp_chunk_free(chunk); } diff --git a/net/sctp/input.c b/net/sctp/input.c index 8c4cc2c233a6..014327be95d1 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -150,7 +150,7 @@ int sctp_rcv(struct sk_buff *skb) * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!af->addr_valid(&src) || !af->addr_valid(&dest)) + if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 858f3b922ad3..3bce456b895f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -2,6 +2,7 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2002-2003 International Business Machines, Corp. + * Copyright (c) 2002-2003 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -15,7 +16,7 @@ * * 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. * @@ -32,14 +33,15 @@ * http://www.sf.net/projects/lksctp * * Written or modified by: - * Le Yanqun <yanqun.le@nokia.com> + * Le Yanqun <yanqun.le@nokia.com> * Hui Huang <hui.huang@nokia.com> * La Monte H.P. Yarroll <piggy@acm.org> * Sridhar Samudrala <sri@us.ibm.com> - * Jon Grimm <jgrimm@us.ibm.com> + * Jon Grimm <jgrimm@us.ibm.com> + * Ardelle Fan <ardelle.fan@intel.com> * * Based on: - * linux/net/ipv6/tcp_ipv6.c + * 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. @@ -172,7 +174,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - __FUNCTION__, skb, skb->len, + __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); SCTP_INC_STATS(SctpOutSCTPPacks); @@ -192,6 +194,9 @@ struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr); + if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) + fl.oif = daddr->v6.sin6_scope_id; + SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", __FUNCTION__, NIP6(fl.fl6_dst)); @@ -370,13 +375,28 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) /* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->rcv_saddr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + } } /* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->daddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->daddr.s6_addr32[0] = 0; + inet6_sk(sk)->daddr.s6_addr32[1] = 0; + inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->daddr = addr->v6.sin6_addr; + } } /* Initialize a sctp_addr from a dst_entry. */ @@ -390,13 +410,30 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, } /* Compare addresses exactly. - * FIXME: v4-mapped-v6. + * v4-mapped-v6 is also in consideration. */ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2) { - if (addr1->sa.sa_family != addr2->sa.sa_family) + if (addr1->sa.sa_family != addr2->sa.sa_family) { + if (addr1->sa.sa_family == AF_INET && + addr2->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr2->v6.sin6_addr)) { + if (addr2->v6.sin6_port == addr1->v4.sin_port && + addr2->v6.sin6_addr.s6_addr32[3] == + addr1->v4.sin_addr.s_addr) + return 1; + } + if (addr2->sa.sa_family == AF_INET && + addr1->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr1->v6.sin6_addr)) { + if (addr1->v6.sin6_port == addr2->v4.sin_port && + addr1->v6.sin6_addr.s6_addr32[3] == + addr2->v4.sin_addr.s_addr) + return 1; + } return 0; + } if (ipv6_addr_cmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; /* If this is a linklocal address, compare the scope_id. */ @@ -427,7 +464,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) } /* Should this be available for binding? */ -static int sctp_v6_available(const union sctp_addr *addr) +static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp) { int type; struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; @@ -435,6 +472,14 @@ static int sctp_v6_available(const union sctp_addr *addr) type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) return 1; + if (type == IPV6_ADDR_MAPPED) { + if (sp && !sp->v4mapped) + return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->available(addr, sp); + } if (!(type & IPV6_ADDR_UNICAST)) return 0; @@ -448,11 +493,22 @@ static int sctp_v6_available(const union sctp_addr *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v6_addr_valid(union sctp_addr *addr) +static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { int ret = ipv6_addr_type(&addr->v6.sin6_addr); - /* FIXME: v4-mapped-v6 address support. */ + /* Support v4-mapped-v6 address. */ + if (ret == IPV6_ADDR_MAPPED) { + /* Note: This routine is used in input, so v4-mapped-v6 + * are disallowed here when there is no sctp_opt. + */ + if (!sp || !sp->v4mapped) + return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); + } /* Is this a non-unicast address */ if (!(ret & IPV6_ADDR_UNICAST)) @@ -536,7 +592,7 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk, newnp->saddr = np->saddr; newnp->rcv_saddr = np->rcv_saddr; newinet->dport = htons(asoc->peer.port); - newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr; + sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk); /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. @@ -566,6 +622,13 @@ out: return newsk; } +/* Map v4 address to mapped v6 address */ +static void sctp_v6_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + if (sp->v4mapped && AF_INET == addr->sa.sa_family) + sctp_v4_map_v6(addr); +} + /* Where did this skb come from? */ static int sctp_v6_skb_iif(const struct sk_buff *skb) { @@ -606,25 +669,28 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, if (msgname) { union sctp_addr *addr; + struct sctp_association *asoc; + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet6_msgname(msgname, addrlen); sin6 = (struct sockaddr_in6 *)msgname; - sin6->sin6_port = htons(event->asoc->peer.port); - addr = &event->asoc->peer.primary_addr; + sin6->sin6_port = htons(asoc->peer.port); + addr = &asoc->peer.primary_addr; /* Note: If we go to a common v6 format, this code * will change. */ /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (AF_INET == addr->sa.sa_family) { - /* FIXME: Easy, but there was no way to test this - * yet. - */ + if (sctp_sk(asoc->base.sk)->v4mapped && + AF_INET == addr->sa.sa_family) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; return; } - sin6from = &event->asoc->peer.primary_addr.v6; + sin6from = &asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; @@ -644,16 +710,15 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, sh = (struct sctphdr *)skb->h.raw; sin6->sin6_port = sh->source; - /* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */ - if (__constant_htons(ETH_P_IP) == skb->protocol) { - /* FIXME: The latest I-D added options for two - * behaviors. - */ + /* Map ipv4 address into v4-mapped-on-v6 address. */ + if (sctp_sk(skb->sk)->v4mapped && + skb->nh.iph->version == 4) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = skb->nh.iph->saddr; return; } /* Otherwise, just copy the v6 address. */ - ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { struct sctp_ulpevent *ev = sctp_skb2event(skb); @@ -663,16 +728,15 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, } /* Do we support this AF? */ -static int sctp_inet6_af_supported(sa_family_t family) +static int sctp_inet6_af_supported(sa_family_t family, struct sctp_opt *sp) { - /* FIXME: v4-mapped-v6 addresses. The I-D is still waffling - * on what to do with sockaddr formats for PF_INET6 sockets. - * For now assume we'll support both. - */ switch (family) { case AF_INET6: - case AF_INET: return 1; + /* v4-mapped-v6 addresses */ + case AF_INET: + if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) + return 1; default: return 0; } @@ -716,7 +780,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = &container_of(opt, struct sctp6_sock, sctp)->sk; + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if @@ -730,7 +794,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) } af = opt->pf->af; } - return af->available(addr); + return af->available(addr, opt); } /* Verify that the provided sockaddr looks bindable. Common verification, @@ -746,7 +810,7 @@ static int sctp_inet6_send_verify(struct sctp_opt *opt, union sctp_addr *addr) else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = &container_of(opt, struct sctp6_sock, sctp)->sk; + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if @@ -863,6 +927,7 @@ static struct sctp_pf sctp_pf_inet6_specific = { .send_verify = sctp_inet6_send_verify, .supported_addrs = sctp_inet6_supported_addrs, .create_accept_sk = sctp_v6_create_accept_sk, + .addr_v4map = sctp_v6_addr_v4map, .af = &sctp_ipv6_specific, }; diff --git a/net/sctp/output.c b/net/sctp/output.c index bc321f6019fd..262a6aa06b49 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -97,6 +97,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, packet->source_port = sport; packet->destination_port = dport; skb_queue_head_init(&packet->chunks); + packet->size = SCTP_IP_OVERHEAD; packet->vtag = 0; packet->ecn_capable = 0; packet->get_prepend_chunk = NULL; @@ -219,9 +220,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, /* Both control chunks and data chunks with TSNs are * non-fragmentable. */ - if (packet_empty) { - - /* We no longer do refragmentation at all. + if (packet_empty || !sctp_chunk_is_data(chunk)) { + /* We no longer do re-fragmentation. * Just fragment at the IP layer, if we * actually hit this condition */ @@ -229,7 +229,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, packet->ipfragok = 1; goto append; - } else { /* !packet_empty */ + } else { retval = SCTP_XMIT_PMTU_FULL; goto finish; } @@ -283,20 +283,18 @@ int sctp_packet_transmit(struct sctp_packet *packet) __u8 has_data = 0; struct dst_entry *dst; - /* Do NOT generate a chunkless packet... */ - if (skb_queue_empty(&packet->chunks)) + /* Do NOT generate a chunkless packet. */ + chunk = (struct sctp_chunk *)skb_peek(&packet->chunks); + if (unlikely(!chunk)) return err; /* Set up convenience variables... */ - chunk = (struct sctp_chunk *) (packet->chunks.next); sk = chunk->skb->sk; /* Allocate the new skb. */ nskb = dev_alloc_skb(packet->size); - if (!nskb) { - err = -ENOMEM; - goto out; - } + if (!nskb) + goto nomem; /* Make sure the outbound skb has enough header room reserved. */ skb_reserve(nskb, SCTP_IP_OVERHEAD); @@ -468,9 +466,11 @@ int sctp_packet_transmit(struct sctp_packet *packet) if (!nskb->dst) goto no_route; - SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", + SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n", nskb->len); + (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); + out: packet->size = SCTP_IP_OVERHEAD; return err; @@ -486,7 +486,20 @@ no_route: * required. */ /* err = -EHOSTUNREACH; */ +err: + /* Control chunks are unreliable so just drop them. DATA chunks + * will get resent or dropped later. + */ + + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + if (!sctp_chunk_is_data(chunk)) + sctp_chunk_free(chunk); + } goto out; +nomem: + err = -ENOMEM; + printk("%s alloc_skb failed.\n", __FUNCTION__); + goto err; } /******************************************************************** diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index b7bd2bf6e6a2..d26292af9ff1 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -258,7 +258,7 @@ void sctp_outq_teardown(struct sctp_outq *q) /* Throw away chunks that have been gap ACKed. */ list_for_each_safe(lchunk, temp, &q->sacked) { - list_del(lchunk); + list_del_init(lchunk); chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); sctp_datamsg_fail(chunk, q->error); @@ -267,7 +267,7 @@ void sctp_outq_teardown(struct sctp_outq *q) /* Throw away any chunks in the retransmit queue. */ list_for_each_safe(lchunk, temp, &q->retransmit) { - list_del(lchunk); + list_del_init(lchunk); chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); sctp_datamsg_fail(chunk, q->error); @@ -445,7 +445,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, /* Move the chunk to the retransmit queue. The chunks * on the retransmit queue is always kept in order. */ - list_del(lchunk); + list_del_init(lchunk); sctp_retransmit_insert(lchunk, q); } } @@ -1007,7 +1007,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; struct sctp_chunk *tchunk; - struct list_head *lchunk, *transport_list, *pos; + struct list_head *lchunk, *transport_list, *pos, *temp; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; __u32 highest_tsn, highest_new_tsn; @@ -1115,14 +1115,12 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) "%p is 0x%x.\n", __FUNCTION__, asoc, ctsn); /* Throw away stuff rotting on the sack queue. */ - list_for_each(lchunk, &q->sacked) { + list_for_each_safe(lchunk, temp, &q->sacked) { tchunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); - if (TSN_lte(tsn, ctsn)) { - lchunk = lchunk->prev; + if (TSN_lte(tsn, ctsn)) sctp_chunk_free(tchunk); - } } /* ii) Set rwnd equal to the newly received a_rwnd minus the diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 604215bd21d4..5e0c6aa9d100 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -340,7 +340,7 @@ static int sctp_v4_is_any(const union sctp_addr *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v4_addr_valid(union sctp_addr *addr) +static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) @@ -350,7 +350,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) } /* Should this be available for binding? */ -static int sctp_v4_available(const union sctp_addr *addr) +static int sctp_v4_available(union sctp_addr *addr, struct sctp_opt *sp) { int ret = inet_addr_type(addr->v4.sin_addr.s_addr); @@ -580,6 +580,12 @@ out: return newsk; } +/* Map address, empty for v4 family */ +static void sctp_v4_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + /* Empty */ +} + /* Dump the v4 addr to the seq file. */ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { @@ -685,10 +691,13 @@ static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname, struct sockaddr_in *sin, *sinfrom; if (msgname) { + struct sctp_association *asoc; + + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet_msgname(msgname, addr_len); sin = (struct sockaddr_in *)msgname; - sinfrom = &event->asoc->peer.primary_addr.v4; - sin->sin_port = htons(event->asoc->peer.port); + sinfrom = &asoc->peer.primary_addr.v4; + sin->sin_port = htons(asoc->peer.port); sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; } } @@ -709,7 +718,7 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len) } /* Do we support this AF? */ -static int sctp_inet_af_supported(sa_family_t family) +static int sctp_inet_af_supported(sa_family_t family, struct sctp_opt *sp) { /* PF_INET only supports AF_INET addresses. */ return (AF_INET == family); @@ -737,7 +746,7 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1, */ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) { - return sctp_v4_available(addr); + return sctp_v4_available(addr, opt); } /* Verify that sockaddr looks sendable. Common verification has already @@ -783,6 +792,7 @@ static struct sctp_pf sctp_pf_inet = { .send_verify = sctp_inet_send_verify, .supported_addrs = sctp_inet_supported_addrs, .create_accept_sk = sctp_v4_create_accept_sk, + .addr_v4map = sctp_v4_addr_v4map, .af = &sctp_ipv4_specific, }; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 2408465dda8a..655c895b7ad8 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -667,7 +667,8 @@ nodata: } /* Make a SHUTDOWN chunk. */ -struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { struct sctp_chunk *retval; sctp_shutdownhdr_t shut; @@ -683,6 +684,9 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) retval->subh.shutdown_hdr = sctp_addto_chunk(retval, sizeof(shut), &shut); + + if (chunk) + retval->transport = chunk->transport; nodata: return retval; } @@ -1089,7 +1093,7 @@ void sctp_chunk_free(struct sctp_chunk *chunk) { /* Make sure that we are not on any list. */ skb_unlink((struct sk_buff *) chunk); - list_del(&chunk->transmitted_list); + list_del_init(&chunk->transmitted_list); /* Release our reference on the message tracker. */ if (chunk->msg) @@ -1850,7 +1854,7 @@ clean_up: /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - list_del(pos); + list_del_init(pos); sctp_transport_free(transport); } nomem: diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index b320c1c5e670..9a99495265f8 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -962,7 +962,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, asoc->overall_error_count = 0; /* Generate a SHUTDOWN chunk. */ - new_obj = sctp_make_shutdown(asoc); + new_obj = sctp_make_shutdown(asoc, chunk); if (!new_obj) goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 0e3f27b90020..7a20e554de4d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3862,7 +3862,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown( * in the Cumulative TSN Ack field the last sequential TSN it * has received from the peer. */ - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); if (!reply) goto nomem; @@ -4179,7 +4179,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, switch (asoc->state) { case SCTP_STATE_SHUTDOWN_SENT: - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); break; case SCTP_STATE_SHUTDOWN_ACK_SENT: diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 72029eb799eb..962699973875 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -156,6 +156,9 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk, if (id_asoc && (id_asoc != addr_asoc)) return NULL; + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)addr); + return transport; } @@ -206,7 +209,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, return NULL; /* Does this PF support this AF? */ - if (!opt->pf->af_supported(addr->sa.sa_family)) + if (!opt->pf->af_supported(addr->sa.sa_family, opt)) return NULL; /* If we get this far, af is valid. */ @@ -365,15 +368,15 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, 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")); + (SCTP_BINDX_ADD_ADDR == flags) ? "ADD" : + ((SCTP_BINDX_REM_ADDR == flags) ? "REM" : "BOGUS")); switch (flags) { - case BINDX_ADD_ADDR: + case SCTP_BINDX_ADD_ADDR: retval = sctp_bindx_add(sk, addrs, addrcnt); break; - case BINDX_REM_ADDR: + case SCTP_BINDX_REM_ADDR: retval = sctp_bindx_rem(sk, addrs, addrcnt); break; @@ -768,8 +771,8 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) } /* Clean up any skbs sitting on the receive queue. */ - skb_queue_purge(&sk->sk_receive_queue); - skb_queue_purge(&sctp_sk(sk)->pd_lobby); + sctp_queue_purge_ulpevents(&sk->sk_receive_queue); + sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); /* On a TCP-style socket, block for at most linger_time if set. */ if (sctp_style(sk, TCP) && timeout) @@ -1342,10 +1345,10 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, /* When only partial message is copied to the user, increase * rwnd by that amount. If all the data in the skb is read, - * rwnd is updated when the skb's destructor is called via - * sctp_ulpevent_free(). + * rwnd is updated when the event is freed. */ - sctp_assoc_rwnd_increase(event->asoc, copied); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) @@ -1354,7 +1357,18 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, msg->msg_flags &= ~MSG_EOR; out_free: - sctp_ulpevent_free(event); /* Free the skb. */ + if (flags & MSG_PEEK) { + /* Release the skb reference acquired after peeking the skb in + * sctp_skb_recv_datagram(). + */ + kfree_skb(skb); + } else { + /* Free the event which includes releasing the reference to + * the owner of the skb, freeing the skb and updating the + * rwnd. + */ + sctp_ulpevent_free(event); + } out: sctp_release_sock(sk); return err; @@ -1421,7 +1435,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, return 0; } -/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS) +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address of * an association, modify an address's heartbeat interval, force a @@ -1571,24 +1585,25 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Peer Primary Address (SCTP_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. */ -static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) +static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval, + int optlen) { - struct sctp_setpeerprim prim; + struct sctp_prim prim; struct sctp_transport *trans; - if (optlen != sizeof(struct sctp_setpeerprim)) + if (optlen != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - trans = sctp_addr_id2transport(sk, &prim.sspp_addr, prim.sspp_assoc_id); + trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); if (!trans) return -EINVAL; @@ -1682,8 +1697,8 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { * See [SCTP] for more information. * */ -static int sctp_setsockopt_assocrtx(struct sock *sk, char *optval, - int optlen) { +static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) +{ struct sctp_assocparams assocparams; struct sctp_association *asoc; @@ -1736,14 +1751,18 @@ static int sctp_setsockopt_assocrtx(struct sock *sk, char *optval, static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) { int val; + struct sctp_opt *sp = sctp_sk(sk); if (optlen < sizeof(int)) return -EINVAL; if (get_user(val, (int *)optval)) return -EFAULT; - /* FIXME: Put real support here. */ + if (val) + sp->v4mapped = 1; + else + sp->v4mapped = 0; - return -ENOPROTOOPT; + return 0; } /* @@ -1794,7 +1813,6 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int retval = 0; - char *tmp; SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", sk, optname); @@ -1814,38 +1832,25 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, 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); + optval, optlen, + SCTP_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); + optval, optlen, + SCTP_BINDX_REM_ADDR); break; case SCTP_DISABLE_FRAGMENTS: retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); break; - case SCTP_SET_EVENTS: + case SCTP_EVENTS: retval = sctp_setsockopt_events(sk, optval, optlen); break; @@ -1853,19 +1858,19 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_autoclose(sk, optval, optlen); break; - case SCTP_SET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); break; case SCTP_INITMSG: retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_setsockopt_peer_prim(sk, optval, optlen); + case SCTP_PRIMARY_ADDR: + retval = sctp_setsockopt_primary_addr(sk, optval, optlen); break; case SCTP_NODELAY: retval = sctp_setsockopt_nodelay(sk, optval, optlen); @@ -1873,8 +1878,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_RTOINFO: retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); break; - case SCTP_ASSOCRTXINFO: - retval = sctp_setsockopt_assocrtx(sk, optval, optlen); + case SCTP_ASSOCINFO: + retval = sctp_setsockopt_associnfo(sk, optval, optlen); break; case SCTP_I_WANT_MAPPED_V4_ADDR: retval = sctp_setsockopt_mappedv4(sk, optval, optlen); @@ -1887,7 +1892,6 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, break; }; -out_unlock: sctp_release_sock(sk); out_nounlock: @@ -2163,7 +2167,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) } /* Default Peer Address Parameters. These defaults can - * be modified via SCTP_SET_PEER_ADDR_PARAMS + * be modified via SCTP_PEER_ADDR_PARAMS */ sp->paddrparam.spp_hbinterval = (sctp_hb_interval / HZ) * 1000; sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; @@ -2309,6 +2313,9 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(union sctp_addr)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)&status.sstat_primary.spinfo_address); status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; @@ -2408,12 +2415,13 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, return 0; } -/* 7.1.15 Set notification and ancillary events (SCTP_SET_EVENTS) +/* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) * * This socket option is used to specify various notifications and * ancillary data the user wishes to receive. */ -static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_events(struct sock *sk, int len, char *optval, + int *optlen) { if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2516,7 +2524,7 @@ out: return retval; } -/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS) +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address of * an association, modify an address's heartbeat interval, force a @@ -2645,6 +2653,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, struct sctp_getaddrs getaddrs; struct sctp_transport *from; struct sockaddr_storage *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2663,7 +2673,9 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, to = getaddrs.addrs; list_for_each(pos, &asoc->peer.transport_addr_list) { from = list_entry(pos, struct sctp_transport, transports); - if (copy_to_user(to, &from->ipaddr, sizeof(from->ipaddr))) + memcpy(&temp, &from->ipaddr, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + if (copy_to_user(to, &temp, sizeof(temp))) return -EFAULT; to ++; cnt ++; @@ -2725,6 +2737,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, struct sctp_getaddrs getaddrs; struct sctp_sockaddr_entry *from; struct sockaddr_storage *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2753,7 +2767,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, from = list_entry(pos, struct sctp_sockaddr_entry, list); - if (copy_to_user(to, &from->a, sizeof(from->a))) + memcpy(&temp, &from->a, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + if (copy_to_user(to, &temp, sizeof(temp))) return -EFAULT; to ++; cnt ++; @@ -2766,35 +2782,39 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Primary Address (SCTP_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. */ -static int sctp_getsockopt_peer_prim(struct sock *sk, int len, - char *optval, int *optlen) +static int sctp_getsockopt_primary_addr(struct sock *sk, int len, + char *optval, int *optlen) { - struct sctp_setpeerprim prim; + struct sctp_prim prim; struct sctp_association *asoc; + struct sctp_opt *sp = sctp_sk(sk); - if (len != sizeof(struct sctp_setpeerprim)) + if (len != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); + asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); if (!asoc) return -EINVAL; if (!asoc->peer.primary_path) return -ENOTCONN; - memcpy(&prim.sspp_addr, &asoc->peer.primary_path->ipaddr, + memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, sizeof(union sctp_addr)); - if (copy_to_user(optval, &prim, sizeof(struct sctp_setpeerprim))) + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, + (union sctp_addr *)&prim.ssp_addr); + + if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) return -EFAULT; return 0; @@ -2808,6 +2828,8 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len, * specify a default set of parameters that would normally be supplied * through the inclusion of ancillary data. This socket option allows * such an application to set the default sctp_sndrcvinfo structure. + + * The application that wishes to use this socket option simply passes * in to this call the sctp_sndrcvinfo structure defined in Section * 5.2.2) The input parameters accepted by this call include @@ -2942,8 +2964,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, * See [SCTP] for more information. * */ -static int sctp_getsockopt_assocrtx(struct sock *sk, int len, char *optval, - int *optlen) { +static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, + int *optlen) +{ struct sctp_assocparams assocparams; struct sctp_association *asoc; @@ -3014,12 +3037,13 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len, char *optval, int *optlen) { int val; + struct sctp_opt *sp = sctp_sk(sk); + if (len < sizeof(int)) return -EINVAL; len = sizeof(int); - /* FIXME: Until we have support, return disabled. */ - val = 0; + val = sp->v4mapped; if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &val, len)) @@ -3091,8 +3115,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_disable_fragments(sk, len, optval, optlen); break; - case SCTP_SET_EVENTS: - retval = sctp_getsockopt_set_events(sk, len, optval, optlen); + case SCTP_EVENTS: + retval = sctp_getsockopt_events(sk, len, optval, optlen); break; case SCTP_AUTOCLOSE: retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); @@ -3100,7 +3124,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_SOCKOPT_PEELOFF: retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; - case SCTP_GET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); break; @@ -3123,12 +3147,12 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_addrs(sk, len, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen); + case SCTP_PRIMARY_ADDR: + retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); break; case SCTP_NODELAY: retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); @@ -3136,8 +3160,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_RTOINFO: retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); break; - case SCTP_ASSOCRTXINFO: - retval = sctp_getsockopt_assocrtx(sk, len, optval, optlen); + case SCTP_ASSOCINFO: + retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); break; case SCTP_I_WANT_MAPPED_V4_ADDR: retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); @@ -3865,7 +3889,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, return -EINVAL; /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr)) + if (!af->addr_valid(addr, sctp_sk(sk))) return -EINVAL; if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) @@ -4210,7 +4234,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); - if (event->asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(&newsk->sk_receive_queue, skb); } @@ -4239,7 +4263,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { event = sctp_skb2event(skb); - if (event->asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(queue, skb); } diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 9728fc5b7bf2..485d77015399 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -117,6 +117,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); + sctp_packet_init(&peer->packet, peer, 0, 0); /* Set up the retransmission timer. */ init_timer(&peer->T3_rtx_timer); diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 4a9d9d2b5a5e..e56e1fdb156c 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -35,6 +35,8 @@ * Written or modified by: * Jon Grimm <jgrimm@us.ibm.com> * La Monte H.P. Yarroll <piggy@acm.org> + * Ardelle Fan <ardelle.fan@intel.com> + * Sridhar Samudrala <sri@us.ibm.com> * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -46,10 +48,12 @@ #include <net/sctp/sctp.h> #include <net/sctp/sm.h> -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc); -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc); +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc); +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc); +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) @@ -62,30 +66,19 @@ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) goto fail; event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, msg_flags); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, msg_flags); + return event; -fail_init: - kfree_skb(skb); fail: return NULL; } /* Initialize an ULP event from an given skb. */ -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *event, - int msg_flags) +void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) { memset(event, sizeof(struct sctp_ulpevent), 0x00); event->msg_flags = msg_flags; - return event; -} - -/* Dispose of an event. */ -void sctp_ulpevent_free(struct sctp_ulpevent *event) -{ - kfree_skb(sctp_event2skb(event)); } /* Is this a MSG_NOTIFICATION? */ @@ -189,7 +182,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sac->sac_assoc_id = sctp_assoc2id(asoc); return event; @@ -281,7 +274,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); spc->spc_assoc_id = sctp_assoc2id(asoc); /* Sockets API Extensions for SCTP @@ -294,6 +287,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( */ memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map( + sctp_sk(asoc->base.sk), + (union sctp_addr *)&spc->spc_aaddr); + return event; fail: @@ -336,7 +334,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( /* 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), + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), 0, gfp); /* Pull off the rest of the cause TLV from the chunk. */ @@ -346,10 +344,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); sre = (struct sctp_remote_error *) skb_push(skb, sizeof(struct sctp_remote_error)); @@ -402,8 +397,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sre->sre_assoc_id = sctp_assoc2id(asoc); return event; @@ -442,9 +436,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); @@ -502,7 +494,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); /* Per TSVWG discussion with Randy. Allow the application to - * ressemble a fragmented message. + * ressemble a fragmented message. */ ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; @@ -515,8 +507,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( * same association identifier. For TCP style socket, this field is * ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc); return event; @@ -579,7 +570,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sse->sse_assoc_id = sctp_assoc2id(asoc); return event; @@ -596,12 +587,12 @@ fail: * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) */ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, - struct sctp_chunk *chunk, + struct sctp_chunk *chunk, int gfp) { struct sctp_ulpevent *event; struct sctp_sndrcvinfo *info; - struct sk_buff *skb, *list; + struct sk_buff *skb; size_t padding, len; /* Clone the original skb, sharing the data. */ @@ -627,24 +618,15 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, /* 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_skb2event(skb); /* Initialize event with flags 0. */ - event = sctp_ulpevent_init(event, 0); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, 0); event->iif = sctp_chunk_iif(chunk); - /* Note: Not clearing the entire event struct as - * this is just a fragment of the real event. However, - * we still need to do rwnd accounting. - */ - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) - sctp_ulpevent_set_owner_r(list, asoc); + + sctp_ulpevent_receive_data(event, asoc); info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; @@ -735,9 +717,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, return event; -fail_init: - kfree_skb(skb); - fail: return NULL; } @@ -754,7 +733,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( const struct sctp_association *asoc, __u32 indication, int gfp) { struct sctp_ulpevent *event; - struct sctp_rcv_pdapi_event *pd; + struct sctp_pdapi_event *pd; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), @@ -763,8 +742,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( goto fail; skb = sctp_event2skb(event); - pd = (struct sctp_rcv_pdapi_event *) - skb_put(skb, sizeof(struct sctp_rcv_pdapi_event)); + pd = (struct sctp_pdapi_event *) + skb_put(skb, sizeof(struct sctp_pdapi_event)); /* pdapi_type * It should be SCTP_PARTIAL_DELIVERY_EVENT @@ -779,9 +758,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( * * This field is the total length of the notification data, including * the notification header. It will generally be sizeof (struct - * sctp_rcv_pdapi_event). + * sctp_pdapi_event). */ - pd->pdapi_length = sizeof(struct sctp_rcv_pdapi_event); + pd->pdapi_length = sizeof(struct sctp_pdapi_event); /* pdapi_indication: 32 bits (unsigned integer) * @@ -793,6 +772,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( * * The association id field, holds the identifier for the association. */ + sctp_ulpevent_set_owner(event, asoc); pd->pdapi_assoc_id = sctp_assoc2id(asoc); return event; @@ -810,7 +790,7 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event) skb = sctp_event2skb((struct sctp_ulpevent *)event); notification = (union sctp_notification *) skb->data; - return notification->h.sn_type; + return notification->sn_header.sn_type; } /* Copy out the sndrcvinfo into a msghdr. */ @@ -824,69 +804,115 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, } } -/* Do accounting for bytes just read by user. */ -static void sctp_rcvmsg_rfree(struct sk_buff *skb) +/* Stub skb destructor. */ +static void sctp_stub_rfree(struct sk_buff *skb) { - struct sctp_association *asoc; - struct sctp_ulpevent *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_skb2event(skb); - asoc = event->asoc; - sctp_assoc_rwnd_increase(asoc, skb_headlen(skb)); - sctp_association_put(asoc); +/* WARNING: This function is just a warning not to use the + * skb destructor. If the skb is shared, we may get the destructor + * callback on some processor that does not own the sock_lock. This + * was occuring with PACKET socket applications that were monitoring + * our skbs. We can't take the sock_lock, because we can't risk + * recursing if we do really own the sock lock. Instead, do all + * of our rwnd manipulation while we own the sock_lock outright. + */ } -/* Charge receive window for bytes received. */ -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc) +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) { - struct sctp_ulpevent *event; + struct sk_buff *skb; - /* 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. + /* Cast away the const, as we are just wanting to + * bump the reference count. */ - sctp_association_hold(asoc); + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->asoc = asoc; + event->sndrcvinfo.sinfo_assoc_id = sctp_assoc2id(asoc); + skb->destructor = sctp_stub_rfree; +} - skb->destructor = sctp_rcvmsg_rfree; +/* A simple destructor to give up the reference to the association. */ +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) +{ + sctp_association_put(event->sndrcvinfo.sinfo_assoc_id); +} +/* Do accounting for bytes received and hold a reference to the association + * for each skb. + */ +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc) +{ + struct sk_buff *skb, *frag; + + skb = sctp_event2skb(event); + /* Set the owner and charge rwnd for bytes received. */ + sctp_ulpevent_set_owner(event, asoc); sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); + + /* Note: Not clearing the entire event struct as this is just a + * fragment of the real event. However, we still need to do rwnd + * accounting. + * In general, the skb passed from IP can have only 1 level of + * fragments. But we allow multiple levels of fragments. + */ + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); + } } -/* A simple destructor to give up the reference to the association. */ -static void sctp_ulpevent_rfree(struct sk_buff *skb) +/* Do accounting for bytes just read by user and release the references to + * the association. + */ +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; + struct sk_buff *skb, *frag; - event = sctp_skb2event(skb); - sctp_association_put(event->asoc); + /* 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. + */ + + skb = sctp_event2skb(event); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + skb_headlen(skb)); + + /* Don't forget the fragments. */ + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + /* NOTE: skb_shinfos are recursive. Although IP returns + * skb's with only 1 level of fragments, SCTP reassembly can + * increase the levels. + */ + sctp_ulpevent_release_data(sctp_skb2event(frag)); + } + sctp_ulpevent_release_owner(event); } -/* Hold the association in case the msg_name needs read out of - * the association. +/* Free a ulpevent that has an owner. It includes releasing the reference + * to the owner, updating the rwnd in case of a DATA event and freeing the + * skb. + * See comments in sctp_stub_rfree(). */ -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc) +void sctp_ulpevent_free(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; + if (sctp_ulpevent_is_notification(event)) + sctp_ulpevent_release_owner(event); + else + sctp_ulpevent_release_data(event); - /* Cast away the const, as we are just wanting to - * bump the reference count. - */ - sctp_association_hold((struct sctp_association *)asoc); - skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_ulpevent_rfree; + kfree_skb(sctp_event2skb(event)); +} + +/* Purge the skb lists holding ulpevents. */ +void sctp_queue_purge_ulpevents(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(list)) != NULL) + sctp_ulpevent_free(sctp_skb2event(skb)); } diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 8a11bc28bd38..a02b2143239b 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -235,9 +235,9 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) out_free: if (sctp_event2skb(event)->list) - skb_queue_purge(sctp_event2skb(event)->list); + sctp_queue_purge_ulpevents(sctp_event2skb(event)->list); else - kfree_skb(sctp_event2skb(event)); + sctp_ulpevent_free(event); return 0; } @@ -289,7 +289,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, * payload was fragmented on the way and ip had to reassemble them. * We add the rest of skb's to the first skb's fraglist. */ -static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) +static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; struct sctp_ulpevent *event; @@ -325,11 +325,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff * /* 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; }; |
