Commit 59682120 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/sctp-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 0cc526e0 c09d36c8
......@@ -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__ */
......@@ -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 *,
......
......@@ -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;
};
......
......@@ -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,
......
/* 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
......@@ -447,76 +422,26 @@ typedef enum sctp_sn_error {
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;
__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__ */
......@@ -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))
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
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,
};
......
......@@ -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 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* 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;
}
/********************************************************************
......
......@@ -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
......
......@@ -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 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
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,
};
......
......@@ -667,7 +667,8 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
}
/* 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 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
/* 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:
......
......@@ -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,
......
......@@ -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:
......
......@@ -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 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
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);
}
......
......@@ -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);
......
......@@ -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 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
* 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));
}
......@@ -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;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment