Commit 551c773f authored by Jon Grimm's avatar Jon Grimm

Merge touki.austin.ibm.com:/home/jgrimm/bk/lksctp-2.5

into touki.austin.ibm.com:/home/jgrimm/bk/lksctp-2.5.work
parents a0065b2f 62603506
...@@ -86,6 +86,7 @@ typedef enum { ...@@ -86,6 +86,7 @@ typedef enum {
SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */ SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */ SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */ SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */
SCTP_CMD_CHUNK_PD, /* Partial data delivery considerations. */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
...@@ -115,7 +116,7 @@ typedef union { ...@@ -115,7 +116,7 @@ typedef union {
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_bind_addr_t *bp; sctp_bind_addr_t *bp;
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
sctp_ulpevent_t *ulpevent; struct sctp_ulpevent *ulpevent;
sctp_packet_t *packet; sctp_packet_t *packet;
sctp_sackhdr_t *sackh; sctp_sackhdr_t *sackh;
} sctp_arg_t; } sctp_arg_t;
...@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) ...@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport) SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport)
SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp) SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp)
SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent) SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet) SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet)
SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp. * Copyright (c) 2001-2003 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -105,27 +105,25 @@ union sctp_addr { ...@@ -105,27 +105,25 @@ union sctp_addr {
/* Forward declarations for data structures. */ /* Forward declarations for data structures. */
struct sctp_protocol; struct sctp_protocol;
struct SCTP_endpoint; struct sctp_endpoint;
struct SCTP_association; struct sctp_association;
struct sctp_transport; struct sctp_transport;
struct SCTP_packet; struct sctp_packet;
struct SCTP_chunk; struct sctp_chunk;
struct SCTP_inqueue; struct sctp_inq;
struct sctp_outq; struct sctp_outq;
struct SCTP_bind_addr; struct sctp_bind_addr;
struct sctp_ulpq; struct sctp_ulpq;
struct sctp_opt; struct sctp_opt;
struct sctp_endpoint_common; struct sctp_endpoint_common;
struct sctp_ssnmap; struct sctp_ssnmap;
typedef struct sctp_protocol sctp_protocol_t; typedef struct sctp_protocol sctp_protocol_t;
typedef struct SCTP_endpoint sctp_endpoint_t; typedef struct sctp_endpoint sctp_endpoint_t;
typedef struct SCTP_association sctp_association_t; typedef struct sctp_association sctp_association_t;
typedef struct SCTP_packet sctp_packet_t; typedef struct sctp_packet sctp_packet_t;
typedef struct SCTP_chunk sctp_chunk_t; typedef struct sctp_chunk sctp_chunk_t;
typedef struct SCTP_inqueue sctp_inqueue_t; typedef struct sctp_bind_addr sctp_bind_addr_t;
typedef struct SCTP_bind_addr sctp_bind_addr_t;
typedef struct sctp_opt sctp_opt_t;
typedef struct sctp_endpoint_common sctp_endpoint_common_t; typedef struct sctp_endpoint_common sctp_endpoint_common_t;
#include <net/sctp/tsnmap.h> #include <net/sctp/tsnmap.h>
...@@ -250,10 +248,10 @@ struct sctp_af { ...@@ -250,10 +248,10 @@ struct sctp_af {
int optname, int optname,
char *optval, char *optval,
int *optlen); int *optlen);
struct dst_entry *(*get_dst) (sctp_association_t *asoc, struct dst_entry *(*get_dst) (struct sctp_association *asoc,
union sctp_addr *daddr, union sctp_addr *daddr,
union sctp_addr *saddr); union sctp_addr *saddr);
void (*get_saddr) (sctp_association_t *asoc, void (*get_saddr) (struct sctp_association *asoc,
struct dst_entry *dst, struct dst_entry *dst,
union sctp_addr *daddr, union sctp_addr *daddr,
union sctp_addr *saddr); union sctp_addr *saddr);
...@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *); ...@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */ /* Protocol family functions. */
struct sctp_pf { struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *); void (*event_msgname)(struct sctp_ulpevent *, char *, int *);
void (*skb_msgname) (struct sk_buff *, char *, int *); void (*skb_msgname) (struct sk_buff *, char *, int *);
int (*af_supported) (sa_family_t); int (*af_supported) (sa_family_t);
int (*cmp_addr) (const union sctp_addr *, int (*cmp_addr) (const union sctp_addr *,
...@@ -311,6 +309,9 @@ struct sctp_opt { ...@@ -311,6 +309,9 @@ struct sctp_opt {
/* What kind of a socket is this? */ /* What kind of a socket is this? */
sctp_socket_type_t type; sctp_socket_type_t type;
/* PF_ family specific functions. */
struct sctp_pf *pf;
/* What is our base endpointer? */ /* What is our base endpointer? */
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
...@@ -324,7 +325,10 @@ struct sctp_opt { ...@@ -324,7 +325,10 @@ struct sctp_opt {
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
__u8 disable_fragments; __u8 disable_fragments;
struct sctp_pf *pf; __u8 pd_mode;
/* Receive to here while partial delivery is in effect. */
struct sk_buff_head pd_lobby;
}; };
...@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) ...@@ -484,7 +488,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
* As a matter of convenience, we remember the SCTP common header for * As a matter of convenience, we remember the SCTP common header for
* each chunk as well as a few other header pointers... * each chunk as well as a few other header pointers...
*/ */
struct SCTP_chunk { struct sctp_chunk {
/* These first three elements MUST PRECISELY match the first /* These first three elements MUST PRECISELY match the first
* three elements of struct sk_buff. This allows us to reuse * three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions. * all the skb_* queue management functions.
...@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *); ...@@ -594,7 +598,7 @@ typedef sctp_chunk_t *(sctp_packet_phandler_t)(sctp_association_t *);
/* This structure holds lists of chunks as we are assembling for /* This structure holds lists of chunks as we are assembling for
* transmission. * transmission.
*/ */
struct SCTP_packet { struct sctp_packet {
/* These are the SCTP header values (host order) for the packet. */ /* These are the SCTP header values (host order) for the packet. */
__u16 source_port; __u16 source_port;
__u16 destination_port; __u16 destination_port;
...@@ -846,8 +850,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *); ...@@ -846,8 +850,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *);
/* This is the structure we use to queue packets as they come into /* This is the structure we use to queue packets as they come into
* SCTP. We write packets to it and read chunks from it. * SCTP. We write packets to it and read chunks from it.
*/ */
struct SCTP_inqueue { struct sctp_inq {
/* This is actually a queue of sctp_chunk_t each /* This is actually a queue of sctp_chunk each
* containing a partially decoded packet. * containing a partially decoded packet.
*/ */
struct sk_buff_head in; struct sk_buff_head in;
...@@ -864,13 +868,12 @@ struct SCTP_inqueue { ...@@ -864,13 +868,12 @@ struct SCTP_inqueue {
int malloced; /* Is this structure kfree()able? */ int malloced; /* Is this structure kfree()able? */
}; };
sctp_inqueue_t *sctp_inqueue_new(void); struct sctp_inq *sctp_inq_new(void);
void sctp_inqueue_init(sctp_inqueue_t *); void sctp_inq_init(struct sctp_inq *);
void sctp_inqueue_free(sctp_inqueue_t *); void sctp_inq_free(struct sctp_inq *);
void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet); void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet);
sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
void sctp_inqueue_set_th_handler(sctp_inqueue_t *, void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
void (*)(void *), void *);
/* This is the structure we use to hold outbound chunks. You push /* This is the structure we use to hold outbound chunks. You push
* chunks in and they automatically pop out the other end as bundled * chunks in and they automatically pop out the other end as bundled
...@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); ...@@ -954,7 +957,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
/* These bind address data fields common between endpoints and associations */ /* These bind address data fields common between endpoints and associations */
struct SCTP_bind_addr { struct sctp_bind_addr {
/* RFC 2960 12.1 Parameters necessary for the SCTP instance /* RFC 2960 12.1 Parameters necessary for the SCTP instance
* *
...@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common { ...@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
struct sock *sk; struct sock *sk;
/* This is where we receive inbound chunks. */ /* This is where we receive inbound chunks. */
sctp_inqueue_t inqueue; struct sctp_inq inqueue;
/* This substructure includes the defining parameters of the /* This substructure includes the defining parameters of the
* endpoint: * endpoint:
...@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common { ...@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
* off one of these. * off one of these.
*/ */
struct SCTP_endpoint { struct sctp_endpoint {
/* Common substructure for endpoint and association. */ /* Common substructure for endpoint and association. */
sctp_endpoint_common_t base; sctp_endpoint_common_t base;
...@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep); ...@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
/* Here we have information about each individual association. */ /* Here we have information about each individual association. */
struct SCTP_association { struct sctp_association {
/* A base structure common to endpoint and association. /* A base structure common to endpoint and association.
* In this context, it represents the associations's view * In this context, it represents the associations's view
...@@ -1457,7 +1460,10 @@ struct SCTP_association { ...@@ -1457,7 +1460,10 @@ struct SCTP_association {
struct { struct {
__u16 stream; __u16 stream;
__u16 flags;
__u32 ppid; __u32 ppid;
__u32 context;
__u32 timetolive;
} defaults; } defaults;
/* This tracks outbound ssn for a given stream. */ /* This tracks outbound ssn for a given stream. */
......
...@@ -6,34 +6,34 @@ ...@@ -6,34 +6,34 @@
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* These are the definitions needed for the sctp_ulpevent type. The * These are the definitions needed for the sctp_ulpevent type. The
* sctp_ulpevent type is used to carry information from the state machine * sctp_ulpevent type is used to carry information from the state machine
* upwards to the ULP. * upwards to the ULP.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* the SCTP reference implementation is distributed in the hope that it * the SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to one of the * Please send any bug reports or fixes you make to one of the
* following email addresses: * following email addresses:
* *
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -46,85 +46,97 @@ ...@@ -46,85 +46,97 @@
/* Warning: This sits inside an skb.cb[] area. Be very careful of /* Warning: This sits inside an skb.cb[] area. Be very careful of
* growing this structure as it is at the maximum limit now. * growing this structure as it is at the maximum limit now.
*/ */
typedef struct sctp_ulpevent { struct sctp_ulpevent {
int malloced; struct sctp_association *asoc;
sctp_association_t *asoc;
struct sk_buff *parent;
struct sctp_sndrcvinfo sndrcvinfo; struct sctp_sndrcvinfo sndrcvinfo;
int chunk_flags; /* Temp. until we get a new chunk_t */
int msg_flags; int msg_flags;
} sctp_ulpevent_t; };
sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority);
sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags);
void sctp_ulpevent_free(sctp_ulpevent_t *event);
int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event);
sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(
const struct SCTP_association *asoc,
__u16 flags,
__u16 state,
__u16 error,
__u16 outbound,
__u16 inbound,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
const struct SCTP_association *asoc,
const struct sockaddr_storage *aaddr,
int flags,
int state,
int error,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_remote_error(
const struct SCTP_association *asoc,
struct SCTP_chunk *chunk,
__u16 flags,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_send_failed(
const struct SCTP_association *asoc,
struct SCTP_chunk *chunk,
__u16 flags,
__u32 error,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
const struct SCTP_association *asoc,
__u16 flags,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc,
struct SCTP_chunk *chunk,
int priority);
void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
struct msghdr *msghdr);
__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event);
/* Retrieve the skb this event sits inside of. */
static inline struct sk_buff *sctp_event2skb(struct sctp_ulpevent *ev)
{
return container_of((void *)ev, struct sk_buff, cb);
}
/* Retrieve & cast the event sitting inside the skb. */
static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
{
return (struct sctp_ulpevent *)skb->cb;
}
struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority);
struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
void sctp_ulpevent_free(struct sctp_ulpevent *);
int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
const struct sctp_association *asoc,
__u16 flags,
__u16 state,
__u16 error,
__u16 outbound,
__u16 inbound,
int priority);
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const struct sctp_association *asoc,
const struct sockaddr_storage *aaddr,
int flags,
int state,
int error,
int priority);
struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
__u16 flags,
int priority);
struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
__u16 flags,
__u32 error,
int priority);
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const struct sctp_association *asoc,
__u16 flags,
int priority);
struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const struct sctp_association *asoc,
__u32 indication, int priority);
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
struct sctp_chunk *chunk,
int priority);
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
struct msghdr *);
__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event);
/* Is this event type enabled? */
static inline int sctp_ulpevent_type_enabled(__u16 sn_type,
struct sctp_event_subscribe *mask)
{
char *amask = (char *) mask;
return amask[sn_type - SCTP_SN_TYPE_BASE];
}
/* Given an event subscription, is this event enabled? */ /* Given an event subscription, is this event enabled? */
static inline int sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event, static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event,
const struct sctp_event_subscribe *mask) struct sctp_event_subscribe *mask)
{ {
const char *amask = (const char *) mask;
__u16 sn_type; __u16 sn_type;
int enabled = 1; int enabled = 1;
if (sctp_ulpevent_is_notification(event)) { if (sctp_ulpevent_is_notification(event)) {
sn_type = sctp_ulpevent_get_notification_type(event); sn_type = sctp_ulpevent_get_notification_type(event);
enabled = amask[sn_type - SCTP_SN_TYPE_BASE]; enabled = sctp_ulpevent_type_enabled(sn_type, mask);
} }
return enabled; return enabled;
} }
#endif /* __sctp_ulpevent_h__ */ #endif /* __sctp_ulpevent_h__ */
......
...@@ -48,7 +48,8 @@ ...@@ -48,7 +48,8 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */ /* A structure to carry information to the ULP (e.g. Sockets API) */
struct sctp_ulpq { struct sctp_ulpq {
int malloced; char malloced;
char pd_mode;
sctp_association_t *asoc; sctp_association_t *asoc;
struct sk_buff_head reasm; struct sk_buff_head reasm;
struct sk_buff_head lobby; struct sk_buff_head lobby;
...@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *); ...@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void sctp_ulpq_free(struct sctp_ulpq *); void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */ /* Add a new DATA chunk for processing. */
int sctp_ulpq_tail_data(struct sctp_ulpq *, sctp_chunk_t *chunk, int priority); int sctp_ulpq_tail_data(struct sctp_ulpq *, struct sctp_chunk *, int);
/* Add a new event for propogation to the ULP. */ /* Add a new event for propogation to the ULP. */
int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev); int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
/* Is the ulpqueue empty. */ /* Perform partial delivery. */
int sctp_ulpqueue_is_empty(struct sctp_ulpq *); void sctp_ulpq_partial_delivery(struct sctp_ulpq *, struct sctp_chunk *, int);
/* Abort the partial delivery. */
void sctp_ulpq_abort_pd(struct sctp_ulpq *, int);
/* Clear the partial data delivery condition on this socket. */
int sctp_clear_pd(struct sock *sk);
#endif /* __sctp_ulpqueue_h__ */ #endif /* __sctp_ulpqueue_h__ */
......
...@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo { ...@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
__u32 sinfo_context; __u32 sinfo_context;
__u32 sinfo_timetolive; __u32 sinfo_timetolive;
__u32 sinfo_tsn; __u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id; sctp_assoc_t sinfo_assoc_id;
}; };
...@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event { ...@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
sctp_assoc_t pdapi_assoc_id; sctp_assoc_t pdapi_assoc_id;
}; };
enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
/* /*
* Described in Section 7.3 * Described in Section 7.3
...@@ -414,8 +416,8 @@ enum sctp_sn_type { ...@@ -414,8 +416,8 @@ enum sctp_sn_type {
SCTP_SN_TYPE_BASE = (1<<15), SCTP_SN_TYPE_BASE = (1<<15),
SCTP_ASSOC_CHANGE, SCTP_ASSOC_CHANGE,
SCTP_PEER_ADDR_CHANGE, SCTP_PEER_ADDR_CHANGE,
SCTP_REMOTE_ERROR,
SCTP_SEND_FAILED, SCTP_SEND_FAILED,
SCTP_REMOTE_ERROR,
SCTP_SHUTDOWN_EVENT, SCTP_SHUTDOWN_EVENT,
SCTP_PARTIAL_DELIVERY_EVENT, SCTP_PARTIAL_DELIVERY_EVENT,
SCTP_ADAPTION_INDICATION, SCTP_ADAPTION_INDICATION,
......
...@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
sctp_scope_t scope, sctp_scope_t scope,
int priority) int priority)
{ {
sctp_opt_t *sp; struct sctp_opt *sp;
int i; int i;
/* Retrieve the SCTP per socket area. */ /* Retrieve the SCTP per socket area. */
...@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->peer.sack_needed = 1; asoc->peer.sack_needed = 1;
/* Create an input queue. */ /* Create an input queue. */
sctp_inqueue_init(&asoc->base.inqueue); sctp_inq_init(&asoc->base.inqueue);
sctp_inqueue_set_th_handler(&asoc->base.inqueue, sctp_inq_set_th_handler(&asoc->base.inqueue,
(void (*)(void *))sctp_assoc_bh_rcv, (void (*)(void *))sctp_assoc_bh_rcv,
asoc); asoc);
...@@ -311,7 +311,7 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -311,7 +311,7 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_ulpq_free(&asoc->ulpq); sctp_ulpq_free(&asoc->ulpq);
/* Dispose of any pending chunks on the inqueue. */ /* Dispose of any pending chunks on the inqueue. */
sctp_inqueue_free(&asoc->base.inqueue); sctp_inq_free(&asoc->base.inqueue);
/* Free ssnmap storage. */ /* Free ssnmap storage. */
sctp_ssnmap_free(asoc->ssnmap); sctp_ssnmap_free(asoc->ssnmap);
...@@ -368,7 +368,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -368,7 +368,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
int priority) int priority)
{ {
struct sctp_transport *peer; struct sctp_transport *peer;
sctp_opt_t *sp; struct sctp_opt *sp;
unsigned short port; unsigned short port;
/* AF_INET and AF_INET6 share common port field. */ /* AF_INET and AF_INET6 share common port field. */
...@@ -505,7 +505,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -505,7 +505,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
struct sctp_transport *t = NULL; struct sctp_transport *t = NULL;
struct sctp_transport *first; struct sctp_transport *first;
struct sctp_transport *second; struct sctp_transport *second;
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct list_head *pos; struct list_head *pos;
int spc_state = 0; int spc_state = 0;
...@@ -776,7 +776,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -776,7 +776,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
struct sock *sk; struct sock *sk;
sctp_inqueue_t *inqueue; struct sctp_inq *inqueue;
int state, subtype; int state, subtype;
sctp_assoc_t associd = sctp_assoc2id(asoc); sctp_assoc_t associd = sctp_assoc2id(asoc);
int error = 0; int error = 0;
...@@ -786,7 +786,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -786,7 +786,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sk = asoc->base.sk; sk = asoc->base.sk;
inqueue = &asoc->base.inqueue; inqueue = &asoc->base.inqueue;
while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { while (NULL != (chunk = sctp_inq_pop(inqueue))) {
state = asoc->state; state = asoc->state;
subtype = chunk->chunk_hdr->type; subtype = chunk->chunk_hdr->type;
...@@ -819,7 +819,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -819,7 +819,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
/* This routine moves an association from its old sk to a new sk. */ /* This routine moves an association from its old sk to a new sk. */
void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
{ {
sctp_opt_t *newsp = sctp_sk(newsk); struct sctp_opt *newsp = sctp_sk(newsk);
/* Delete the association from the old endpoint's list of /* Delete the association from the old endpoint's list of
* associations. * associations.
...@@ -996,7 +996,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -996,7 +996,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
/* Send a window update SACK if the rwnd has increased by at least the /* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer. * minimum of the association's PMTU and half of the receive buffer.
* The algorithm used is similar to the one described in * The algorithm used is similar to the one described in
* Section 4.2.3.3 of RFC 1122. * Section 4.2.3.3 of RFC 1122.
*/ */
if ((asoc->state == SCTP_STATE_ESTABLISHED) && if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
...@@ -1006,9 +1006,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -1006,9 +1006,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p " SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
"rwnd: %u a_rwnd: %u\n", "rwnd: %u a_rwnd: %u\n",
__FUNCTION__, asoc, asoc->rwnd, asoc->a_rwnd); __FUNCTION__, asoc, asoc->rwnd, asoc->a_rwnd);
sack = sctp_make_sack(asoc); sack = sctp_make_sack(asoc);
if (!sack) if (!sack)
return; return;
/* Update the last advertised rwnd value. */ /* Update the last advertised rwnd value. */
asoc->a_rwnd = asoc->rwnd; asoc->a_rwnd = asoc->rwnd;
...@@ -1022,7 +1022,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -1022,7 +1022,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
if (timer_pending(timer) && del_timer(timer)) if (timer_pending(timer) && del_timer(timer))
sctp_association_put(asoc); sctp_association_put(asoc);
} }
} }
/* Decrease asoc's rwnd by len. */ /* Decrease asoc's rwnd by len. */
......
...@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, ...@@ -92,7 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
struct sock *sk, int priority) struct sock *sk, int priority)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
memset(ep, 0, sizeof(sctp_endpoint_t)); memset(ep, 0, sizeof(sctp_endpoint_t));
/* Initialize the base structure. */ /* Initialize the base structure. */
...@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ...@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep->base.malloced = 1; ep->base.malloced = 1;
/* Create an input queue. */ /* Create an input queue. */
sctp_inqueue_init(&ep->base.inqueue); sctp_inq_init(&ep->base.inqueue);
/* Set its top-half handler */ /* Set its top-half handler */
sctp_inqueue_set_th_handler(&ep->base.inqueue, sctp_inq_set_th_handler(&ep->base.inqueue,
(void (*)(void *))sctp_endpoint_bh_rcv, (void (*)(void *))sctp_endpoint_bh_rcv,
ep); ep);
...@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) ...@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
sctp_unhash_endpoint(ep); sctp_unhash_endpoint(ep);
/* Cleanup the inqueue. */ /* Cleanup the inqueue. */
sctp_inqueue_free(&ep->base.inqueue); sctp_inq_free(&ep->base.inqueue);
sctp_bind_addr_free(&ep->base.bind_addr); sctp_bind_addr_free(&ep->base.bind_addr);
...@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
struct sock *sk; struct sock *sk;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue; struct sctp_inq *inqueue;
sctp_subtype_t subtype; sctp_subtype_t subtype;
sctp_state_t state; sctp_state_t state;
int error = 0; int error = 0;
...@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue = &ep->base.inqueue; inqueue = &ep->base.inqueue;
sk = ep->base.sk; sk = ep->base.sk;
while (NULL != (chunk = sctp_pop_inqueue(inqueue))) { while (NULL != (chunk = sctp_inq_pop(inqueue))) {
subtype.chunk = chunk->chunk_hdr->type; subtype.chunk = chunk->chunk_hdr->type;
/* We might have grown an association since last we /* We might have grown an association since last we
......
...@@ -248,7 +248,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -248,7 +248,7 @@ int sctp_rcv(struct sk_buff *skb)
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{ {
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue; struct sctp_inq *inqueue;
/* One day chunk will live inside the skb, but for /* One day chunk will live inside the skb, but for
* now this works. * now this works.
...@@ -256,7 +256,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -256,7 +256,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
chunk = (sctp_chunk_t *) skb; chunk = (sctp_chunk_t *) skb;
inqueue = &chunk->rcvr->inqueue; inqueue = &chunk->rcvr->inqueue;
sctp_push_inqueue(inqueue, chunk); sctp_inq_push(inqueue, chunk);
return 0; return 0;
} }
......
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
/* Initialize an SCTP_inqueue. */ /* Initialize an SCTP inqueue. */
void sctp_inqueue_init(sctp_inqueue_t *queue) void sctp_inq_init(struct sctp_inq *queue)
{ {
skb_queue_head_init(&queue->in); skb_queue_head_init(&queue->in);
queue->in_progress = NULL; queue->in_progress = NULL;
...@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue) ...@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
queue->malloced = 0; queue->malloced = 0;
} }
/* Create an initialized SCTP_inqueue. */ /* Create an initialized sctp_inq. */
sctp_inqueue_t *sctp_inqueue_new(void) struct sctp_inq *sctp_inq_new(void)
{ {
sctp_inqueue_t *retval; struct sctp_inq *retval;
retval = t_new(sctp_inqueue_t, GFP_ATOMIC); retval = t_new(struct sctp_inq, GFP_ATOMIC);
if (retval) { if (retval) {
sctp_inqueue_init(retval); sctp_inq_init(retval);
retval->malloced = 1; retval->malloced = 1;
} }
return retval; return retval;
} }
/* Release the memory associated with an SCTP inqueue. */ /* Release the memory associated with an SCTP inqueue. */
void sctp_inqueue_free(sctp_inqueue_t *queue) void sctp_inq_free(struct sctp_inq *queue)
{ {
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
...@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue) ...@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
/* Put a new packet in an SCTP inqueue. /* Put a new packet in an SCTP inqueue.
* We assume that packet->sctp_hdr is set and in host byte order. * We assume that packet->sctp_hdr is set and in host byte order.
*/ */
void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet)
{ {
/* Directly call the packet handling routine. */ /* Directly call the packet handling routine. */
...@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet) ...@@ -114,7 +114,7 @@ void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
* WARNING: If you need to put the chunk on another queue, you need to * WARNING: If you need to put the chunk on another queue, you need to
* make a shallow copy (clone) of it. * make a shallow copy (clone) of it.
*/ */
sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue) sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue)
{ {
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_chunkhdr_t *ch = NULL; sctp_chunkhdr_t *ch = NULL;
...@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue) ...@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
chunk->end_of_packet = 1; chunk->end_of_packet = 1;
} }
SCTP_DEBUG_PRINTK("+++sctp_pop_inqueue+++ chunk %p[%s]," SCTP_DEBUG_PRINTK("+++sctp_inq_pop+++ chunk %p[%s],"
" length %d, skb->len %d\n",chunk, " length %d, skb->len %d\n",chunk,
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)),
ntohs(chunk->chunk_hdr->length), chunk->skb->len); ntohs(chunk->chunk_hdr->length), chunk->skb->len);
...@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue) ...@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
/* Set a top-half handler. /* Set a top-half handler.
* *
* Originally, we the top-half handler was scheduled as a BH. We now * Originally, we the top-half handler was scheduled as a BH. We now
* call the handler directly in sctp_push_inqueue() at a time that * call the handler directly in sctp_inq_push() at a time that
* we know we are lock safe. * we know we are lock safe.
* The intent is that this routine will pull stuff out of the * The intent is that this routine will pull stuff out of the
* inqueue and process it. * inqueue and process it.
*/ */
void sctp_inqueue_set_th_handler(sctp_inqueue_t *q, void sctp_inq_set_th_handler(struct sctp_inq *q,
void (*callback)(void *), void *arg) void (*callback)(void *), void *arg)
{ {
INIT_WORK(&q->immediate, callback, arg); INIT_WORK(&q->immediate, callback, arg);
......
...@@ -444,7 +444,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) ...@@ -444,7 +444,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
} }
/* Initialize a PF_INET msgname from a ulpevent. */ /* Initialize a PF_INET msgname from a ulpevent. */
static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname,
int *addrlen) int *addrlen)
{ {
struct sockaddr_in6 *sin6, *sin6from; struct sockaddr_in6 *sin6, *sin6from;
......
...@@ -124,7 +124,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -124,7 +124,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
if (addr) { if (addr) {
INIT_LIST_HEAD(&addr->list);
addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0; addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
...@@ -557,7 +556,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len) ...@@ -557,7 +556,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
} }
/* Copy the primary address of the peer primary address as the msg_name. */ /* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname,
int *addr_len) int *addr_len)
{ {
struct sockaddr_in *sin, *sinfrom; struct sockaddr_in *sin, *sinfrom;
......
...@@ -245,7 +245,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -245,7 +245,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
retval = NULL; retval = NULL;
addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, priority); addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len,
priority);
if (!addrs.v) if (!addrs.v)
goto nomem_rawaddr; goto nomem_rawaddr;
......
...@@ -598,6 +598,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -598,6 +598,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
t->rto_pending = 1; t->rto_pending = 1;
break; break;
case SCTP_CMD_CHUNK_PD:
/* Send a chunk to the sockets layer. */
sctp_ulpq_partial_delivery(&asoc->ulpq,
command->obj.ptr,
GFP_ATOMIC);
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
command->verb, command->obj.ptr); command->verb, command->obj.ptr);
...@@ -1014,7 +1021,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, ...@@ -1014,7 +1021,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
sctp_association_t *asoc) sctp_association_t *asoc)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc, event = sctp_ulpevent_make_assoc_change(asoc,
0, 0,
...@@ -1041,7 +1048,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1041,7 +1048,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_subtype_t subtype, sctp_subtype_t subtype,
sctp_chunk_t *chunk) sctp_chunk_t *chunk)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
__u16 error = 0; __u16 error = 0;
switch(event_type) { switch(event_type) {
...@@ -1061,12 +1068,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1061,12 +1068,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
break; break;
} }
event = sctp_ulpevent_make_assoc_change(asoc, /* Cancel any partial delivery in progress. */
0, sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
SCTP_COMM_LOST,
error, 0, 0,
GFP_ATOMIC);
event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
error, 0, 0, GFP_ATOMIC);
if (event) if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event)); SCTP_ULPEVENT(event));
...@@ -1141,7 +1147,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, ...@@ -1141,7 +1147,7 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
if (del_timer(&t->hb_timer)) if (del_timer(&t->hb_timer))
sctp_transport_put(t); sctp_transport_put(t);
} }
} }
/* Helper function to update the heartbeat timer. */ /* Helper function to update the heartbeat timer. */
static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
......
...@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, ...@@ -102,7 +102,7 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
/* RFC 2960 6.10 Bundling /* RFC 2960 6.10 Bundling
* *
...@@ -264,7 +264,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -264,7 +264,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
goto nomem_ack; goto nomem_ack;
repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
if (!repl) if (!repl)
goto nomem_ack; goto nomem_ack;
...@@ -504,7 +504,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -504,7 +504,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_association_t *new_asoc; sctp_association_t *new_asoc;
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
sctp_chunk_t *repl; sctp_chunk_t *repl;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
int error = 0; int error = 0;
sctp_chunk_t *err_chk_p; sctp_chunk_t *err_chk_p;
...@@ -636,7 +636,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, ...@@ -636,7 +636,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
const sctp_subtype_t type, void *arg, const sctp_subtype_t type, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
/* RFC 2960 5.1 Normal Establishment of an Association /* RFC 2960 5.1 Normal Establishment of an Association
* *
...@@ -1355,7 +1355,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -1355,7 +1355,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
sctp_association_t *new_asoc) sctp_association_t *new_asoc)
{ {
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
sctp_chunk_t *repl; sctp_chunk_t *repl;
/* new_asoc is a brand-new association, so these are not yet /* new_asoc is a brand-new association, so these are not yet
...@@ -1421,7 +1421,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, ...@@ -1421,7 +1421,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
sctp_association_t *new_asoc) sctp_association_t *new_asoc)
{ {
sctp_init_chunk_t *peer_init; sctp_init_chunk_t *peer_init;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
sctp_chunk_t *repl; sctp_chunk_t *repl;
/* new_asoc is a brand-new association, so these are not yet /* new_asoc is a brand-new association, so these are not yet
...@@ -1503,7 +1503,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, ...@@ -1503,7 +1503,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_association_t *new_asoc) sctp_association_t *new_asoc)
{ {
sctp_ulpevent_t *ev = NULL; struct sctp_ulpevent *ev = NULL;
sctp_chunk_t *repl; sctp_chunk_t *repl;
/* Clarification from Implementor's Guide: /* Clarification from Implementor's Guide:
...@@ -1540,11 +1540,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, ...@@ -1540,11 +1540,11 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
SCTP_ULPEVENT(ev)); SCTP_ULPEVENT(ev));
} }
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
repl = sctp_make_cookie_ack(new_asoc, chunk); repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl) if (!repl)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
...@@ -2241,6 +2241,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2241,6 +2241,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
sctp_datahdr_t *data_hdr; sctp_datahdr_t *data_hdr;
sctp_chunk_t *err; sctp_chunk_t *err;
size_t datalen; size_t datalen;
sctp_verb_t deliver;
int tmp; int tmp;
__u32 tsn; __u32 tsn;
...@@ -2307,10 +2308,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2307,10 +2308,32 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
datalen = ntohs(chunk->chunk_hdr->length); datalen = ntohs(chunk->chunk_hdr->length);
datalen -= sizeof(sctp_data_chunk_t); datalen -= sizeof(sctp_data_chunk_t);
deliver = SCTP_CMD_CHUNK_ULP;
/* Think about partial delivery. */
if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
/* Even if we don't accept this chunk there is
* memory pressure.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_CHUNK_PD, SCTP_NULL());
}
if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) {
SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %Zd, "
"rwnd: %d\n", tsn, datalen, asoc->rwnd);
goto discard_force; /* There is absolutely no room, but this is the most
* important tsn that we are waiting on, try to
* to partial deliver or renege to make room.
*/
if ((sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
deliver = SCTP_CMD_CHUNK_PD;
} else {
SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
"rwnd: %d\n", tsn, datalen,
asoc->rwnd);
goto discard_force;
}
} }
/* /*
...@@ -2335,10 +2358,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2335,10 +2358,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
/* We are accepting this DATA chunk. */ /* If definately accepting the DATA chunk, record its TSN, otherwise
* wait for renege processing.
/* Record the fact that we have received this TSN. */ */
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); if (deliver != SCTP_CMD_CHUNK_PD)
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number /* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
* *
...@@ -2352,10 +2376,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2352,10 +2376,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM, err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
&data_hdr->stream, &data_hdr->stream,
sizeof(data_hdr->stream)); sizeof(data_hdr->stream));
if (err) { if (err)
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(err)); SCTP_CHUNK(err));
}
goto discard_noforce; goto discard_noforce;
} }
...@@ -2363,7 +2386,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -2363,7 +2386,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
* chunk needs the updated rwnd. * chunk needs the updated rwnd.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_CHUNK_ULP, SCTP_CHUNK(chunk)); sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
if (asoc->autoclose) { if (asoc->autoclose) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
...@@ -2726,7 +2750,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, ...@@ -2726,7 +2750,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
while (chunk->chunk_end > chunk->skb->data) { while (chunk->chunk_end > chunk->skb->data) {
ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0, ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
...@@ -2764,7 +2788,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, ...@@ -2764,7 +2788,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
{ {
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sctp_chunk_t *reply; sctp_chunk_t *reply;
sctp_ulpevent_t *ev; struct sctp_ulpevent *ev;
/* 10.2 H) SHUTDOWN COMPLETE notification /* 10.2 H) SHUTDOWN COMPLETE notification
* *
......
...@@ -81,13 +81,13 @@ ...@@ -81,13 +81,13 @@
/* Forward declarations for internal helper functions. */ /* Forward declarations for internal helper functions. */
static int sctp_writeable(struct sock *sk); static int sctp_writeable(struct sock *sk);
static inline int sctp_wspace(sctp_association_t *asoc); static inline int sctp_wspace(struct sctp_association *asoc);
static inline void sctp_set_owner_w(sctp_chunk_t *chunk); static inline void sctp_set_owner_w(sctp_chunk_t *chunk);
static void sctp_wfree(struct sk_buff *skb); static void sctp_wfree(struct sk_buff *skb);
static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
int msg_len); int msg_len);
static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
...@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, ...@@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
/* Bind a local address either to an endpoint or to an association. */ /* Bind a local address either to an endpoint or to an association. */
SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; sctp_endpoint_t *ep = sp->ep;
sctp_bind_addr_t *bp = &ep->base.bind_addr; sctp_bind_addr_t *bp = &ep->base.bind_addr;
struct sctp_af *af; struct sctp_af *af;
...@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -454,7 +454,7 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*/ */
int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; sctp_endpoint_t *ep = sp->ep;
int cnt; int cnt;
sctp_bind_addr_t *bp = &ep->base.bind_addr; sctp_bind_addr_t *bp = &ep->base.bind_addr;
...@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
/* Clean up any skbs sitting on the receive queue. */ /* Clean up any skbs sitting on the receive queue. */
skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sctp_sk(sk)->pd_lobby);
/* This will run the backlog queue. */ /* This will run the backlog queue. */
sctp_release_sock(sk); sctp_release_sock(sk);
...@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); ...@@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, int msg_len) struct msghdr *msg, int msg_len)
{ {
sctp_opt_t *sp; struct sctp_opt *sp;
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
sctp_association_t *new_asoc=NULL, *asoc=NULL; sctp_association_t *new_asoc=NULL, *asoc=NULL;
struct sctp_transport *transport; struct sctp_transport *transport;
...@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* ASSERT: we have a valid association at this point. */ /* ASSERT: we have a valid association at this point. */
SCTP_DEBUG_PRINTK("We have a valid association.\n"); SCTP_DEBUG_PRINTK("We have a valid association.\n");
if (!sinfo) {
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo.sinfo_stream = asoc->defaults.stream;
default_sinfo.sinfo_flags = asoc->defaults.flags;
default_sinfo.sinfo_ppid = asoc->defaults.ppid;
default_sinfo.sinfo_context = asoc->defaults.context;
default_sinfo.sinfo_timetolive = asoc->defaults.timetolive;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo;
}
/* API 7.1.7, the sndbuf size per association bounds the /* API 7.1.7, the sndbuf size per association bounds the
* maximum size of data that can be sent in a single send call. * maximum size of data that can be sent in a single send call.
*/ */
...@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
err = -EINVAL; err = -EINVAL;
goto out_free; goto out_free;
} }
} else {
/* If the user didn't specify SNDRCVINFO, make up one with
* some defaults.
*/
default_sinfo.sinfo_stream = asoc->defaults.stream;
default_sinfo.sinfo_ppid = asoc->defaults.ppid;
sinfo = &default_sinfo;
} }
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
...@@ -1110,8 +1117,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); ...@@ -1110,8 +1117,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
int len, int noblock, int flags, int *addr_len) int len, int noblock, int flags, int *addr_len)
{ {
sctp_ulpevent_t *event = NULL; struct sctp_ulpevent *event = NULL;
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
int copied; int copied;
int err = 0; int err = 0;
...@@ -1143,7 +1150,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1143,7 +1150,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
if (err) if (err)
goto out_free; goto out_free;
...@@ -1170,7 +1177,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1170,7 +1177,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
/* If skb's length exceeds the user's buffer, update the skb and /* If skb's length exceeds the user's buffer, update the skb and
* push it back to the receive_queue so that the next call to * push it back to the receive_queue so that the next call to
* recvmsg() will return the remaining data. Don't set MSG_EOR. * recvmsg() will return the remaining data. Don't set MSG_EOR.
* Otherwise, set MSG_EOR indicating the end of a message.
*/ */
if (skb_len > copied) { if (skb_len > copied) {
msg->msg_flags &= ~MSG_EOR; msg->msg_flags &= ~MSG_EOR;
...@@ -1178,6 +1184,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1178,6 +1184,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
goto out_free; goto out_free;
sctp_skb_pull(skb, copied); sctp_skb_pull(skb, copied);
skb_queue_head(&sk->receive_queue, skb); skb_queue_head(&sk->receive_queue, skb);
/* When only partial message is copied to the user, increase /* When only partial message is copied to the user, increase
* rwnd by that amount. If all the data in the skb is read, * rwnd by that amount. If all the data in the skb is read,
* rwnd is updated when the skb's destructor is called via * rwnd is updated when the skb's destructor is called via
...@@ -1185,9 +1192,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1185,9 +1192,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
*/ */
sctp_assoc_rwnd_increase(event->asoc, copied); sctp_assoc_rwnd_increase(event->asoc, copied);
goto out; goto out;
} else { } else if ((event->msg_flags & MSG_NOTIFICATION) ||
msg->msg_flags |= MSG_EOR; (event->msg_flags & MSG_EOR))
} msg->msg_flags |= MSG_EOR;
else
msg->msg_flags &= ~MSG_EOR;
out_free: out_free:
sctp_ulpevent_free(event); /* Free the skb. */ sctp_ulpevent_free(event); /* Free the skb. */
...@@ -1225,7 +1234,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, ...@@ -1225,7 +1234,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sp->type) if (SCTP_SOCKET_TCP == sp->type)
...@@ -1310,6 +1319,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, ...@@ -1310,6 +1319,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
return 0; return 0;
} }
/*
*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* 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
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static inline int sctp_setsockopt_set_default_send_param(struct sock *sk,
char *optval, int optlen)
{
struct sctp_sndrcvinfo info;
sctp_association_t *asoc;
if (optlen != sizeof(struct sctp_sndrcvinfo))
return -EINVAL;
if (copy_from_user(&info, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
if (!asoc)
return -EINVAL;
asoc->defaults.stream = info.sinfo_stream;
asoc->defaults.flags = info.sinfo_flags;
asoc->defaults.ppid = info.sinfo_ppid;
asoc->defaults.context = info.sinfo_context;
asoc->defaults.timetolive = info.sinfo_timetolive;
return 0;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -1401,6 +1448,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1401,6 +1448,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_initmsg(sk, optval, optlen); retval = sctp_setsockopt_initmsg(sk, optval, optlen);
break; break;
case SCTP_SET_DEFAULT_SEND_PARAM:
retval = sctp_setsockopt_set_default_send_param(sk,
optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -1432,7 +1484,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1432,7 +1484,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len) int addr_len)
{ {
sctp_opt_t *sp; struct sctp_opt *sp;
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
sctp_association_t *asoc; sctp_association_t *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
...@@ -1554,7 +1606,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1554,7 +1606,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
{ {
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
sctp_protocol_t *proto; sctp_protocol_t *proto;
sctp_opt_t *sp; struct sctp_opt *sp;
SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk);
...@@ -1583,7 +1635,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1583,7 +1635,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can /* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option. * be modified for with the SCTP_RTOINFO socket option.
* FIXME: This are not used yet. * FIXME: These are not used yet.
*/ */
sp->rtoinfo.srto_initial = proto->rto_initial; sp->rtoinfo.srto_initial = proto->rto_initial;
sp->rtoinfo.srto_max = proto->rto_max; sp->rtoinfo.srto_max = proto->rto_max;
...@@ -1620,6 +1672,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1620,6 +1672,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/ */
sp->autoclose = 0; sp->autoclose = 0;
sp->pf = sctp_get_pf_specific(sk->family); sp->pf = sctp_get_pf_specific(sk->family);
/* Control variables for partial data delivery. */
sp->pd_mode = 0;
skb_queue_head_init(&sp->pd_lobby);
/* Create a per socket endpoint structure. Even if we /* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still * change the data structure relationships, this may still
* be useful for storing pre-connect address information. * be useful for storing pre-connect address information.
...@@ -1774,10 +1831,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso ...@@ -1774,10 +1831,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct sock *newsk; struct sock *newsk;
struct socket *tmpsock; struct socket *tmpsock;
sctp_endpoint_t *newep; sctp_endpoint_t *newep;
sctp_opt_t *oldsp = sctp_sk(oldsk); struct sctp_opt *oldsp = sctp_sk(oldsk);
sctp_opt_t *newsp; struct sctp_opt *newsp;
struct sk_buff *skb, *tmp; struct sk_buff *skb, *tmp;
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
int err = 0; int err = 0;
/* An association cannot be branched off from an already peeled-off /* An association cannot be branched off from an already peeled-off
...@@ -1811,13 +1868,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso ...@@ -1811,13 +1868,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
* peeled off association to the new socket's receive queue. * peeled off association to the new socket's receive queue.
*/ */
sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) { sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
event = (sctp_ulpevent_t *)skb->cb; event = sctp_skb2event(skb);
if (event->asoc == assoc) { if (event->asoc == assoc) {
__skb_unlink(skb, skb->list); __skb_unlink(skb, skb->list);
__skb_queue_tail(&newsk->receive_queue, skb); __skb_queue_tail(&newsk->receive_queue, skb);
} }
} }
/* Clean up an messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
*/
skb_queue_head_init(&newsp->pd_lobby);
sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;;
if (sctp_sk(oldsk)->pd_mode) {
struct sk_buff_head *queue;
/* Decide which queue to move pd_lobby skbs to. */
if (assoc->ulpq.pd_mode) {
queue = &newsp->pd_lobby;
} else
queue = &newsk->receive_queue;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
event = sctp_skb2event(skb);
if (event->asoc == assoc) {
__skb_unlink(skb, skb->list);
__skb_queue_tail(queue, skb);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if (assoc->ulpq.pd_mode)
sctp_clear_pd(oldsk);
}
/* Set the type of socket to indicate that it is peeled off from the /* Set the type of socket to indicate that it is peeled off from the
* original socket. * original socket.
*/ */
...@@ -2389,7 +2483,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum) ...@@ -2389,7 +2483,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
*/ */
SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
sctp_endpoint_t *ep = sp->ep; sctp_endpoint_t *ep = sp->ep;
/* Only UDP style sockets that are not peeled off are allowed to /* Only UDP style sockets that are not peeled off are allowed to
......
...@@ -5,37 +5,37 @@ ...@@ -5,37 +5,37 @@
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* These functions manipulate an sctp event. The sctp_ulpevent_t is used * These functions manipulate an sctp event. The struct ulpevent is used
* to carry notifications and data to the ULP (sockets). * to carry notifications and data to the ULP (sockets).
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -47,58 +47,51 @@ ...@@ -47,58 +47,51 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
sctp_association_t *asoc); struct sctp_association *asoc);
static void static void sctp_ulpevent_set_owner(struct sk_buff *skb,
sctp_ulpevent_set_owner(struct sk_buff *skb, const sctp_association_t *asoc); const struct sctp_association *asoc);
/* Create a new sctp_ulpevent. */ /* Create a new sctp_ulpevent. */
sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority) struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sk_buff *skb; struct sk_buff *skb;
skb = alloc_skb(size, priority); skb = alloc_skb(size, priority);
if (!skb) if (!skb)
goto fail; goto fail;
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
event = sctp_ulpevent_init(event, skb, msg_flags); event = sctp_ulpevent_init(event, msg_flags);
if (!event) if (!event)
goto fail_init; goto fail_init;
event->malloced = 1;
return event; return event;
fail_init: fail_init:
kfree_skb(event->parent); kfree_skb(skb);
fail: fail:
return NULL; return NULL;
} }
/* Initialize an ULP event from an given skb. */ /* Initialize an ULP event from an given skb. */
sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *event,
struct sk_buff *parent, int msg_flags)
int msg_flags)
{ {
memset(event, sizeof(sctp_ulpevent_t), 0x00); memset(event, sizeof(struct sctp_ulpevent), 0x00);
event->msg_flags = msg_flags; event->msg_flags = msg_flags;
event->parent = parent;
event->malloced = 0;
return event; return event;
} }
/* Dispose of an event. */ /* Dispose of an event. */
void sctp_ulpevent_free(sctp_ulpevent_t *event) void sctp_ulpevent_free(struct sctp_ulpevent *event)
{ {
if (event->malloced) kfree_skb(sctp_event2skb(event));
kfree_skb(event->parent);
} }
/* Is this a MSG_NOTIFICATION? */ /* Is this a MSG_NOTIFICATION? */
int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
{ {
return event->msg_flags & MSG_NOTIFICATION; return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);
} }
/* Create and initialize an SCTP_ASSOC_CHANGE event. /* Create and initialize an SCTP_ASSOC_CHANGE event.
...@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event) ...@@ -112,24 +105,22 @@ int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
* Note: There is no field checking here. If a field is unused it will be * Note: There is no field checking here. If a field is unused it will be
* zero'd out. * zero'd out.
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
__u16 flags, const sctp_association_t *asoc,
__u16 state, __u16 flags, __u16 state, __u16 error, __u16 outbound,
__u16 error, __u16 inbound, int priority)
__u16 outbound,
__u16 inbound,
int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sctp_assoc_change *sac; struct sctp_assoc_change *sac;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, priority);
if (!event) if (!event)
goto fail; goto fail;
skb = sctp_event2skb(event);
sac = (struct sctp_assoc_change *) sac = (struct sctp_assoc_change *)
skb_put(event->parent, sizeof(struct sctp_assoc_change)); skb_put(skb, sizeof(struct sctp_assoc_change));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
...@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -198,13 +189,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc); sctp_ulpevent_set_owner(skb, asoc);
sac->sac_assoc_id = sctp_assoc2id(asoc); sac->sac_assoc_id = sctp_assoc2id(asoc);
return event; return event;
fail: fail:
return NULL; return NULL;
} }
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event. /* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
...@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -215,24 +206,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* When a destination address on a multi-homed peer encounters a change * When a destination address on a multi-homed peer encounters a change
* an interface details event is sent. * an interface details event is sent.
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const sctp_association_t *asoc, const sctp_association_t *asoc, const struct sockaddr_storage *aaddr,
const struct sockaddr_storage *aaddr, int flags, int state, int error, int priority)
int flags,
int state,
int error,
int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sctp_paddr_change *spc; struct sctp_paddr_change *spc;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, priority);
if (!event) if (!event)
goto fail; goto fail;
skb = sctp_event2skb(event);
spc = (struct sctp_paddr_change *) spc = (struct sctp_paddr_change *)
skb_put(event->parent, sizeof(struct sctp_paddr_change)); skb_put(skb, sizeof(struct sctp_paddr_change));
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
...@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -265,7 +254,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
* *
* spc_state: 32 bits (signed integer) * spc_state: 32 bits (signed integer)
* *
* This field holds one of a number of values that communicate the * This field holds one of a number of values that communicate the
* event that happened to the address. * event that happened to the address.
*/ */
...@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -291,7 +280,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc); sctp_ulpevent_set_owner(skb, asoc);
spc->spc_assoc_id = sctp_assoc2id(asoc); spc->spc_assoc_id = sctp_assoc2id(asoc);
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
...@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -325,12 +314,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
* specification [SCTP] and any extensions for a list of possible * specification [SCTP] and any extensions for a list of possible
* error formats. * error formats.
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
sctp_chunk_t *chunk, const sctp_association_t *asoc, sctp_chunk_t *chunk,
__u16 flags, __u16 flags, int priority)
int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sctp_remote_error *sre; struct sctp_remote_error *sre;
struct sk_buff *skb; struct sk_buff *skb;
sctp_errhdr_t *ch; sctp_errhdr_t *ch;
...@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -358,13 +346,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
goto fail; goto fail;
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); event = sctp_ulpevent_init(event, MSG_NOTIFICATION);
if (!event) if (!event)
goto fail; goto fail;
event->malloced = 1;
sre = (struct sctp_remote_error *) sre = (struct sctp_remote_error *)
skb_push(skb, sizeof(struct sctp_remote_error)); skb_push(skb, sizeof(struct sctp_remote_error));
...@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -416,7 +403,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc); skb = sctp_event2skb(event);
sctp_ulpevent_set_owner(skb, asoc);
sre->sre_assoc_id = sctp_assoc2id(asoc); sre->sre_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -430,13 +418,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP - draft-01
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
sctp_chunk_t *chunk, const sctp_association_t *asoc, sctp_chunk_t *chunk,
__u16 flags, __u16 flags, __u32 error, int priority)
__u32 error,
int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sctp_send_failed *ssf; struct sctp_send_failed *ssf;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -452,16 +438,11 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
skb_pull(skb, sizeof(sctp_data_chunk_t)); skb_pull(skb, sizeof(sctp_data_chunk_t));
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION); event = sctp_ulpevent_init(event, MSG_NOTIFICATION);
if (!event) if (!event)
goto fail; goto fail;
/* Mark as malloced, even though the constructor was not
* called.
*/
event->malloced = 1;
ssf = (struct sctp_send_failed *) ssf = (struct sctp_send_failed *)
skb_push(skb, sizeof(struct sctp_send_failed)); skb_push(skb, sizeof(struct sctp_send_failed));
...@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -525,7 +506,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* same association identifier. For TCP style socket, this field is * same association identifier. For TCP style socket, this field is
* ignored. * ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc); skb = sctp_event2skb(event);
sctp_ulpevent_set_owner(skb, asoc);
ssf->ssf_assoc_id = sctp_assoc2id(asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -538,21 +520,22 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP - draft-01
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const sctp_association_t *asoc, const sctp_association_t *asoc,
__u16 flags, __u16 flags, int priority)
int priority)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
struct sctp_shutdown_event *sse; struct sctp_shutdown_event *sse;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority); MSG_NOTIFICATION, priority);
if (!event) if (!event)
goto fail; goto fail;
skb = sctp_event2skb(event);
sse = (struct sctp_shutdown_event *) sse = (struct sctp_shutdown_event *)
skb_put(event->parent, sizeof(struct sctp_shutdown_event)); skb_put(skb, sizeof(struct sctp_shutdown_event));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
...@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( ...@@ -587,7 +570,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc); sctp_ulpevent_set_owner(skb, asoc);
sse->sse_assoc_id = sctp_assoc2id(asoc); sse->sse_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event( ...@@ -600,13 +583,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
* to pass it to the upper layers. Go ahead and calculate the sndrcvinfo * to pass it to the upper layers. Go ahead and calculate the sndrcvinfo
* even if filtered out later. * even if filtered out later.
* *
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_chunk_t *chunk, int priority) sctp_chunk_t *chunk, int priority)
{ {
sctp_ulpevent_t *event, *levent; struct sctp_ulpevent *event;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *info;
struct sk_buff *skb, *list; struct sk_buff *skb, *list;
size_t padding, len; size_t padding, len;
...@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -638,24 +621,19 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_ulpevent_set_owner_r(skb, asoc); sctp_ulpevent_set_owner_r(skb, asoc);
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
/* Initialize event with flags 0. */ /* Initialize event with flags 0. */
event = sctp_ulpevent_init(event, skb, 0); event = sctp_ulpevent_init(event, 0);
if (!event) if (!event)
goto fail_init; goto fail_init;
event->malloced = 1; /* Note: Not clearing the entire event struct as
* this is just a fragment of the real event. However,
for (list = skb_shinfo(skb)->frag_list; list; list = list->next) { * 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_set_owner_r(list, asoc);
/* Initialize event with flags 0. */
levent = sctp_ulpevent_init(event, skb, 0);
if (!levent)
goto fail_init;
levent->malloced = 1;
}
info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo;
...@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -707,18 +685,26 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
* MSG_UNORDERED - This flag is present when the message was sent * MSG_UNORDERED - This flag is present when the message was sent
* non-ordered. * non-ordered.
*/ */
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
info->sinfo_flags |= MSG_UNORDERED; info->sinfo_flags |= MSG_UNORDERED;
/* FIXME: For reassembly, we need to have the fragmentation bits. /* sinfo_cumtsn: 32 bit (unsigned integer)
* This really does not belong in the event structure, but *
* its difficult to fix everything at the same time. Eventually, * This field will hold the current cumulative TSN as
* we should create and skb based chunk structure. This structure * known by the underlying SCTP layer. Note this field is
* storage can be converted to an event. --jgrimm * ignored when sending and only valid for a receive
* operation when sinfo_flags are set to MSG_UNORDERED.
*/
info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
}
/* Note: For reassembly, we need to have the fragmentation bits.
* For now, merge these into the msg_flags, since those bit
* possitions are not used.
*/ */
event->chunk_flags = chunk->chunk_hdr->flags; event->msg_flags |= chunk->chunk_hdr->flags;
/* With -04 draft, tsn moves into sndrcvinfo. */ /* With 04 draft, tsn moves into sndrcvinfo. */
info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn); info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn);
/* Context is not used on receive. */ /* Context is not used on receive. */
...@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, ...@@ -745,19 +731,79 @@ sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
return NULL; return NULL;
} }
/* Create a partial delivery related event.
*
* 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
*
* When a reciever is engaged in a partial delivery of a
* message this notification will be used to inidicate
* various events.
*/
struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const sctp_association_t *asoc, __u32 indication, int priority)
{
struct sctp_ulpevent *event;
struct sctp_rcv_pdapi_event *pd;
struct sk_buff *skb;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, priority);
if (!event)
goto fail;
skb = sctp_event2skb(event);
pd = (struct sctp_rcv_pdapi_event *)
skb_put(skb, sizeof(struct sctp_rcv_pdapi_event));
/* pdapi_type
* It should be SCTP_PARTIAL_DELIVERY_EVENT
*
* pdapi_flags: 16 bits (unsigned integer)
* Currently unused.
*/
pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
pd->pdapi_flags = 0;
/* pdapi_length: 32 bits (unsigned integer)
*
* This field is the total length of the notification data, including
* the notification header. It will generally be sizeof (struct
* sctp_rcv_pdapi_event).
*/
pd->pdapi_length = sizeof(struct sctp_rcv_pdapi_event);
/* pdapi_indication: 32 bits (unsigned integer)
*
* This field holds the indication being sent to the application.
*/
pd->pdapi_indication = indication;
/* pdapi_assoc_id: sizeof (sctp_assoc_t)
*
* The association id field, holds the identifier for the association.
*/
pd->pdapi_assoc_id = sctp_assoc2id(asoc);
return event;
fail:
return NULL;
}
/* Return the notification type, assuming this is a notification /* Return the notification type, assuming this is a notification
* event. * event.
*/ */
__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event) __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
{ {
union sctp_notification *notification; union sctp_notification *notification;
struct sk_buff *skb;
notification = (union sctp_notification *) event->parent->data; skb = sctp_event2skb((struct sctp_ulpevent *)event);
notification = (union sctp_notification *) skb->data;
return notification->h.sn_type; return notification->h.sn_type;
} }
/* Copy out the sndrcvinfo into a msghdr. */ /* Copy out the sndrcvinfo into a msghdr. */
void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
struct msghdr *msghdr) struct msghdr *msghdr)
{ {
if (!sctp_ulpevent_is_notification(event)) { if (!sctp_ulpevent_is_notification(event)) {
...@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event, ...@@ -771,7 +817,7 @@ void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
static void sctp_rcvmsg_rfree(struct sk_buff *skb) static void sctp_rcvmsg_rfree(struct sk_buff *skb)
{ {
sctp_association_t *asoc; sctp_association_t *asoc;
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
/* Current stack structures assume that the rcv buffer is /* Current stack structures assume that the rcv buffer is
* per socket. For UDP style sockets this is not true as * per socket. For UDP style sockets this is not true as
...@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -779,16 +825,17 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
* Use the local private area of the skb to track the owning * Use the local private area of the skb to track the owning
* association. * association.
*/ */
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
asoc = event->asoc; asoc = event->asoc;
sctp_assoc_rwnd_increase(asoc, skb_headlen(skb)); sctp_assoc_rwnd_increase(asoc, skb_headlen(skb));
sctp_association_put(asoc); sctp_association_put(asoc);
} }
/* Charge receive window for bytes recieved. */ /* Charge receive window for bytes recieved. */
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc) static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
sctp_association_t *asoc)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
/* The current stack structures assume that the rcv buffer is /* The current stack structures assume that the rcv buffer is
* per socket. For UDP-style sockets this is not true as * per socket. For UDP-style sockets this is not true as
...@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a ...@@ -798,7 +845,7 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
*/ */
sctp_association_hold(asoc); sctp_association_hold(asoc);
skb->sk = asoc->base.sk; skb->sk = asoc->base.sk;
event = (sctp_ulpevent_t *) skb->cb; event = sctp_skb2event(skb);
event->asoc = asoc; event->asoc = asoc;
skb->destructor = sctp_rcvmsg_rfree; skb->destructor = sctp_rcvmsg_rfree;
...@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a ...@@ -809,26 +856,26 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
/* A simple destructor to give up the reference to the association. */ /* A simple destructor to give up the reference to the association. */
static void sctp_ulpevent_rfree(struct sk_buff *skb) static void sctp_ulpevent_rfree(struct sk_buff *skb)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
event = (sctp_ulpevent_t *)skb->cb; event = sctp_skb2event(skb);
sctp_association_put(event->asoc); sctp_association_put(event->asoc);
} }
/* Hold the association in case the msg_name needs read out of /* Hold the association in case the msg_name needs read out of
* the association. * the association.
*/ */
static void sctp_ulpevent_set_owner(struct sk_buff *skb, static void sctp_ulpevent_set_owner(struct sk_buff *skb,
const sctp_association_t *asoc) const struct sctp_association *asoc)
{ {
sctp_ulpevent_t *event; struct sctp_ulpevent *event;
/* Cast away the const, as we are just wanting to /* Cast away the const, as we are just wanting to
* bump the reference count. * bump the reference count.
*/ */
sctp_association_hold((sctp_association_t *)asoc); sctp_association_hold((struct sctp_association *)asoc);
skb->sk = asoc->base.sk; skb->sk = asoc->base.sk;
event = (sctp_ulpevent_t *)skb->cb; event = sctp_skb2event(skb);
event->asoc = (sctp_association_t *)asoc; event->asoc = (struct sctp_association *)asoc;
skb->destructor = sctp_ulpevent_rfree; skb->destructor = sctp_ulpevent_rfree;
} }
...@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, ...@@ -84,6 +84,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
ulpq->asoc = asoc; ulpq->asoc = asoc;
skb_queue_head_init(&ulpq->reasm); skb_queue_head_init(&ulpq->reasm);
skb_queue_head_init(&ulpq->lobby); skb_queue_head_init(&ulpq->lobby);
ulpq->pd_mode = 0;
ulpq->malloced = 0; ulpq->malloced = 0;
return ulpq; return ulpq;
...@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq) ...@@ -96,15 +97,16 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
struct sk_buff *skb; struct sk_buff *skb;
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
while ((skb = skb_dequeue(&ulpq->lobby))) { while ((skb = __skb_dequeue(&ulpq->lobby))) {
event = (struct sctp_ulpevent *) skb->cb; event = sctp_skb2event(skb);
sctp_ulpevent_free(event); sctp_ulpevent_free(event);
} }
while ((skb = skb_dequeue(&ulpq->reasm))) { while ((skb = __skb_dequeue(&ulpq->reasm))) {
event = (struct sctp_ulpevent *) skb->cb; event = sctp_skb2event(skb);
sctp_ulpevent_free(event); sctp_ulpevent_free(event);
} }
} }
/* Dispose of a ulpqueue. */ /* Dispose of a ulpqueue. */
...@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq) ...@@ -117,7 +119,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
/* Process an incoming DATA chunk. */ /* Process an incoming DATA chunk. */
int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
int priority) int priority)
{ {
struct sk_buff_head temp; struct sk_buff_head temp;
sctp_data_chunk_t *hdr; sctp_data_chunk_t *hdr;
...@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, ...@@ -125,12 +127,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; hdr = (sctp_data_chunk_t *) chunk->chunk_hdr;
/* FIXME: Instead of event being the skb clone, we really should /* Create an event from the incoming chunk. */
* have a new skb based chunk structure that we can convert to
* an event. Temporarily, I'm carrying a few chunk fields in
* the event to allow reassembly. Its too painful to change
* everything at once. --jgrimm
*/
event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority);
if (!event) if (!event)
return -ENOMEM; return -ENOMEM;
...@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, ...@@ -139,10 +136,10 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
event = sctp_ulpq_reasm(ulpq, event); event = sctp_ulpq_reasm(ulpq, event);
/* Do ordering if needed. */ /* Do ordering if needed. */
if (event) { if ((event) && (event->msg_flags & MSG_EOR)){
/* Create a temporary list to collect chunks on. */ /* Create a temporary list to collect chunks on. */
skb_queue_head_init(&temp); skb_queue_head_init(&temp);
skb_queue_tail(&temp, event->parent); __skb_queue_tail(&temp, sctp_event2skb(event));
event = sctp_ulpq_order(ulpq, event); event = sctp_ulpq_order(ulpq, event);
} }
...@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, ...@@ -154,10 +151,40 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
return 0; return 0;
} }
/* Clear the partial delivery mode for this socket. Note: This
* assumes that no association is currently in partial delivery mode.
*/
int sctp_clear_pd(struct sock *sk)
{
struct sctp_opt *sp;
sp = sctp_sk(sk);
sp->pd_mode = 0;
if (!skb_queue_empty(&sp->pd_lobby)) {
struct list_head *list;
sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue);
list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
INIT_LIST_HEAD(list);
return 1;
}
return 0;
}
/* Clear the pd_mode and restart any pending messages waiting for delivery. */
static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
{
ulpq->pd_mode = 0;
return sctp_clear_pd(ulpq->asoc->base.sk);
}
/* Add a new event for propogation to the ULP. */ /* Add a new event for propogation to the ULP. */
int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
{ {
struct sock *sk = ulpq->asoc->base.sk; struct sock *sk = ulpq->asoc->base.sk;
struct sk_buff_head *queue;
int clear_pd = 0;
/* If the socket is just going to throw this away, do not /* If the socket is just going to throw this away, do not
* even try to deliver it. * even try to deliver it.
...@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event) ...@@ -169,29 +196,55 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe)) if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe))
goto out_free; goto out_free;
/* If we are in partial delivery mode, post to the lobby until
* partial delivery is cleared, unless, of course _this_ is
* the association the cause of the partial delivery.
*/
if (!sctp_sk(sk)->pd_mode) {
queue = &sk->receive_queue;
} else if (ulpq->pd_mode) {
if (event->msg_flags & MSG_NOTIFICATION)
queue = &sctp_sk(sk)->pd_lobby;
else {
clear_pd = event->msg_flags & MSG_EOR;
queue = &sk->receive_queue;
}
} else
queue = &sctp_sk(sk)->pd_lobby;
/* If we are harvesting multiple skbs they will be /* If we are harvesting multiple skbs they will be
* collected on a list. * collected on a list.
*/ */
if (event->parent->list) if (sctp_event2skb(event)->list)
sctp_skb_list_tail(event->parent->list, &sk->receive_queue); sctp_skb_list_tail(sctp_event2skb(event)->list, queue);
else else
skb_queue_tail(&sk->receive_queue, event->parent); skb_queue_tail(queue, sctp_event2skb(event));
wake_up_interruptible(sk->sleep); /* Did we just complete partial delivery and need to get
* rolling again? Move pending data to the receive
* queue.
*/
if (clear_pd)
sctp_ulpq_clear_pd(ulpq);
if (queue == &sk->receive_queue)
wake_up_interruptible(sk->sleep);
return 1; return 1;
out_free: out_free:
if (event->parent->list) if (sctp_event2skb(event)->list)
skb_queue_purge(event->parent->list); skb_queue_purge(sctp_event2skb(event)->list);
else else
kfree_skb(event->parent); kfree_skb(sctp_event2skb(event));
return 0; return 0;
} }
/* 2nd Level Abstractions */ /* 2nd Level Abstractions */
/* Helper function to store chunks that need to be reassembled. */ /* Helper function to store chunks that need to be reassembled. */
static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
struct sctp_ulpevent *event) struct sctp_ulpevent *event)
{ {
struct sk_buff *pos, *tmp; struct sk_buff *pos, *tmp;
...@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, ...@@ -202,7 +255,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* Find the right place in this list. We store them by TSN. */ /* Find the right place in this list. We store them by TSN. */
sctp_skb_for_each(pos, &ulpq->reasm, tmp) { sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
cevent = (struct sctp_ulpevent *)pos->cb; cevent = sctp_skb2event(pos);
ctsn = cevent->sndrcvinfo.sinfo_tsn; ctsn = cevent->sndrcvinfo.sinfo_tsn;
if (TSN_lt(tsn, ctsn)) if (TSN_lt(tsn, ctsn))
...@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, ...@@ -211,9 +264,10 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
/* If the queue is empty, we have a different function to call. */ /* If the queue is empty, we have a different function to call. */
if (skb_peek(&ulpq->reasm)) if (skb_peek(&ulpq->reasm))
__skb_insert(event->parent, pos->prev, pos, &ulpq->reasm); __skb_insert(sctp_event2skb(event), pos->prev, pos,
&ulpq->reasm);
else else
__skb_queue_tail(&ulpq->reasm, event->parent); __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
} }
/* Helper function to return an event corresponding to the reassembled /* Helper function to return an event corresponding to the reassembled
...@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff * ...@@ -231,7 +285,10 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
struct sk_buff *list = skb_shinfo(f_frag)->frag_list; struct sk_buff *list = skb_shinfo(f_frag)->frag_list;
/* Store the pointer to the 2nd skb */ /* Store the pointer to the 2nd skb */
pos = f_frag->next; if (f_frag == l_frag)
pos = NULL;
else
pos = f_frag->next;
/* Get the last skb in the f_frag's frag_list if present. */ /* Get the last skb in the f_frag's frag_list if present. */
for (last = list; list; last = list, list = list->next); for (last = list; list; last = list, list = list->next);
...@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff * ...@@ -246,7 +303,8 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
/* Remove the first fragment from the reassembly queue. */ /* Remove the first fragment from the reassembly queue. */
__skb_unlink(f_frag, f_frag->list); __skb_unlink(f_frag, f_frag->list);
do { while (pos) {
pnext = pos->next; pnext = pos->next;
/* Update the len and data_len fields of the first fragment. */ /* Update the len and data_len fields of the first fragment. */
...@@ -262,25 +320,26 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff * ...@@ -262,25 +320,26 @@ static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *
pos->next = pnext; pos->next = pnext;
pos = pnext; pos = pnext;
} while (1); };
event = (sctp_ulpevent_t *) f_frag->cb; event = sctp_skb2event(f_frag);
return event; return event;
} }
/* Helper function to check if an incoming chunk has filled up the last /* Helper function to check if an incoming chunk has filled up the last
* missing fragment in a SCTP datagram and return the corresponding event. * missing fragment in a SCTP datagram and return the corresponding event.
*/ */
static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq) static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq)
{ {
struct sk_buff *pos, *tmp; struct sk_buff *pos, *tmp;
sctp_ulpevent_t *cevent; struct sctp_ulpevent *cevent;
struct sk_buff *first_frag = NULL; struct sk_buff *first_frag = NULL;
__u32 ctsn, next_tsn; __u32 ctsn, next_tsn;
sctp_ulpevent_t *retval = NULL; struct sctp_ulpevent *retval = NULL;
/* Initialized to 0 just to avoid compiler warning message. Will /* Initialized to 0 just to avoid compiler warning message. Will
* never be used with this value. It is referenced only after it * never be used with this value. It is referenced only after it
* is set when we find the first fragment of a message. * is set when we find the first fragment of a message.
*/ */
...@@ -296,10 +355,10 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq * ...@@ -296,10 +355,10 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
* start the next pass when we find another first fragment. * start the next pass when we find another first fragment.
*/ */
sctp_skb_for_each(pos, &ulpq->reasm, tmp) { sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
cevent = (sctp_ulpevent_t *) pos->cb; cevent = sctp_skb2event(pos);
ctsn = cevent->sndrcvinfo.sinfo_tsn; ctsn = cevent->sndrcvinfo.sinfo_tsn;
switch (cevent->chunk_flags & SCTP_DATA_FRAG_MASK) { switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
case SCTP_DATA_FIRST_FRAG: case SCTP_DATA_FIRST_FRAG:
first_frag = pos; first_frag = pos;
next_tsn = ctsn + 1; next_tsn = ctsn + 1;
...@@ -313,7 +372,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq * ...@@ -313,7 +372,7 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
break; break;
case SCTP_DATA_LAST_FRAG: case SCTP_DATA_LAST_FRAG:
if ((first_frag) && (ctsn == next_tsn)) if (first_frag && (ctsn == next_tsn))
retval = sctp_make_reassembled_event( retval = sctp_make_reassembled_event(
first_frag, pos); first_frag, pos);
else else
...@@ -324,42 +383,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq * ...@@ -324,42 +383,170 @@ static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *
/* We have the reassembled event. There is no need to look /* We have the reassembled event. There is no need to look
* further. * further.
*/ */
if (retval) if (retval) {
retval->msg_flags |= MSG_EOR;
break; break;
}
} }
return retval; return retval;
} }
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that /* Retrieve the next set of fragments of a partial message. */
* need reassembling. static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq)
*/
static inline sctp_ulpevent_t *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
sctp_ulpevent_t *event)
{ {
sctp_ulpevent_t *retval = NULL; struct sk_buff *pos, *tmp, *last_frag, *first_frag;
struct sctp_ulpevent *cevent;
__u32 ctsn, next_tsn;
int is_last;
struct sctp_ulpevent *retval;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for the first
* sequence of fragmented chunks.
*/
if (skb_queue_empty(&ulpq->reasm))
return NULL;
last_frag = first_frag = NULL;
retval = NULL;
next_tsn = 0;
is_last = 0;
sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
cevent = sctp_skb2event(pos);
ctsn = cevent->sndrcvinfo.sinfo_tsn;
switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
case SCTP_DATA_MIDDLE_FRAG:
if (!first_frag) {
first_frag = pos;
next_tsn = ctsn + 1;
last_frag = pos;
} else if (next_tsn == ctsn)
next_tsn++;
else
goto done;
break;
case SCTP_DATA_LAST_FRAG:
if (!first_frag)
first_frag = pos;
else if (ctsn != next_tsn)
goto done;
last_frag = pos;
is_last = 1;
goto done;
default:
return NULL;
};
}
/* FIXME: We should be using some new chunk structure here /* We have the reassembled event. There is no need to look
* instead of carrying chunk fields in the event structure. * further.
* This is temporary as it is too painful to change everything
* at once.
*/ */
done:
retval = sctp_make_reassembled_event(first_frag, last_frag);
if (is_last)
retval->msg_flags |= MSG_EOR;
return retval;
}
/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
* need reassembling.
*/
static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
struct sctp_ulpevent *event)
{
struct sctp_ulpevent *retval = NULL;
/* Check if this is part of a fragmented message. */ /* Check if this is part of a fragmented message. */
if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK)) if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) {
event->msg_flags |= MSG_EOR;
return event; return event;
}
sctp_ulpq_store_reasm(ulpq, event); sctp_ulpq_store_reasm(ulpq, event);
retval = sctp_ulpq_retrieve_reassembled(ulpq); if (!ulpq->pd_mode)
retval = sctp_ulpq_retrieve_reassembled(ulpq);
else {
__u32 ctsn, ctsnap;
/* Do not even bother unless this is the next tsn to
* be delivered.
*/
ctsn = event->sndrcvinfo.sinfo_tsn;
ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map);
if (TSN_lte(ctsn, ctsnap))
retval = sctp_ulpq_retrieve_partial(ulpq);
}
return retval; return retval;
} }
/* Retrieve the first part (sequential fragments) for partial delivery. */
static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq)
{
struct sk_buff *pos, *tmp, *last_frag, *first_frag;
struct sctp_ulpevent *cevent;
__u32 ctsn, next_tsn;
struct sctp_ulpevent *retval;
/* The chunks are held in the reasm queue sorted by TSN.
* Walk through the queue sequentially and look for a sequence of
* fragmented chunks that start a datagram.
*/
if (skb_queue_empty(&ulpq->reasm))
return NULL;
last_frag = first_frag = NULL;
retval = NULL;
next_tsn = 0;
sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
cevent = sctp_skb2event(pos);
ctsn = cevent->sndrcvinfo.sinfo_tsn;
switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
case SCTP_DATA_FIRST_FRAG:
if (!first_frag) {
first_frag = pos;
next_tsn = ctsn + 1;
last_frag = pos;
} else
goto done;
break;
case SCTP_DATA_MIDDLE_FRAG:
if (!first_frag)
return NULL;
if (ctsn == next_tsn) {
next_tsn++;
last_frag = pos;
} else
goto done;
break;
default:
return NULL;
};
}
/* We have the reassembled event. There is no need to look
* further.
*/
done:
retval = sctp_make_reassembled_event(first_frag, last_frag);
return retval;
}
/* Helper function to gather skbs that have possibly become /* Helper function to gather skbs that have possibly become
* ordered by an an incoming chunk. * ordered by an an incoming chunk.
*/ */
static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
sctp_ulpevent_t *event) struct sctp_ulpevent *event)
{ {
struct sk_buff *pos, *tmp; struct sk_buff *pos, *tmp;
struct sctp_ulpevent *cevent; struct sctp_ulpevent *cevent;
...@@ -373,7 +560,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, ...@@ -373,7 +560,7 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* We are holding the chunks by stream, by SSN. */ /* We are holding the chunks by stream, by SSN. */
sctp_skb_for_each(pos, &ulpq->lobby, tmp) { sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
cevent = (sctp_ulpevent_t *) pos->cb; cevent = (struct sctp_ulpevent *) pos->cb;
csid = cevent->sndrcvinfo.sinfo_stream; csid = cevent->sndrcvinfo.sinfo_stream;
cssn = cevent->sndrcvinfo.sinfo_ssn; cssn = cevent->sndrcvinfo.sinfo_ssn;
...@@ -390,32 +577,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq, ...@@ -390,32 +577,31 @@ static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
/* Found it, so mark in the ssnmap. */ /* Found it, so mark in the ssnmap. */
sctp_ssn_next(in, sid); sctp_ssn_next(in, sid);
__skb_unlink(pos, pos->list); __skb_unlink(pos, pos->list);
/* Attach all gathered skbs to the event. */ /* Attach all gathered skbs to the event. */
__skb_queue_tail(event->parent->list, pos); __skb_queue_tail(sctp_event2skb(event)->list, pos);
} }
} }
/* Helper function to store chunks needing ordering. */ /* Helper function to store chunks needing ordering. */
static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
sctp_ulpevent_t *event) struct sctp_ulpevent *event)
{ {
struct sk_buff *pos, *tmp; struct sk_buff *pos, *tmp;
sctp_ulpevent_t *cevent; struct sctp_ulpevent *cevent;
__u16 sid, csid; __u16 sid, csid;
__u16 ssn, cssn; __u16 ssn, cssn;
sid = event->sndrcvinfo.sinfo_stream; sid = event->sndrcvinfo.sinfo_stream;
ssn = event->sndrcvinfo.sinfo_ssn; ssn = event->sndrcvinfo.sinfo_ssn;
/* Find the right place in this list. We store them by /* Find the right place in this list. We store them by
* stream ID and then by SSN. * stream ID and then by SSN.
*/ */
sctp_skb_for_each(pos, &ulpq->lobby, tmp) { sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
cevent = (sctp_ulpevent_t *) pos->cb; cevent = (struct sctp_ulpevent *) pos->cb;
csid = cevent->sndrcvinfo.sinfo_stream; csid = cevent->sndrcvinfo.sinfo_stream;
cssn = cevent->sndrcvinfo.sinfo_ssn; cssn = cevent->sndrcvinfo.sinfo_ssn;
...@@ -427,25 +613,20 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq, ...@@ -427,25 +613,20 @@ static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
/* If the queue is empty, we have a different function to call. */ /* If the queue is empty, we have a different function to call. */
if (skb_peek(&ulpq->lobby)) if (skb_peek(&ulpq->lobby))
__skb_insert(event->parent, pos->prev, pos, &ulpq->lobby); __skb_insert(sctp_event2skb(event), pos->prev, pos,
&ulpq->lobby);
else else
__skb_queue_tail(&ulpq->lobby, event->parent); __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
} }
static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq, static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
sctp_ulpevent_t *event) struct sctp_ulpevent *event)
{ {
__u16 sid, ssn; __u16 sid, ssn;
struct sctp_stream *in; struct sctp_stream *in;
/* FIXME: We should be using some new chunk structure here
* instead of carrying chunk fields in the event structure.
* This is temporary as it is too painful to change everything
* at once.
*/
/* Check if this message needs ordering. */ /* Check if this message needs ordering. */
if (SCTP_DATA_UNORDERED & event->chunk_flags) if (SCTP_DATA_UNORDERED & event->msg_flags)
return event; return event;
/* Note: The stream ID must be verified before this routine. */ /* Note: The stream ID must be verified before this routine. */
...@@ -472,3 +653,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq, ...@@ -472,3 +653,54 @@ static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
return event; return event;
} }
/* Partial deliver the first message as there is pressure on rwnd. */
void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
struct sctp_chunk *chunk, int priority)
{
struct sctp_ulpevent *event;
/* Are we already in partial delivery mode? */
if (!sctp_sk(ulpq->asoc->base.sk)->pd_mode) {
/* Is partial delivery possible? */
event = sctp_ulpq_retrieve_first(ulpq);
/* Send event to the ULP. */
if (event) {
sctp_ulpq_tail_event(ulpq, event);
sctp_sk(ulpq->asoc->base.sk)->pd_mode = 1;
ulpq->pd_mode = 1;
return;
}
}
/* Assert: Either already in partial delivery mode or partial
* delivery wasn't possible, so now the only recourse is
* to renege. FIXME: Add renege support starts here.
*/
}
/* Notify the application if an association is aborted and in
* partial delivery mode. Send up any pending received messages.
*/
void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
{
struct sctp_ulpevent *ev = NULL;
struct sock *sk;
if (!ulpq->pd_mode)
return;
sk = ulpq->asoc->base.sk;
if (sctp_ulpevent_type_enabled(SCTP_PARTIAL_DELIVERY_EVENT,
&sctp_sk(sk)->subscribe))
ev = sctp_ulpevent_make_pdapi(ulpq->asoc,
SCTP_PARTIAL_DELIVERY_ABORTED,
priority);
if (ev)
skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
/* If there is data waiting, send it up the socket now. */
if (sctp_ulpq_clear_pd(ulpq) || ev)
wake_up_interruptible(sk->sleep);
}
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