Commit 9967b51f authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge us.ibm.com:/home/sridhar/BK/linux-2.5.62

into us.ibm.com:/home/sridhar/BK/lksctp-2.5.62
parents 611f4c04 13970d8e
......@@ -86,6 +86,7 @@ typedef enum {
SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */
SCTP_CMD_SETUP_T2, /* Hi-level, setup T2-shutdown parms. */
SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */
SCTP_CMD_CHUNK_PD, /* Partial data delivery considerations. */
SCTP_CMD_LAST
} sctp_verb_t;
......@@ -115,7 +116,7 @@ typedef union {
struct sctp_transport *transport;
sctp_bind_addr_t *bp;
sctp_init_chunk_t *init;
sctp_ulpevent_t *ulpevent;
struct sctp_ulpevent *ulpevent;
sctp_packet_t *packet;
sctp_sackhdr_t *sackh;
} sctp_arg_t;
......@@ -163,7 +164,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc)
SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport)
SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp)
SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, sctp_ulpevent_t *, ulpevent)
SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet)
SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
......
......@@ -214,6 +214,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field)
#define SCTP_INC_STATS_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field)
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
#define SCTP_DEC_STATS(field) SNMP_DEC_STATS(sctp_statistics, field)
/* Determine if this is a valid kernel address. */
static inline int sctp_is_valid_kaddr(unsigned long addr)
......
......@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -105,27 +105,25 @@ union sctp_addr {
/* Forward declarations for data structures. */
struct sctp_protocol;
struct SCTP_endpoint;
struct SCTP_association;
struct sctp_endpoint;
struct sctp_association;
struct sctp_transport;
struct SCTP_packet;
struct SCTP_chunk;
struct SCTP_inqueue;
struct sctp_packet;
struct sctp_chunk;
struct sctp_inq;
struct sctp_outq;
struct SCTP_bind_addr;
struct sctp_bind_addr;
struct sctp_ulpq;
struct sctp_opt;
struct sctp_endpoint_common;
struct sctp_ssnmap;
typedef struct sctp_protocol sctp_protocol_t;
typedef struct SCTP_endpoint sctp_endpoint_t;
typedef struct SCTP_association sctp_association_t;
typedef struct SCTP_packet sctp_packet_t;
typedef struct SCTP_chunk sctp_chunk_t;
typedef struct SCTP_inqueue sctp_inqueue_t;
typedef struct SCTP_bind_addr sctp_bind_addr_t;
typedef struct sctp_opt sctp_opt_t;
typedef struct sctp_endpoint sctp_endpoint_t;
typedef struct sctp_association sctp_association_t;
typedef struct sctp_packet sctp_packet_t;
typedef struct sctp_chunk sctp_chunk_t;
typedef struct sctp_bind_addr sctp_bind_addr_t;
typedef struct sctp_endpoint_common sctp_endpoint_common_t;
#include <net/sctp/tsnmap.h>
......@@ -250,10 +248,10 @@ struct sctp_af {
int optname,
char *optval,
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 *saddr);
void (*get_saddr) (sctp_association_t *asoc,
void (*get_saddr) (struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr);
......@@ -289,7 +287,7 @@ int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
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 *);
int (*af_supported) (sa_family_t);
int (*cmp_addr) (const union sctp_addr *,
......@@ -311,6 +309,9 @@ struct sctp_opt {
/* What kind of a socket is this? */
sctp_socket_type_t type;
/* PF_ family specific functions. */
struct sctp_pf *pf;
/* What is our base endpointer? */
sctp_endpoint_t *ep;
......@@ -324,7 +325,10 @@ struct sctp_opt {
__u32 autoclose;
__u8 nodelay;
__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)
* As a matter of convenience, we remember the SCTP common header for
* each chunk as well as a few other header pointers...
*/
struct SCTP_chunk {
struct sctp_chunk {
/* These first three elements MUST PRECISELY match the first
* three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions.
......@@ -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
* transmission.
*/
struct SCTP_packet {
struct sctp_packet {
/* These are the SCTP header values (host order) for the packet. */
__u16 source_port;
__u16 destination_port;
......@@ -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
* SCTP. We write packets to it and read chunks from it.
*/
struct SCTP_inqueue {
/* This is actually a queue of sctp_chunk_t each
struct sctp_inq {
/* This is actually a queue of sctp_chunk each
* containing a partially decoded packet.
*/
struct sk_buff_head in;
......@@ -864,13 +868,12 @@ struct SCTP_inqueue {
int malloced; /* Is this structure kfree()able? */
};
sctp_inqueue_t *sctp_inqueue_new(void);
void sctp_inqueue_init(sctp_inqueue_t *);
void sctp_inqueue_free(sctp_inqueue_t *);
void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet);
sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *);
void sctp_inqueue_set_th_handler(sctp_inqueue_t *,
void (*)(void *), void *);
struct sctp_inq *sctp_inq_new(void);
void sctp_inq_init(struct sctp_inq *);
void sctp_inq_free(struct sctp_inq *);
void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet);
struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
/* This is the structure we use to hold outbound chunks. You push
* chunks in and they automatically pop out the other end as bundled
......@@ -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 */
struct SCTP_bind_addr {
struct sctp_bind_addr {
/* RFC 2960 12.1 Parameters necessary for the SCTP instance
*
......@@ -1043,7 +1046,7 @@ struct sctp_endpoint_common {
struct sock *sk;
/* This is where we receive inbound chunks. */
sctp_inqueue_t inqueue;
struct sctp_inq inqueue;
/* This substructure includes the defining parameters of the
* endpoint:
......@@ -1076,7 +1079,7 @@ struct sctp_endpoint_common {
* off one of these.
*/
struct SCTP_endpoint {
struct sctp_endpoint {
/* Common substructure for endpoint and association. */
sctp_endpoint_common_t base;
......@@ -1172,7 +1175,7 @@ __u32 sctp_generate_tsn(const sctp_endpoint_t *ep);
/* Here we have information about each individual association. */
struct SCTP_association {
struct sctp_association {
/* A base structure common to endpoint and association.
* In this context, it represents the associations's view
......@@ -1288,19 +1291,11 @@ struct SCTP_association {
* used in the bulk of the text. This value is hidden
* in tsn_map--we get it by calling sctp_tsnmap_get_ctsn().
*/
sctp_tsnmap_t tsn_map;
struct sctp_tsnmap tsn_map;
__u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)];
/* We record duplicate TSNs here. We clear this after
* every SACK.
* FIXME: We should move this into the tsnmap? --jgrimm
*/
sctp_dup_tsn_t dup_tsns[SCTP_MAX_DUP_TSNS];
int next_dup_tsn;
/* Do we need to sack the peer? */
uint8_t sack_needed;
__u8 sack_needed;
/* These are capabilities which our peer advertised. */
__u8 ecn_capable; /* Can peer do ECN? */
__u8 ipv4_address; /* Peer understands IPv4 addresses? */
......@@ -1457,7 +1452,10 @@ struct SCTP_association {
struct {
__u16 stream;
__u16 flags;
__u32 ppid;
__u32 context;
__u32 timetolive;
} defaults;
/* This tracks outbound ssn for a given stream. */
......@@ -1615,6 +1613,7 @@ void sctp_association_put(sctp_association_t *);
void sctp_association_hold(sctp_association_t *);
struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *);
void sctp_assoc_update_retran_path(sctp_association_t *);
struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *,
const union sctp_addr *);
struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *,
......
......@@ -38,8 +38,6 @@
#ifndef __sctp_tsnmap_h__
#define __sctp_tsnmap_h__
/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
* Mapping An array of bits or bytes indicating which out of
* Array order TSN's have been received (relative to the
......@@ -48,9 +46,7 @@
* will be set to all zero. This structure may be
* in the form of a circular buffer or bit array.
*/
typedef struct sctp_tsnmap {
struct sctp_tsnmap {
/* This array counts the number of chunks with each TSN.
* It points at one of the two buffers with which we will
* ping-pong between.
......@@ -93,25 +89,30 @@ typedef struct sctp_tsnmap {
/* This is the highest TSN we've marked. */
__u32 max_tsn_seen;
/* No. of data chunks pending receipt. used by SCTP_STATUS sockopt */
/* Data chunks pending receipt. used by SCTP_STATUS sockopt */
__u16 pending_data;
/* We record duplicate TSNs here. We clear this after
* every SACK. Store up to SCTP_MAX_DUP_TSNS worth of
* information.
*/
__u32 dup_tsns[SCTP_MAX_DUP_TSNS];
__u16 num_dup_tsns;
int malloced;
__u8 raw_map[0];
} sctp_tsnmap_t;
};
typedef struct sctp_tsnmap_iter {
struct sctp_tsnmap_iter {
__u32 start;
} sctp_tsnmap_iter_t;
};
/* Create a new tsnmap. */
sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn,
int priority);
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority);
/* Dispose of a tsnmap. */
void sctp_tsnmap_free(sctp_tsnmap_t *map);
void sctp_tsnmap_free(struct sctp_tsnmap *);
/* This macro assists in creation of external storage for variable length
* internal buffers. We double allocate so the overflow map works.
......@@ -119,9 +120,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map);
#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
/* Initialize a block of memory as a tsnmap. */
sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn);
struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *, __u16 len,
__u32 initial_tsn);
/* Test the tracking state of this TSN.
* Returns:
......@@ -129,29 +129,51 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
* >0 if the TSN has been seen (duplicate)
* <0 if the TSN is invalid (too large to track)
*/
int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn);
int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
/* Mark this TSN as seen. */
void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn);
void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
/* Retrieve the Cumulative TSN ACK Point. */
__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map);
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *);
/* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map);
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *);
/* How many Duplicate TSNs are stored? */
static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map)
{
return map->num_dup_tsns;
}
/* Return pointer to duplicate tsn array as needed by SACK. */
static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map)
{
map->num_dup_tsns = 0;
return map->dup_tsns;
}
/* Mark a duplicate TSN. Note: we limit how many we are willing to
* store and consequently report.
*/
static inline void sctp_tsnmap_mark_dup(struct sctp_tsnmap *map, __u32 tsn)
{
if (map->num_dup_tsns < SCTP_MAX_DUP_TSNS)
map->dup_tsns[map->num_dup_tsns++] = tsn;
}
/* Is there a gap in the TSN map? */
int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map);
int sctp_tsnmap_has_gap(const struct sctp_tsnmap *);
/* Initialize a gap ack block interator from user-provided memory. */
void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter);
void sctp_tsnmap_iter_init(const struct sctp_tsnmap *,
struct sctp_tsnmap_iter *);
/* Get the next gap ack blocks. We return 0 if there are no more
* gap ack blocks.
*/
int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
__u16 *start, __u16 *end);
int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
#endif /* __sctp_tsnmap_h__ */
......
......@@ -46,26 +46,31 @@
/* Warning: This sits inside an skb.cb[] area. Be very careful of
* growing this structure as it is at the maximum limit now.
*/
typedef struct sctp_ulpevent {
int malloced;
sctp_association_t *asoc;
struct sk_buff *parent;
struct sctp_ulpevent {
struct sctp_association *asoc;
struct sctp_sndrcvinfo sndrcvinfo;
int chunk_flags; /* Temp. until we get a new chunk_t */
int msg_flags;
} sctp_ulpevent_t;
};
/* 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);
}
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);
/* 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;
}
int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event);
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 *);
sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(
const struct SCTP_association *asoc,
struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
const struct sctp_association *asoc,
__u16 flags,
__u16 state,
__u16 error,
......@@ -73,58 +78,65 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(
__u16 inbound,
int priority);
sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
const struct SCTP_association *asoc,
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);
sctp_ulpevent_t *sctp_ulpevent_make_remote_error(
const struct SCTP_association *asoc,
struct SCTP_chunk *chunk,
struct sctp_ulpevent *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,
struct sctp_ulpevent *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,
struct sctp_ulpevent *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);
struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const struct sctp_association *asoc,
__u32 indication, int priority);
__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event);
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? */
static inline int sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event,
const struct sctp_event_subscribe *mask)
static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event,
struct sctp_event_subscribe *mask)
{
const char *amask = (const char *) mask;
__u16 sn_type;
int enabled = 1;
if (sctp_ulpevent_is_notification(event)) {
sn_type = sctp_ulpevent_get_notification_type(event);
enabled = amask[sn_type - SCTP_SN_TYPE_BASE];
enabled = sctp_ulpevent_type_enabled(sn_type, mask);
}
return enabled;
}
#endif /* __sctp_ulpevent_h__ */
......
......@@ -48,7 +48,8 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */
struct sctp_ulpq {
int malloced;
char malloced;
char pd_mode;
sctp_association_t *asoc;
struct sk_buff_head reasm;
struct sk_buff_head lobby;
......@@ -60,13 +61,19 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */
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. */
int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
/* Is the ulpqueue empty. */
int sctp_ulpqueue_is_empty(struct sctp_ulpq *);
/* Perform partial delivery. */
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__ */
......
......@@ -166,6 +166,7 @@ struct sctp_sndrcvinfo {
__u32 sinfo_context;
__u32 sinfo_timetolive;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
};
......@@ -367,6 +368,7 @@ struct sctp_rcv_pdapi_event {
sctp_assoc_t pdapi_assoc_id;
};
enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
/*
* Described in Section 7.3
......@@ -414,8 +416,8 @@ enum sctp_sn_type {
SCTP_SN_TYPE_BASE = (1<<15),
SCTP_ASSOC_CHANGE,
SCTP_PEER_ADDR_CHANGE,
SCTP_REMOTE_ERROR,
SCTP_SEND_FAILED,
SCTP_REMOTE_ERROR,
SCTP_SHUTDOWN_EVENT,
SCTP_PARTIAL_DELIVERY_EVENT,
SCTP_ADAPTION_INDICATION,
......
......@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \
output.o input.o hashdriver.o sla1.o \
debug.o ssnmap.o
debug.o ssnmap.o proc.o
ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o
......
......@@ -95,7 +95,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
sctp_scope_t scope,
int priority)
{
sctp_opt_t *sp;
struct sctp_opt *sp;
int i;
/* Retrieve the SCTP per socket area. */
......@@ -241,8 +241,8 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->peer.sack_needed = 1;
/* Create an input queue. */
sctp_inqueue_init(&asoc->base.inqueue);
sctp_inqueue_set_th_handler(&asoc->base.inqueue,
sctp_inq_init(&asoc->base.inqueue);
sctp_inq_set_th_handler(&asoc->base.inqueue,
(void (*)(void *))sctp_assoc_bh_rcv,
asoc);
......@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Set up the tsn tracking. */
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0);
asoc->peer.next_dup_tsn = 0;
skb_queue_head_init(&asoc->addip_chunks);
......@@ -311,7 +310,7 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_ulpq_free(&asoc->ulpq);
/* Dispose of any pending chunks on the inqueue. */
sctp_inqueue_free(&asoc->base.inqueue);
sctp_inq_free(&asoc->base.inqueue);
/* Free ssnmap storage. */
sctp_ssnmap_free(asoc->ssnmap);
......@@ -368,7 +367,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
int priority)
{
struct sctp_transport *peer;
sctp_opt_t *sp;
struct sctp_opt *sp;
unsigned short port;
/* AF_INET and AF_INET6 share common port field. */
......@@ -505,7 +504,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
struct sctp_transport *t = NULL;
struct sctp_transport *first;
struct sctp_transport *second;
sctp_ulpevent_t *event;
struct sctp_ulpevent *event;
struct list_head *pos;
int spc_state = 0;
......@@ -776,7 +775,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sctp_endpoint_t *ep;
sctp_chunk_t *chunk;
struct sock *sk;
sctp_inqueue_t *inqueue;
struct sctp_inq *inqueue;
int state, subtype;
sctp_assoc_t associd = sctp_assoc2id(asoc);
int error = 0;
......@@ -786,7 +785,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
sk = asoc->base.sk;
inqueue = &asoc->base.inqueue;
while (NULL != (chunk = sctp_pop_inqueue(inqueue))) {
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
state = asoc->state;
subtype = chunk->chunk_hdr->type;
......@@ -795,6 +794,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
*/
if (sctp_chunk_is_data(chunk))
asoc->peer.last_data_from = chunk->transport;
else
SCTP_INC_STATS(SctpInCtrlChunks);
if (chunk->transport)
chunk->transport->last_time_heard = jiffies;
......@@ -819,7 +820,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
/* This routine moves an association from its old sk to a new sk. */
void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
{
sctp_opt_t *newsp = sctp_sk(newsk);
struct sctp_opt *newsp = sctp_sk(newsk);
/* Delete the association from the old endpoint's list of
* associations.
......@@ -848,7 +849,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* Copy in new parameters of peer. */
asoc->c = new->c;
asoc->peer.rwnd = new->peer.rwnd;
asoc->peer.next_dup_tsn = new->peer.next_dup_tsn;
asoc->peer.sack_needed = new->peer.sack_needed;
asoc->peer.i = new->peer.i;
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
......@@ -887,26 +887,19 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
}
/* Choose the transport for sending a shutdown packet.
/* Update the retran path for sending a retransmitted packet.
* Round-robin through the active transports, else round-robin
* through the inactive transports as this is the next best thing
* we can try.
*/
struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
void sctp_assoc_update_retran_path(sctp_association_t *asoc)
{
struct sctp_transport *t, *next;
struct list_head *head = &asoc->peer.transport_addr_list;
struct list_head *pos;
/* If this is the first time SHUTDOWN is sent, use the active
* path.
*/
if (!asoc->shutdown_last_sent_to)
return asoc->peer.active_path;
/* Otherwise, find the next transport in a round-robin fashion. */
t = asoc->shutdown_last_sent_to;
/* Find the next transport in a round-robin fashion. */
t = asoc->peer.retran_path;
pos = &t->transports;
next = NULL;
......@@ -935,13 +928,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
* other active transports. If so, use the next
* transport.
*/
if (t == asoc->shutdown_last_sent_to) {
if (t == asoc->peer.retran_path) {
t = next;
break;
}
}
return t;
asoc->peer.retran_path = t;
}
/* Choose the transport for sending a SHUTDOWN packet. */
struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
{
/* If this is the first time SHUTDOWN is sent, use the active path,
* else use the retran path. If the last SHUTDOWN was sent over the
* retran path, update the retran path and use it.
*/
if (!asoc->shutdown_last_sent_to)
return asoc->peer.active_path;
else {
if (asoc->shutdown_last_sent_to == asoc->peer.retran_path)
sctp_assoc_update_retran_path(asoc);
return asoc->peer.retran_path;
}
}
/* Update the association's pmtu and frag_point by going through all the
......@@ -990,9 +1000,9 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc->rwnd += len;
}
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) - %u\n",
__FUNCTION__, asoc, len, asoc->rwnd, asoc->rwnd_over,
asoc->a_rwnd);
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
"- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
asoc->rwnd_over, asoc->a_rwnd);
/* Send a window update SACK if the rwnd has increased by at least the
* minimum of the association's PMTU and half of the receive buffer.
......@@ -1014,7 +1024,6 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc->a_rwnd = asoc->rwnd;
asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0;
sctp_outq_tail(&asoc->outqueue, sack);
......
......@@ -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,
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));
/* Initialize the base structure. */
......@@ -105,10 +105,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
ep->base.malloced = 1;
/* Create an input queue. */
sctp_inqueue_init(&ep->base.inqueue);
sctp_inq_init(&ep->base.inqueue);
/* 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,
ep);
......@@ -198,7 +198,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
sctp_unhash_endpoint(ep);
/* Cleanup the inqueue. */
sctp_inqueue_free(&ep->base.inqueue);
sctp_inq_free(&ep->base.inqueue);
sctp_bind_addr_free(&ep->base.bind_addr);
......@@ -333,7 +333,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
struct sock *sk;
struct sctp_transport *transport;
sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue;
struct sctp_inq *inqueue;
sctp_subtype_t subtype;
sctp_state_t state;
int error = 0;
......@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
inqueue = &ep->base.inqueue;
sk = ep->base.sk;
while (NULL != (chunk = sctp_pop_inqueue(inqueue))) {
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
subtype.chunk = chunk->chunk_hdr->type;
/* We might have grown an association since last we
......@@ -369,6 +369,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
*/
if (asoc && sctp_chunk_is_data(chunk))
asoc->peer.last_data_from = chunk->transport;
else
SCTP_INC_STATS(SctpInCtrlChunks);
if (chunk->transport)
chunk->transport->last_time_heard = jiffies;
......
......@@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
if (val != cmp) {
/* CRC failure, dump it. */
SCTP_INC_STATS_BH(SctpChecksumErrors);
return -1;
}
return 0;
......@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb)
if (skb->pkt_type!=PACKET_HOST)
goto discard_it;
SCTP_INC_STATS_BH(SctpInSCTPPacks);
sh = (struct sctphdr *) skb->h.raw;
/* Pull up the IP and SCTP headers. */
......@@ -160,9 +163,11 @@ int sctp_rcv(struct sk_buff *skb)
*/
if (!asoc) {
ep = __sctp_rcv_lookup_endpoint(&dest);
if (sctp_rcv_ootb(skb))
if (sctp_rcv_ootb(skb)) {
SCTP_INC_STATS_BH(SctpOutOfBlues);
goto discard_release;
}
}
/* Retrieve the common input handling substructure. */
rcvr = asoc ? &asoc->base : &ep->base;
......@@ -248,7 +253,7 @@ int sctp_rcv(struct sk_buff *skb)
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
sctp_chunk_t *chunk;
sctp_inqueue_t *inqueue;
struct sctp_inq *inqueue;
/* One day chunk will live inside the skb, but for
* now this works.
......@@ -256,7 +261,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
chunk = (sctp_chunk_t *) skb;
inqueue = &chunk->rcvr->inqueue;
sctp_push_inqueue(inqueue, chunk);
sctp_inq_push(inqueue, chunk);
return 0;
}
......
......@@ -47,8 +47,8 @@
#include <net/sctp/sm.h>
#include <linux/interrupt.h>
/* Initialize an SCTP_inqueue. */
void sctp_inqueue_init(sctp_inqueue_t *queue)
/* Initialize an SCTP inqueue. */
void sctp_inq_init(struct sctp_inq *queue)
{
skb_queue_head_init(&queue->in);
queue->in_progress = NULL;
......@@ -59,21 +59,21 @@ void sctp_inqueue_init(sctp_inqueue_t *queue)
queue->malloced = 0;
}
/* Create an initialized SCTP_inqueue. */
sctp_inqueue_t *sctp_inqueue_new(void)
/* Create an initialized sctp_inq. */
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) {
sctp_inqueue_init(retval);
sctp_inq_init(retval);
retval->malloced = 1;
}
return retval;
}
/* Release the memory associated with an SCTP inqueue. */
void sctp_inqueue_free(sctp_inqueue_t *queue)
void sctp_inq_free(struct sctp_inq *queue)
{
sctp_chunk_t *chunk;
......@@ -96,7 +96,7 @@ void sctp_inqueue_free(sctp_inqueue_t *queue)
/* Put a new packet in an SCTP inqueue.
* We assume that packet->sctp_hdr is set and in host byte order.
*/
void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet)
{
/* Directly call the packet handling routine. */
......@@ -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
* 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_chunkhdr_t *ch = NULL;
......@@ -172,7 +172,7 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
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,
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)),
ntohs(chunk->chunk_hdr->length), chunk->skb->len);
......@@ -182,12 +182,12 @@ sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
/* Set a top-half handler.
*
* Originally, we the top-half handler was scheduled as a BH. We now
* call the handler directly in sctp_push_inqueue() at a time that
* call the handler directly in sctp_inq_push() at a time that
* we know we are lock safe.
* The intent is that this routine will pull stuff out of the
* inqueue and process it.
*/
void sctp_inqueue_set_th_handler(sctp_inqueue_t *q,
void sctp_inq_set_th_handler(struct sctp_inq *q,
void (*callback)(void *), void *arg)
{
INIT_WORK(&q->immediate, callback, arg);
......
......@@ -132,6 +132,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
__FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
NIP6(fl.fl6_dst));
SCTP_INC_STATS(SctpOutSCTPPacks);
return ip6_xmit(sk, skb, &fl, np->opt);
}
......@@ -444,7 +446,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len)
}
/* 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)
{
struct sockaddr_in6 *sin6, *sin6from;
......
......@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst = transport->dst;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if (!dst || (dst->obsolete > 1)) {
dst_release(dst);
sctp_transport_route(transport, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc);
}
......
......@@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
: "Illegal Chunk");
skb_queue_tail(&q->out, (struct sk_buff *) chunk);
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
SCTP_INC_STATS(SctpOutUnorderChunks);
else
SCTP_INC_STATS(SctpOutOrderChunks);
q->empty = 0;
break;
};
} else
} else {
skb_queue_tail(&q->control, (struct sk_buff *) chunk);
SCTP_INC_STATS(SctpOutCtrlChunks);
}
if (error < 0)
return error;
......@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
switch(reason) {
case SCTP_RETRANSMIT_T3_RTX:
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
/* Update the retran path if the T3-rtx timer has expired for
* the current retran path.
*/
if (transport == transport->asoc->peer.retran_path)
sctp_assoc_update_retran_path(transport->asoc);
break;
case SCTP_RETRANSMIT_FAST_RTX:
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
......
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net>
*
* Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Sridhar Samudrala <sri@us.ibm.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
#include <linux/types.h>
#include <linux/seq_file.h>
#include <net/sctp/sctp.h>
static char *sctp_snmp_list[] = {
#define SCTP_SNMP_ENTRY(x) #x
SCTP_SNMP_ENTRY(SctpCurrEstab),
SCTP_SNMP_ENTRY(SctpActiveEstabs),
SCTP_SNMP_ENTRY(SctpPassiveEstabs),
SCTP_SNMP_ENTRY(SctpAborteds),
SCTP_SNMP_ENTRY(SctpShutdowns),
SCTP_SNMP_ENTRY(SctpOutOfBlues),
SCTP_SNMP_ENTRY(SctpChecksumErrors),
SCTP_SNMP_ENTRY(SctpOutCtrlChunks),
SCTP_SNMP_ENTRY(SctpOutOrderChunks),
SCTP_SNMP_ENTRY(SctpOutUnorderChunks),
SCTP_SNMP_ENTRY(SctpInCtrlChunks),
SCTP_SNMP_ENTRY(SctpInOrderChunks),
SCTP_SNMP_ENTRY(SctpInUnorderChunks),
SCTP_SNMP_ENTRY(SctpFragUsrMsgs),
SCTP_SNMP_ENTRY(SctpReasmUsrMsgs),
SCTP_SNMP_ENTRY(SctpOutSCTPPacks),
SCTP_SNMP_ENTRY(SctpInSCTPPacks),
#undef SCTP_SNMP_ENTRY
};
/* Return the current value of a particular entry in the mib by adding its
* per cpu counters.
*/
static unsigned long
fold_field(void *mib[], int nr)
{
unsigned long res = 0;
int i;
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_possible(i))
continue;
res +=
*((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) +
sizeof (unsigned long) * nr));
res +=
*((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) +
sizeof (unsigned long) * nr));
}
return res;
}
/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
{
int i;
for (i = 0; i < sizeof(sctp_snmp_list) / sizeof(char *); i++)
seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i],
fold_field((void **)sctp_statistics, i));
return 0;
}
/* Initialize the seq file operations for 'snmp' object. */
static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, sctp_snmp_seq_show, NULL);
}
static struct file_operations sctp_snmp_seq_fops = {
.open = sctp_snmp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* Set up the proc fs entry for 'snmp' object. */
int __init sctp_snmp_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("snmp", S_IRUGO, proc_net_sctp);
if (!p)
return -ENOMEM;
p->proc_fops = &sctp_snmp_seq_fops;
return 0;
}
/* Cleanup the proc fs entry for 'snmp' object. */
void sctp_snmp_proc_exit(void)
{
remove_proc_entry("snmp", proc_net_sctp);
}
......@@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific;
extern struct net_proto_family inet_family_ops;
extern int sctp_snmp_proc_init(void);
extern int sctp_snmp_proc_exit(void);
/* Return the address of the control sock. */
struct sock *sctp_get_ctl_sock(void)
{
......@@ -82,21 +85,32 @@ struct sock *sctp_get_ctl_sock(void)
}
/* Set up the proc fs entry for the SCTP protocol. */
__init void sctp_proc_init(void)
__init int sctp_proc_init(void)
{
int rc = 0;
if (!proc_net_sctp) {
struct proc_dir_entry *ent;
ent = proc_mkdir("net/sctp", 0);
if (ent) {
ent->owner = THIS_MODULE;
proc_net_sctp = ent;
} else
rc = -ENOMEM;
}
}
if (sctp_snmp_proc_init())
rc = -ENOMEM;
return rc;
}
/* Clean up the proc fs entry for the SCTP protocol. */
void sctp_proc_exit(void)
{
sctp_snmp_proc_exit();
if (proc_net_sctp) {
proc_net_sctp = NULL;
remove_proc_entry("net/sctp", 0);
......@@ -124,7 +138,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Add the address to the local list. */
addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
if (addr) {
INIT_LIST_HEAD(&addr->list);
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
......@@ -436,7 +449,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
if (AF_INET == laddr->a.sa.sa_family) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
dst = sctp_v4_get_dst(asoc, daddr, &laddr->a);
if (!ip_route_output_key(&rt, &fl)) {
dst = &rt->u.dst;
goto out_unlock;
......@@ -557,7 +569,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
}
/* 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)
{
struct sockaddr_in *sin, *sinfrom;
......@@ -628,6 +640,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
NIPQUAD(((struct rtable *)skb->dst)->rt_src),
NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
SCTP_INC_STATS(SctpOutSCTPPacks);
return ip_queue_xmit(skb, ipfragok);
}
......
......@@ -222,9 +222,7 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param);
sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types);
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
nodata:
if (addrs.v)
kfree(addrs.v);
......@@ -245,7 +243,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
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)
goto nomem_rawaddr;
......@@ -586,14 +585,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
sctp_gap_ack_block_t gab;
int length;
__u32 ctsn;
sctp_tsnmap_iter_t iter;
__u16 num_gabs;
__u16 num_dup_tsns = asoc->peer.next_dup_tsn;
const sctp_tsnmap_t *map = &asoc->peer.tsn_map;
struct sctp_tsnmap_iter iter;
__u16 num_gabs, num_dup_tsns;
struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
ctsn = sctp_tsnmap_get_ctsn(map);
SCTP_DEBUG_PRINTK("make_sack: sackCTSNAck sent is 0x%x.\n",
ctsn);
SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
/* Count the number of Gap Ack Blocks. */
sctp_tsnmap_iter_init(map, &iter);
......@@ -603,6 +600,8 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Do nothing. */
}
num_dup_tsns = sctp_tsnmap_num_dups(map);
/* Initialize the SACK header. */
sack.cum_tsn_ack = htonl(ctsn);
sack.a_rwnd = htonl(asoc->rwnd);
......@@ -611,7 +610,7 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
length = sizeof(sack)
+ sizeof(sctp_gap_ack_block_t) * num_gabs
+ sizeof(sctp_dup_tsn_t) * num_dup_tsns;
+ sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length);
......@@ -658,21 +657,18 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) {
gab.start = htons(gab.start);
gab.end = htons(gab.end);
sctp_addto_chunk(retval,
sizeof(sctp_gap_ack_block_t),
&gab);
sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab);
}
/* Register the duplicates. */
sctp_addto_chunk(retval,
sizeof(sctp_dup_tsn_t) * num_dup_tsns,
&asoc->peer.dup_tsns);
sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sctp_tsnmap_get_dups(map));
nodata:
return retval;
}
/* FIXME: Comments. */
/* Make a SHUTDOWN chunk. */
sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
{
sctp_chunk_t *retval;
......@@ -689,7 +685,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
retval->subh.shutdown_hdr =
sctp_addto_chunk(retval, sizeof(shut), &shut);
nodata:
return retval;
}
......@@ -1180,6 +1175,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
over = msg_len % max;
offset = 0;
if (whole && over)
SCTP_INC_STATS_USER(SctpFragUsrMsgs);
/* Create chunks for all the full sized DATA chunks. */
for (i=0, len=first_len; i < whole; i++) {
frag = SCTP_DATA_MIDDLE_FRAG;
......
......@@ -527,10 +527,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break;
case SCTP_CMD_REPORT_DUP:
if (asoc->peer.next_dup_tsn < SCTP_MAX_DUP_TSNS) {
asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] =
ntohl(command->obj.u32);
}
sctp_tsnmap_mark_dup(&asoc->peer.tsn_map,
ntohl(command->obj.u32));
break;
case SCTP_CMD_REPORT_BIGGAP:
......@@ -598,6 +596,13 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
t->rto_pending = 1;
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:
printk(KERN_WARNING "Impossible command: %u, %p\n",
command->verb, command->obj.ptr);
......@@ -737,7 +742,6 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc->a_rwnd = asoc->rwnd;
asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0;
error = sctp_outq_tail(&asoc->outqueue, sack);
......@@ -1014,7 +1018,7 @@ static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
sctp_association_t *asoc)
{
sctp_ulpevent_t *event;
struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc,
0,
......@@ -1041,7 +1045,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_subtype_t subtype,
sctp_chunk_t *chunk)
{
sctp_ulpevent_t *event;
struct sctp_ulpevent *event;
__u16 error = 0;
switch(event_type) {
......@@ -1061,12 +1065,11 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
break;
}
event = sctp_ulpevent_make_assoc_change(asoc,
0,
SCTP_COMM_LOST,
error, 0, 0,
GFP_ATOMIC);
/* Cancel any partial delivery in progress. */
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
error, 0, 0, GFP_ATOMIC);
if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event));
......
This diff is collapsed.
This diff is collapsed.
......@@ -45,9 +45,9 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
static void _sctp_tsnmap_update(sctp_tsnmap_t *map);
static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map);
static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
static void sctp_tsnmap_update(struct sctp_tsnmap *map);
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map);
static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
__u16 len, __u16 base,
int *started, __u16 *start,
int *ended, __u16 *end);
......@@ -55,11 +55,11 @@ static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
/* Create a new sctp_tsnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
{
sctp_tsnmap_t *retval;
struct sctp_tsnmap *retval;
retval = kmalloc(sizeof(sctp_tsnmap_t) +
retval = kmalloc(sizeof(struct sctp_tsnmap) +
sctp_tsnmap_storage_size(len),
priority);
if (!retval)
......@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
fail_map:
kfree(retval);
fail:
return NULL;
}
/* Initialize a block of memory as a tsnmap. */
sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn)
struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
__u32 initial_tsn)
{
map->tsn_map = map->raw_map;
map->overflow_map = map->tsn_map + len;
......@@ -94,6 +94,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
map->max_tsn_seen = map->cumulative_tsn_ack_point;
map->malloced = 0;
map->pending_data = 0;
map->num_dup_tsns = 0;
return map;
}
......@@ -104,7 +105,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn
* >0 if the TSN has been seen (duplicate)
* <0 if the TSN is invalid (too large to track)
*/
int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
{
__s32 gap;
int dup;
......@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
}
/* Is there a gap in the TSN map? */
int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
{
int has_gap;
......@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
}
/* Mark this TSN as seen. */
void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
{
__s32 gap;
......@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
/* Go fixup any internal TSN mapping variables including
* cumulative_tsn_ack_point.
*/
_sctp_tsnmap_update(map);
sctp_tsnmap_update(map);
}
void sctp_tsnmap_report_dup(struct sctp_tsnmap *map, __u32 tsn)
{
}
/* Retrieve the Cumulative TSN Ack Point. */
__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map)
__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
{
return map->cumulative_tsn_ack_point;
}
/* Retrieve the highest TSN we've seen. */
__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map)
__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
{
return map->max_tsn_seen;
}
/* Dispose of a tsnmap. */
void sctp_tsnmap_free(sctp_tsnmap_t *map)
void sctp_tsnmap_free(struct sctp_tsnmap *map)
{
if (map->malloced)
kfree(map);
}
/* Initialize a Gap Ack Block iterator from memory being provided. */
void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter)
void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter)
{
/* Only start looking one past the Cumulative TSN Ack Point. */
iter->start = map->cumulative_tsn_ack_point + 1;
}
/* Get the next Gap Ack Blocks. Returns 0 if there was not
* another block to get.
/* Get the next Gap Ack Blocks. Returns 0 if there was not another block
* to get.
*/
int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
__u16 *start, __u16 *end)
int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
{
int started, ended;
__u16 _start, _end, offset;
......@@ -216,12 +222,10 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
/* Search the first mapping array. */
if (iter->start - map->base_tsn < map->len) {
offset = iter->start - map->base_tsn;
_sctp_tsnmap_find_gap_ack(map->tsn_map,
offset,
map->len, 0,
&started, &_start,
&ended, &_end);
sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0,
&started, &_start, &ended, &_end);
}
/* Do we need to check the overflow map? */
......@@ -235,7 +239,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
offset = iter->start - map->base_tsn - map->len;
/* Search the overflow map. */
_sctp_tsnmap_find_gap_ack(map->overflow_map,
sctp_tsnmap_find_gap_ack(map->overflow_map,
offset,
map->len,
map->len,
......@@ -278,7 +282,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
/* This private helper function updates the tsnmap buffers and
* the Cumulative TSN Ack Point.
*/
static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
static void sctp_tsnmap_update(struct sctp_tsnmap *map)
{
__u32 ctsn;
......@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
} while (map->tsn_map[ctsn - map->base_tsn]);
map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
_sctp_tsnmap_update_pending_data(map);
sctp_tsnmap_update_pending_data(map);
}
static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
{
__u32 cum_tsn = map->cumulative_tsn_ack_point;
__u32 max_tsn = map->max_tsn_seen;
......@@ -345,14 +349,14 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
* The flags "started" and "ended" tell is if we found the beginning
* or (respectively) the end of a Gap Ack Block.
*/
static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
__u16 len, __u16 base,
int *started, __u16 *start,
int *ended, __u16 *end)
{
int i = off;
/* Let's look through the entire array, but break out
/* Look through the entire array, but break out
* early if we have found the end of the Gap Ack Block.
*/
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment