Commit 088e723f authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge

parents 9f58fa60 44310455
...@@ -68,7 +68,6 @@ typedef enum { ...@@ -68,7 +68,6 @@ typedef enum {
SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */ SCTP_CMD_INIT_RESTART, /* High level, do init timer work. */
SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */ SCTP_CMD_INIT_FAILED, /* High level, do init failure work. */
SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */ SCTP_CMD_REPORT_DUP, /* Report a duplicate TSN. */
SCTP_CMD_REPORT_BIGGAP, /* Narc on a TSN (it was too high). */
SCTP_CMD_STRIKE, /* Mark a strike against a transport. */ SCTP_CMD_STRIKE, /* Mark a strike against a transport. */
SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */ SCTP_CMD_TRANSMIT, /* Transmit the outqueue. */
SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */ SCTP_CMD_HB_TIMERS_START, /* Start the heartbeat timers. */
...@@ -86,7 +85,8 @@ typedef enum { ...@@ -86,7 +85,8 @@ 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_PART_DELIVER, /* Partial data delivery considerations. */
SCTP_CMD_RENEGE, /* Renege data on an association. */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;
...@@ -115,7 +115,7 @@ typedef union { ...@@ -115,7 +115,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 +163,7 @@ SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) ...@@ -163,7 +163,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)
......
...@@ -121,9 +121,10 @@ ...@@ -121,9 +121,10 @@
/* /*
* sctp_protocol.c * sctp_protocol.c
*/ */
extern sctp_protocol_t sctp_proto; extern struct sctp_protocol sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, extern int sctp_copy_local_addr_list(struct sctp_protocol *,
struct sctp_bind_addr *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int priority, int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t); extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
...@@ -214,6 +215,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); ...@@ -214,6 +215,7 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
#define SCTP_INC_STATS(field) SNMP_INC_STATS(sctp_statistics, field) #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_BH(field) SNMP_INC_STATS_BH(sctp_statistics, field)
#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(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. */ /* Determine if this is a valid kernel address. */
static inline int sctp_is_valid_kaddr(unsigned long addr) static inline int sctp_is_valid_kaddr(unsigned long addr)
...@@ -321,7 +323,8 @@ static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) ...@@ -321,7 +323,8 @@ static inline int sctp_ipv6_addr_type(const struct in6_addr *addr)
return ipv6_addr_type((struct in6_addr*) addr); return ipv6_addr_type((struct in6_addr*) addr);
} }
#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16)) /* Size of Supported Address Parameter for 'x' address types. */
#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
/* Note: These V6 macros are obsolescent. */ /* Note: These V6 macros are obsolescent. */
/* Use this macro to enclose code fragments which are V6-dependent. */ /* Use this macro to enclose code fragments which are V6-dependent. */
...@@ -347,25 +350,10 @@ static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) ...@@ -347,25 +350,10 @@ static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc)
return (sctp_assoc_t) asoc; return (sctp_assoc_t) asoc;
} }
/* Look up the association by its id. */ /* Look up the association by its id. */
static inline sctp_association_t *sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
{
sctp_association_t *asoc = NULL;
/* First, verify that this is a kernel address. */
if (sctp_is_valid_kaddr((unsigned long) id)) {
sctp_association_t *temp = (sctp_association_t *) id;
/* Verify that this _is_ an sctp_association_t
* data structure and if so, that the socket matches.
*/
if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
(temp->base.sk == sk))
asoc = temp;
}
return asoc;
}
/* A macro to walk a list of skbs. */ /* A macro to walk a list of skbs. */
#define sctp_skb_for_each(pos, head, tmp) \ #define sctp_skb_for_each(pos, head, tmp) \
...@@ -493,7 +481,7 @@ extern void sctp_put_port(struct sock *sk); ...@@ -493,7 +481,7 @@ extern void sctp_put_port(struct sock *sk);
/* Static inline functions. */ /* Static inline functions. */
/* Return the SCTP protocol structure. */ /* Return the SCTP protocol structure. */
static inline sctp_protocol_t *sctp_get_protocol(void) static inline struct sctp_protocol *sctp_get_protocol(void)
{ {
return &sctp_proto; return &sctp_proto;
} }
...@@ -522,21 +510,21 @@ static inline int ipver2af(__u8 ipver) ...@@ -522,21 +510,21 @@ static inline int ipver2af(__u8 ipver)
/* This is the hash function for the SCTP port hash table. */ /* This is the hash function for the SCTP port hash table. */
static inline int sctp_phashfn(__u16 lport) static inline int sctp_phashfn(__u16 lport)
{ {
sctp_protocol_t *sctp_proto = sctp_get_protocol(); struct sctp_protocol *sctp_proto = sctp_get_protocol();
return (lport & (sctp_proto->port_hashsize - 1)); return (lport & (sctp_proto->port_hashsize - 1));
} }
/* This is the hash function for the endpoint hash table. */ /* This is the hash function for the endpoint hash table. */
static inline int sctp_ep_hashfn(__u16 lport) static inline int sctp_ep_hashfn(__u16 lport)
{ {
sctp_protocol_t *sctp_proto = sctp_get_protocol(); struct sctp_protocol *sctp_proto = sctp_get_protocol();
return (lport & (sctp_proto->ep_hashsize - 1)); return (lport & (sctp_proto->ep_hashsize - 1));
} }
/* This is the hash function for the association hash table. */ /* This is the hash function for the association hash table. */
static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
{ {
sctp_protocol_t *sctp_proto = sctp_get_protocol(); struct sctp_protocol *sctp_proto = sctp_get_protocol();
int h = (lport << 16) + rport; int h = (lport << 16) + rport;
h ^= h>>8; h ^= h>>8;
return (h & (sctp_proto->assoc_hashsize - 1)); return (h & (sctp_proto->assoc_hashsize - 1));
...@@ -548,7 +536,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) ...@@ -548,7 +536,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
*/ */
static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
{ {
sctp_protocol_t *sctp_proto = sctp_get_protocol(); struct sctp_protocol *sctp_proto = sctp_get_protocol();
int h = (lport << 16) + rport; int h = (lport << 16) + rport;
h ^= vtag; h ^= vtag;
return (h & (sctp_proto->assoc_hashsize-1)); return (h & (sctp_proto->assoc_hashsize-1));
......
This diff is collapsed.
/* SCTP kernel reference Implementation Copyright (C) 1999-2001 /* SCTP kernel reference Implementation Copyright (C) 1999-2001
* Cisco, Motorola, Intel, and International Business Machines Corp. * Cisco, Motorola, Intel, and International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* These are the definitions needed for the tsnmap type. The tsnmap is used * These are the definitions needed for the tsnmap type. The tsnmap is used
* to track out of order TSNs received. * to track out of order TSNs received.
* *
* 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 the
* following email addresses: * email address(es):
* * lksctp developers <lksctp-developers@lists.sourceforge.net>
* Jon Grimm <jgrimm@us.ibm.com> *
* La Monte H.P. Yarroll <piggy@acm.org> * Or submit a bug report through the following website:
* Karl Knutson <karl@athena.chicago.il.us> * http://www.sf.net/projects/lksctp
* *
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
* 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.
*/ */
...@@ -38,8 +43,6 @@ ...@@ -38,8 +43,6 @@
#ifndef __sctp_tsnmap_h__ #ifndef __sctp_tsnmap_h__
#define __sctp_tsnmap_h__ #define __sctp_tsnmap_h__
/* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB) /* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
* Mapping An array of bits or bytes indicating which out of * Mapping An array of bits or bytes indicating which out of
* Array order TSN's have been received (relative to the * Array order TSN's have been received (relative to the
...@@ -48,9 +51,7 @@ ...@@ -48,9 +51,7 @@
* will be set to all zero. This structure may be * will be set to all zero. This structure may be
* in the form of a circular buffer or bit array. * 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. /* This array counts the number of chunks with each TSN.
* It points at one of the two buffers with which we will * It points at one of the two buffers with which we will
* ping-pong between. * ping-pong between.
...@@ -93,25 +94,30 @@ typedef struct sctp_tsnmap { ...@@ -93,25 +94,30 @@ typedef struct sctp_tsnmap {
/* This is the highest TSN we've marked. */ /* This is the highest TSN we've marked. */
__u32 max_tsn_seen; __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; __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; int malloced;
__u8 raw_map[0]; __u8 raw_map[0];
} sctp_tsnmap_t; };
typedef struct sctp_tsnmap_iter { struct sctp_tsnmap_iter {
__u32 start; __u32 start;
} sctp_tsnmap_iter_t; };
/* Create a new tsnmap. */ /* Create a new tsnmap. */
sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority);
int priority);
/* Dispose of a tsnmap. */ /* 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 /* This macro assists in creation of external storage for variable length
* internal buffers. We double allocate so the overflow map works. * internal buffers. We double allocate so the overflow map works.
...@@ -119,9 +125,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map); ...@@ -119,9 +125,8 @@ void sctp_tsnmap_free(sctp_tsnmap_t *map);
#define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2) #define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
/* Initialize a block of memory as a tsnmap. */ /* 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. /* Test the tracking state of this TSN.
* Returns: * Returns:
...@@ -129,31 +134,53 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn ...@@ -129,31 +134,53 @@ 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 has been seen (duplicate)
* <0 if the TSN is invalid (too large to track) * <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. */ /* 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. */ /* 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. */ /* 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: limit the storage of duplicate TSN
* information.
*/
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++] = htonl(tsn);
}
/* Renege a TSN that was seen. */
void sctp_tsnmap_renege(struct sctp_tsnmap *, __u32 tsn);
/* Is there a gap in the TSN map? */ /* 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. */ /* 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 /* Get the next gap ack blocks. We return 0 if there are no more
* gap ack blocks. * gap ack blocks.
*/ */
int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
__u16 *start, __u16 *end); struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
#endif /* __sctp_tsnmap_h__ */ #endif /* __sctp_tsnmap_h__ */
...@@ -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,22 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *); ...@@ -60,13 +61,22 @@ 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 propagation to the ULP. */ /* Add a new event for propagation 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. */ /* Renege previously received chunks. */
int sctp_ulpqueue_is_empty(struct sctp_ulpq *); void sctp_ulpq_renege(struct sctp_ulpq *, struct sctp_chunk *, int);
/* 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__ */ #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,
......
...@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ ...@@ -10,7 +10,7 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
inqueue.o outqueue.o ulpqueue.o command.o \ inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \ tsnmap.o bind_addr.o socket.o primitive.o \
output.o input.o hashdriver.o sla1.o \ output.o input.o hashdriver.o sla1.o \
debug.o ssnmap.o debug.o ssnmap.o proc.o
ifeq ($(CONFIG_SCTP_ADLER32), y) ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o sctp-y += adler32.o
......
...@@ -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);
...@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -260,7 +260,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
/* Set up the tsn tracking. */ /* Set up the tsn tracking. */
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0);
asoc->peer.next_dup_tsn = 0;
skb_queue_head_init(&asoc->addip_chunks); skb_queue_head_init(&asoc->addip_chunks);
...@@ -311,7 +310,7 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -311,7 +310,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);
...@@ -361,14 +360,30 @@ static void sctp_association_destroy(sctp_association_t *asoc) ...@@ -361,14 +360,30 @@ static void sctp_association_destroy(sctp_association_t *asoc)
} }
} }
/* Change the primary destination address for the peer. */
void sctp_assoc_set_primary(struct sctp_association *asoc,
struct sctp_transport *transport)
{
asoc->peer.primary_path = transport;
/* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &transport->ipaddr,
sizeof(union sctp_addr));
/* If the primary path is changing, assume that the
* user wants to use this new path.
*/
if (transport->active)
asoc->peer.active_path = transport;
}
/* Add a transport address to an association. */ /* Add a transport address to an association. */
struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc, struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
const union sctp_addr *addr, const union sctp_addr *addr,
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. */
...@@ -461,11 +476,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -461,11 +476,7 @@ struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *asoc,
/* If we do not yet have a primary path, set one. */ /* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) { if (NULL == asoc->peer.primary_path) {
asoc->peer.primary_path = peer; sctp_assoc_set_primary(asoc, peer);
/* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &peer->ipaddr,
sizeof(union sctp_addr));
asoc->peer.active_path = peer;
asoc->peer.retran_path = peer; asoc->peer.retran_path = peer;
} }
...@@ -505,7 +516,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -505,7 +516,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;
...@@ -604,7 +615,7 @@ void sctp_association_put(sctp_association_t *asoc) ...@@ -604,7 +615,7 @@ void sctp_association_put(sctp_association_t *asoc)
/* Allocate the next TSN, Transmission Sequence Number, for the given /* Allocate the next TSN, Transmission Sequence Number, for the given
* association. * association.
*/ */
__u32 __sctp_association_get_next_tsn(sctp_association_t *asoc) __u32 sctp_association_get_next_tsn(sctp_association_t *asoc)
{ {
/* From Section 1.6 Serial Number Arithmetic: /* From Section 1.6 Serial Number Arithmetic:
* Transmission Sequence Numbers wrap around when they reach * Transmission Sequence Numbers wrap around when they reach
...@@ -619,7 +630,7 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *asoc) ...@@ -619,7 +630,7 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *asoc)
} }
/* Allocate 'num' TSNs by incrementing the association's TSN by num. */ /* Allocate 'num' TSNs by incrementing the association's TSN by num. */
__u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num) __u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
{ {
__u32 retval = asoc->next_tsn; __u32 retval = asoc->next_tsn;
...@@ -776,7 +787,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -776,7 +787,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 +797,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -786,7 +797,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;
...@@ -795,6 +806,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -795,6 +806,8 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
*/ */
if (sctp_chunk_is_data(chunk)) if (sctp_chunk_is_data(chunk))
asoc->peer.last_data_from = chunk->transport; asoc->peer.last_data_from = chunk->transport;
else
SCTP_INC_STATS(SctpInCtrlChunks);
if (chunk->transport) if (chunk->transport)
chunk->transport->last_time_heard = jiffies; chunk->transport->last_time_heard = jiffies;
...@@ -819,7 +832,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -819,7 +832,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.
...@@ -848,7 +861,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) ...@@ -848,7 +861,6 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* Copy in new parameters of peer. */ /* Copy in new parameters of peer. */
asoc->c = new->c; asoc->c = new->c;
asoc->peer.rwnd = new->peer.rwnd; asoc->peer.rwnd = new->peer.rwnd;
asoc->peer.next_dup_tsn = new->peer.next_dup_tsn;
asoc->peer.sack_needed = new->peer.sack_needed; asoc->peer.sack_needed = new->peer.sack_needed;
asoc->peer.i = new->peer.i; asoc->peer.i = new->peer.i;
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
...@@ -887,26 +899,19 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) ...@@ -887,26 +899,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 * Round-robin through the active transports, else round-robin
* through the inactive transports as this is the next best thing * through the inactive transports as this is the next best thing
* we can try. * 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 sctp_transport *t, *next;
struct list_head *head = &asoc->peer.transport_addr_list; struct list_head *head = &asoc->peer.transport_addr_list;
struct list_head *pos; struct list_head *pos;
/* If this is the first time SHUTDOWN is sent, use the active /* Find the next transport in a round-robin fashion. */
* path. t = asoc->peer.retran_path;
*/
if (!asoc->shutdown_last_sent_to)
return asoc->peer.active_path;
/* Otherwise, find the next transport in a round-robin fashion. */
t = asoc->shutdown_last_sent_to;
pos = &t->transports; pos = &t->transports;
next = NULL; next = NULL;
...@@ -935,13 +940,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t * ...@@ -935,13 +940,30 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *
* other active transports. If so, use the next * other active transports. If so, use the next
* transport. * transport.
*/ */
if (t == asoc->shutdown_last_sent_to) { if (t == asoc->peer.retran_path) {
t = next; t = next;
break; 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 /* Update the association's pmtu and frag_point by going through all the
...@@ -990,13 +1012,13 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -990,13 +1012,13 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
asoc->rwnd += len; asoc->rwnd += len;
} }
SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) - %u\n", SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
__FUNCTION__, asoc, len, asoc->rwnd, asoc->rwnd_over, "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
asoc->a_rwnd); asoc->rwnd_over, asoc->a_rwnd);
/* 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) &&
...@@ -1004,17 +1026,16 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -1004,17 +1026,16 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
((asoc->rwnd - asoc->a_rwnd) >= ((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) { min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) {
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__,
__FUNCTION__, asoc, asoc->rwnd, asoc->a_rwnd); 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;
asoc->peer.sack_needed = 0; asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0;
sctp_outq_tail(&asoc->outqueue, sack); sctp_outq_tail(&asoc->outqueue, sack);
...@@ -1022,7 +1043,7 @@ void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) ...@@ -1022,7 +1043,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. */
......
...@@ -302,7 +302,7 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, ...@@ -302,7 +302,7 @@ int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
sctp_scope_t scope, int priority, int flags) sctp_scope_t scope, int priority, int flags)
{ {
sctp_protocol_t *proto = sctp_get_protocol(); struct sctp_protocol *proto = sctp_get_protocol();
int error = 0; int error = 0;
if (sctp_is_any(addr)) { if (sctp_is_any(addr)) {
......
...@@ -65,7 +65,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); ...@@ -65,7 +65,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep);
/* Create a sctp_endpoint_t with all that boring stuff initialized. /* Create a sctp_endpoint_t with all that boring stuff initialized.
* Returns NULL if there isn't enough memory. * Returns NULL if there isn't enough memory.
*/ */
sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto,
struct sock *sk, int priority) struct sock *sk, int priority)
{ {
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
...@@ -89,10 +89,11 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, ...@@ -89,10 +89,11 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
/* /*
* Initialize the base fields of the endpoint structure. * Initialize the base fields of the endpoint structure.
*/ */
sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep,
struct sctp_protocol *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 +106,10 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ...@@ -105,10 +106,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 +199,7 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep) ...@@ -198,7 +199,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 +334,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -333,7 +334,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 +346,7 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -345,7 +346,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
...@@ -369,6 +370,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -369,6 +370,8 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
*/ */
if (asoc && sctp_chunk_is_data(chunk)) if (asoc && sctp_chunk_is_data(chunk))
asoc->peer.last_data_from = chunk->transport; asoc->peer.last_data_from = chunk->transport;
else
SCTP_INC_STATS(SctpInCtrlChunks);
if (chunk->transport) if (chunk->transport)
chunk->transport->last_time_heard = jiffies; chunk->transport->last_time_heard = jiffies;
......
...@@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb) ...@@ -90,6 +90,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
if (val != cmp) { if (val != cmp) {
/* CRC failure, dump it. */ /* CRC failure, dump it. */
SCTP_INC_STATS_BH(SctpChecksumErrors);
return -1; return -1;
} }
return 0; return 0;
...@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -115,6 +116,8 @@ int sctp_rcv(struct sk_buff *skb)
if (skb->pkt_type!=PACKET_HOST) if (skb->pkt_type!=PACKET_HOST)
goto discard_it; goto discard_it;
SCTP_INC_STATS_BH(SctpInSCTPPacks);
sh = (struct sctphdr *) skb->h.raw; sh = (struct sctphdr *) skb->h.raw;
/* Pull up the IP and SCTP headers. */ /* Pull up the IP and SCTP headers. */
...@@ -160,8 +163,10 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -160,8 +163,10 @@ int sctp_rcv(struct sk_buff *skb)
*/ */
if (!asoc) { if (!asoc) {
ep = __sctp_rcv_lookup_endpoint(&dest); ep = __sctp_rcv_lookup_endpoint(&dest);
if (sctp_rcv_ootb(skb)) if (sctp_rcv_ootb(skb)) {
SCTP_INC_STATS_BH(SctpOutOfBlues);
goto discard_release; goto discard_release;
}
} }
/* Retrieve the common input handling substructure. */ /* Retrieve the common input handling substructure. */
...@@ -248,7 +253,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -248,7 +253,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 +261,7 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -256,7 +261,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);
......
...@@ -131,6 +131,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb, ...@@ -131,6 +131,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb,
__FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
NIP6(fl.fl6_dst)); NIP6(fl.fl6_dst));
SCTP_INC_STATS(SctpOutSCTPPacks);
return ip6_xmit(sk, skb, &fl, np->opt); return ip6_xmit(sk, skb, &fl, np->opt);
} }
...@@ -443,7 +445,7 @@ static void sctp_inet6_msgname(char *msgname, int *addr_len) ...@@ -443,7 +445,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;
...@@ -562,6 +564,20 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -562,6 +564,20 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return af->available(addr); return af->available(addr);
} }
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Note: In the future, we may want to look at sock options
* to determine whether a PF_INET6 socket really wants to have IPV4
* addresses.
* Returns number of addresses supported.
*/
static int sctp_inet6_supported_addrs(const struct sctp_opt *opt,
__u16 *types)
{
types[0] = SCTP_PARAM_IPV4_ADDRESS;
types[1] = SCTP_PARAM_IPV6_ADDRESS;
return 2;
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
.release = inet6_release, .release = inet6_release,
...@@ -624,6 +640,7 @@ static struct sctp_pf sctp_pf_inet6_specific = { ...@@ -624,6 +640,7 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.af_supported = sctp_inet6_af_supported, .af_supported = sctp_inet6_af_supported,
.cmp_addr = sctp_inet6_cmp_addr, .cmp_addr = sctp_inet6_cmp_addr,
.bind_verify = sctp_inet6_bind_verify, .bind_verify = sctp_inet6_bind_verify,
.supported_addrs = sctp_inet6_supported_addrs,
.af = &sctp_ipv6_specific, .af = &sctp_ipv6_specific,
}; };
......
...@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -419,6 +419,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst = transport->dst; dst = transport->dst;
/* The 'obsolete' field of dst is set to 2 when a dst is freed. */ /* The 'obsolete' field of dst is set to 2 when a dst is freed. */
if (!dst || (dst->obsolete > 1)) { if (!dst || (dst->obsolete > 1)) {
dst_release(dst);
sctp_transport_route(transport, NULL, sctp_sk(sk)); sctp_transport_route(transport, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
} }
......
...@@ -125,7 +125,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -125,7 +125,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
} }
/* Throw away any chunks in the retransmit queue. */ /* Throw away any chunks in the retransmit queue. */
list_for_each_safe(lchunk, temp, &q->retransmit) { list_for_each_safe(lchunk, temp, &q->retransmit) {
list_del(lchunk); list_del(lchunk);
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
...@@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) ...@@ -193,11 +193,17 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
: "Illegal Chunk"); : "Illegal Chunk");
skb_queue_tail(&q->out, (struct sk_buff *) 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; q->empty = 0;
break; break;
}; };
} else } else {
skb_queue_tail(&q->control, (struct sk_buff *) chunk); skb_queue_tail(&q->control, (struct sk_buff *) chunk);
SCTP_INC_STATS(SctpOutCtrlChunks);
}
if (error < 0) if (error < 0)
return error; return error;
...@@ -235,7 +241,7 @@ void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) ...@@ -235,7 +241,7 @@ void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q)
} }
/* Mark all the eligible packets on a transport for retransmission. */ /* Mark all the eligible packets on a transport for retransmission. */
void sctp_retransmit_mark(struct sctp_outq *q, void sctp_retransmit_mark(struct sctp_outq *q,
struct sctp_transport *transport, struct sctp_transport *transport,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
...@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -315,6 +321,11 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
switch(reason) { switch(reason) {
case SCTP_RETRANSMIT_T3_RTX: case SCTP_RETRANSMIT_T3_RTX:
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_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; break;
case SCTP_RETRANSMIT_FAST_RTX: case SCTP_RETRANSMIT_FAST_RTX:
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
...@@ -542,7 +553,7 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet, ...@@ -542,7 +553,7 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet,
} }
/* Get a TSN block of nfrags TSNs. */ /* Get a TSN block of nfrags TSNs. */
tsn = __sctp_association_get_tsn_block(asoc, nfrags); tsn = sctp_association_get_tsn_block(asoc, nfrags);
pos = skb_peek(&q->out); pos = skb_peek(&q->out);
/* Transmit the first fragment. */ /* Transmit the first fragment. */
...@@ -584,7 +595,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, ...@@ -584,7 +595,7 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
old_flags = chunk->chunk_hdr->flags; old_flags = chunk->chunk_hdr->flags;
if (old_flags & SCTP_DATA_FIRST_FRAG) if (old_flags & SCTP_DATA_FIRST_FRAG)
flags = SCTP_DATA_FIRST_FRAG; flags = SCTP_DATA_FIRST_FRAG;
else else
flags = SCTP_DATA_MIDDLE_FRAG; flags = SCTP_DATA_MIDDLE_FRAG;
/* Make the first fragment. */ /* Make the first fragment. */
...@@ -992,7 +1003,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -992,7 +1003,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
*/ */
while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) { while ((ltransport = sctp_list_dequeue(&transport_list)) != NULL ) {
struct sctp_transport *t = list_entry(ltransport, struct sctp_transport *t = list_entry(ltransport,
struct sctp_transport, struct sctp_transport,
send_ready); send_ready);
if (t != transport) if (t != transport)
transport = t; transport = t;
...@@ -1114,7 +1125,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1114,7 +1125,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
* This is a MASSIVE candidate for optimization. * This is a MASSIVE candidate for optimization.
*/ */
list_for_each(pos, transport_list) { list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport, transport = list_entry(pos, struct sctp_transport,
transports); transports);
sctp_check_transmitted(q, &transport->transmitted, sctp_check_transmitted(q, &transport->transmitted,
transport, sack, highest_new_tsn); transport, sack, highest_new_tsn);
...@@ -1168,7 +1179,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1168,7 +1179,7 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
goto finish; goto finish;
list_for_each(pos, transport_list) { list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport, transport = list_entry(pos, struct sctp_transport,
transports); transports);
q->empty = q->empty && list_empty(&transport->transmitted); q->empty = q->empty && list_empty(&transport->transmitted);
if (!q->empty) if (!q->empty)
......
/* 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);
}
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
#include <net/inet_common.h> #include <net/inet_common.h>
/* Global data structures. */ /* Global data structures. */
sctp_protocol_t sctp_proto; struct sctp_protocol sctp_proto;
struct proc_dir_entry *proc_net_sctp; struct proc_dir_entry *proc_net_sctp;
DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics); DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
...@@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific; ...@@ -75,6 +75,9 @@ static struct sctp_af *sctp_af_v6_specific;
extern struct net_proto_family inet_family_ops; 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. */ /* Return the address of the control sock. */
struct sock *sctp_get_ctl_sock(void) struct sock *sctp_get_ctl_sock(void)
{ {
...@@ -82,21 +85,32 @@ 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. */ /* 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) { if (!proc_net_sctp) {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
ent = proc_mkdir("net/sctp", 0); ent = proc_mkdir("net/sctp", 0);
if (ent) { if (ent) {
ent->owner = THIS_MODULE; ent->owner = THIS_MODULE;
proc_net_sctp = ent; 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. */ /* Clean up the proc fs entry for the SCTP protocol. */
void sctp_proc_exit(void) void sctp_proc_exit(void)
{ {
sctp_snmp_proc_exit();
if (proc_net_sctp) { if (proc_net_sctp) {
proc_net_sctp = NULL; proc_net_sctp = NULL;
remove_proc_entry("net/sctp", 0); remove_proc_entry("net/sctp", 0);
...@@ -124,7 +138,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -124,7 +138,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;
...@@ -139,7 +152,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -139,7 +152,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Extract our IP addresses from the system and stash them in the /* Extract our IP addresses from the system and stash them in the
* protocol structure. * protocol structure.
*/ */
static void __sctp_get_local_addr_list(sctp_protocol_t *proto) static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
{ {
struct net_device *dev; struct net_device *dev;
struct list_head *pos; struct list_head *pos;
...@@ -155,7 +168,7 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto) ...@@ -155,7 +168,7 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
} }
static void sctp_get_local_addr_list(sctp_protocol_t *proto) static void sctp_get_local_addr_list(struct sctp_protocol *proto)
{ {
long flags __attribute__ ((unused)); long flags __attribute__ ((unused));
...@@ -165,7 +178,7 @@ static void sctp_get_local_addr_list(sctp_protocol_t *proto) ...@@ -165,7 +178,7 @@ static void sctp_get_local_addr_list(sctp_protocol_t *proto)
} }
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void __sctp_free_local_addr_list(sctp_protocol_t *proto) static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
...@@ -178,7 +191,7 @@ static void __sctp_free_local_addr_list(sctp_protocol_t *proto) ...@@ -178,7 +191,7 @@ static void __sctp_free_local_addr_list(sctp_protocol_t *proto)
} }
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void sctp_free_local_addr_list(sctp_protocol_t *proto) static void sctp_free_local_addr_list(struct sctp_protocol *proto)
{ {
long flags __attribute__ ((unused)); long flags __attribute__ ((unused));
...@@ -188,8 +201,9 @@ static void sctp_free_local_addr_list(sctp_protocol_t *proto) ...@@ -188,8 +201,9 @@ static void sctp_free_local_addr_list(sctp_protocol_t *proto)
} }
/* Copy the local addresses which are valid for 'scope' into 'bp'. */ /* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, int sctp_copy_local_addr_list(struct sctp_protocol *proto,
sctp_scope_t scope, int priority, int copy_flags) struct sctp_bind_addr *bp, sctp_scope_t scope,
int priority, int copy_flags)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
int error = 0; int error = 0;
...@@ -318,7 +332,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) ...@@ -318,7 +332,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr)
static int sctp_v4_available(const union sctp_addr *addr) static int sctp_v4_available(const union sctp_addr *addr)
{ {
int ret = inet_addr_type(addr->v4.sin_addr.s_addr); int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
/* FIXME: ip_nonlocal_bind sysctl support. */ /* FIXME: ip_nonlocal_bind sysctl support. */
if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL) if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL)
...@@ -367,7 +381,7 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) ...@@ -367,7 +381,7 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
/* Returns a valid dst cache entry for the given source and destination ip /* Returns a valid dst cache entry for the given source and destination ip
* addresses. If an association is passed, trys to get a dst entry with a * addresses. If an association is passed, trys to get a dst entry with a
* source adddress that matches an address in the bind address list. * source adddress that matches an address in the bind address list.
*/ */
struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc, struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
union sctp_addr *daddr, union sctp_addr *daddr,
...@@ -436,7 +450,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc, ...@@ -436,7 +450,6 @@ struct dst_entry *sctp_v4_get_dst(sctp_association_t *asoc,
if (AF_INET == laddr->a.sa.sa_family) { if (AF_INET == laddr->a.sa.sa_family) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr; 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)) { if (!ip_route_output_key(&rt, &fl)) {
dst = &rt->u.dst; dst = &rt->u.dst;
goto out_unlock; goto out_unlock;
...@@ -557,7 +570,7 @@ static void sctp_inet_msgname(char *msgname, int *addr_len) ...@@ -557,7 +570,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;
...@@ -618,6 +631,16 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) ...@@ -618,6 +631,16 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
return sctp_v4_available(addr); return sctp_v4_available(addr);
} }
/* Fill in Supported Address Type information for INIT and INIT-ACK
* chunks. Returns number of addresses supported.
*/
static int sctp_inet_supported_addrs(const struct sctp_opt *opt,
__u16 *types)
{
types[0] = SCTP_PARAM_IPV4_ADDRESS;
return 1;
}
/* Wrapper routine that calls the ip transmit routine. */ /* Wrapper routine that calls the ip transmit routine. */
static inline int sctp_v4_xmit(struct sk_buff *skb, static inline int sctp_v4_xmit(struct sk_buff *skb,
struct sctp_transport *transport, int ipfragok) struct sctp_transport *transport, int ipfragok)
...@@ -628,6 +651,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, ...@@ -628,6 +651,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
NIPQUAD(((struct rtable *)skb->dst)->rt_src), NIPQUAD(((struct rtable *)skb->dst)->rt_src),
NIPQUAD(((struct rtable *)skb->dst)->rt_dst)); NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
SCTP_INC_STATS(SctpOutSCTPPacks);
return ip_queue_xmit(skb, ipfragok); return ip_queue_xmit(skb, ipfragok);
} }
...@@ -639,6 +663,7 @@ static struct sctp_pf sctp_pf_inet = { ...@@ -639,6 +663,7 @@ static struct sctp_pf sctp_pf_inet = {
.af_supported = sctp_inet_af_supported, .af_supported = sctp_inet_af_supported,
.cmp_addr = sctp_inet_cmp_addr, .cmp_addr = sctp_inet_cmp_addr,
.bind_verify = sctp_inet_bind_verify, .bind_verify = sctp_inet_bind_verify,
.supported_addrs = sctp_inet_supported_addrs,
.af = &sctp_ipv4_specific, .af = &sctp_ipv4_specific,
}; };
...@@ -743,7 +768,7 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) ...@@ -743,7 +768,7 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
static int __init init_sctp_mibs(void) static int __init init_sctp_mibs(void)
{ {
int i; int i;
sctp_statistics[0] = kmalloc_percpu(sizeof (struct sctp_mib), sctp_statistics[0] = kmalloc_percpu(sizeof (struct sctp_mib),
GFP_KERNEL); GFP_KERNEL);
if (!sctp_statistics[0]) if (!sctp_statistics[0])
...@@ -765,7 +790,7 @@ static int __init init_sctp_mibs(void) ...@@ -765,7 +790,7 @@ static int __init init_sctp_mibs(void)
} }
} }
return 0; return 0;
} }
static void cleanup_sctp_mibs(void) static void cleanup_sctp_mibs(void)
...@@ -789,9 +814,9 @@ __init int sctp_init(void) ...@@ -789,9 +814,9 @@ __init int sctp_init(void)
/* Allocate and initialise sctp mibs. */ /* Allocate and initialise sctp mibs. */
status = init_sctp_mibs(); status = init_sctp_mibs();
if (status) if (status)
goto err_init_mibs; goto err_init_mibs;
/* Initialize proc fs directory. */ /* Initialize proc fs directory. */
sctp_proc_init(); sctp_proc_init();
...@@ -818,7 +843,7 @@ __init int sctp_init(void) ...@@ -818,7 +843,7 @@ __init int sctp_init(void)
/* Valid.Cookie.Life - 60 seconds */ /* Valid.Cookie.Life - 60 seconds */
sctp_proto.valid_cookie_life = 60 * HZ; sctp_proto.valid_cookie_life = 60 * HZ;
/* Whether Cookie Preservative is enabled(1) or not(0) */ /* Whether Cookie Preservative is enabled(1) or not(0) */
sctp_proto.cookie_preserve_enable = 1; sctp_proto.cookie_preserve_enable = 1;
/* Max.Burst - 4 */ /* Max.Burst - 4 */
...@@ -907,7 +932,7 @@ __init int sctp_init(void) ...@@ -907,7 +932,7 @@ __init int sctp_init(void)
INIT_LIST_HEAD(&sctp_proto.local_addr_list); INIT_LIST_HEAD(&sctp_proto.local_addr_list);
sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED;
/* Register notifier for inet address additions/deletions. */ /* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier); register_inetaddr_notifier(&sctp_inetaddr_notifier);
sctp_get_local_addr_list(&sctp_proto); sctp_get_local_addr_list(&sctp_proto);
...@@ -929,7 +954,7 @@ __init int sctp_init(void) ...@@ -929,7 +954,7 @@ __init int sctp_init(void)
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
cleanup_sctp_mibs(); cleanup_sctp_mibs();
err_init_mibs: err_init_mibs:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_protosw); inet_unregister_protosw(&sctp_protosw);
return status; return status;
......
...@@ -66,29 +66,6 @@ ...@@ -66,29 +66,6 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* RFC 2960 3.3.2 Initiation (INIT) (1)
*
* Note 4: This parameter, when present, specifies all the
* address types the sending endpoint can support. The absence
* of this parameter indicates that the sending endpoint can
* support any address type.
*/
static const sctp_supported_addrs_param_t sat_param = {
{
SCTP_PARAM_SUPPORTED_ADDRESS_TYPES,
__constant_htons(SCTP_SAT_LEN),
}
};
/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above
* structure is split and the address types array is initialized using a
* fixed length array.
*/
static const __u16 sat_addr_types[2] = {
SCTP_PARAM_IPV4_ADDRESS,
SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,)
};
/* RFC 2960 3.3.2 Initiation (INIT) (1) /* RFC 2960 3.3.2 Initiation (INIT) (1)
* *
* Note 2: The ECN capable field is reserved for future use of * Note 2: The ECN capable field is reserved for future use of
...@@ -174,7 +151,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -174,7 +151,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
union sctp_params addrs; union sctp_params addrs;
size_t chunksize; size_t chunksize;
sctp_chunk_t *retval = NULL; sctp_chunk_t *retval = NULL;
int addrs_len = 0; int num_types, addrs_len = 0;
struct sctp_opt *sp;
sctp_supported_addrs_param_t sat;
__u16 types[2];
/* RFC 2960 3.3.2 Initiation (INIT) (1) /* RFC 2960 3.3.2 Initiation (INIT) (1)
* *
...@@ -195,7 +175,11 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -195,7 +175,11 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); init.num_inbound_streams = htons(asoc->c.sinit_max_instreams);
init.initial_tsn = htonl(asoc->c.initial_tsn); init.initial_tsn = htonl(asoc->c.initial_tsn);
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; /* How many address types are needed? */
sp = sctp_sk(asoc->base.sk);
num_types = sp->pf->supported_addrs(sp, types);
chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types);
chunksize += sizeof(ecap_param); chunksize += sizeof(ecap_param);
chunksize += vparam_len; chunksize += vparam_len;
...@@ -220,11 +204,19 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, ...@@ -220,11 +204,19 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
retval->param_hdr.v = retval->param_hdr.v =
sctp_addto_chunk(retval, addrs_len, addrs.v); sctp_addto_chunk(retval, addrs_len, addrs.v);
sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param); /* RFC 2960 3.3.2 Initiation (INIT) (1)
sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types); *
* Note 4: This parameter, when present, specifies all the
* address types the sending endpoint can support. The absence
* of this parameter indicates that the sending endpoint can
* support any address type.
*/
sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES;
sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types));
sctp_addto_chunk(retval, sizeof(sat), &sat);
sctp_addto_chunk(retval, num_types * sizeof(__u16), &types);
sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
nodata: nodata:
if (addrs.v) if (addrs.v)
kfree(addrs.v); kfree(addrs.v);
...@@ -245,7 +237,8 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, ...@@ -245,7 +237,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;
...@@ -586,14 +579,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -586,14 +579,12 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
sctp_gap_ack_block_t gab; sctp_gap_ack_block_t gab;
int length; int length;
__u32 ctsn; __u32 ctsn;
sctp_tsnmap_iter_t iter; struct sctp_tsnmap_iter iter;
__u16 num_gabs; __u16 num_gabs, num_dup_tsns;
__u16 num_dup_tsns = asoc->peer.next_dup_tsn; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
const sctp_tsnmap_t *map = &asoc->peer.tsn_map;
ctsn = sctp_tsnmap_get_ctsn(map); ctsn = sctp_tsnmap_get_ctsn(map);
SCTP_DEBUG_PRINTK("make_sack: sackCTSNAck sent is 0x%x.\n", SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
ctsn);
/* Count the number of Gap Ack Blocks. */ /* Count the number of Gap Ack Blocks. */
sctp_tsnmap_iter_init(map, &iter); sctp_tsnmap_iter_init(map, &iter);
...@@ -603,15 +594,17 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -603,15 +594,17 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
/* Do nothing. */ /* Do nothing. */
} }
num_dup_tsns = sctp_tsnmap_num_dups(map);
/* Initialize the SACK header. */ /* Initialize the SACK header. */
sack.cum_tsn_ack = htonl(ctsn); sack.cum_tsn_ack = htonl(ctsn);
sack.a_rwnd = htonl(asoc->rwnd); sack.a_rwnd = htonl(asoc->rwnd);
sack.num_gap_ack_blocks = htons(num_gabs); sack.num_gap_ack_blocks = htons(num_gabs);
sack.num_dup_tsns = htons(num_dup_tsns); sack.num_dup_tsns = htons(num_dup_tsns);
length = sizeof(sack) length = sizeof(sack)
+ sizeof(sctp_gap_ack_block_t) * num_gabs + sizeof(sctp_gap_ack_block_t) * num_gabs
+ sizeof(sctp_dup_tsn_t) * num_dup_tsns; + sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */ /* Create the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length);
...@@ -658,21 +651,18 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) ...@@ -658,21 +651,18 @@ sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) {
gab.start = htons(gab.start); gab.start = htons(gab.start);
gab.end = htons(gab.end); gab.end = htons(gab.end);
sctp_addto_chunk(retval, sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab);
sizeof(sctp_gap_ack_block_t),
&gab);
} }
/* Register the duplicates. */ /* Register the duplicates. */
sctp_addto_chunk(retval, sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
sizeof(sctp_dup_tsn_t) * num_dup_tsns, sctp_tsnmap_get_dups(map));
&asoc->peer.dup_tsns);
nodata: nodata:
return retval; return retval;
} }
/* FIXME: Comments. */ /* Make a SHUTDOWN chunk. */
sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
{ {
sctp_chunk_t *retval; sctp_chunk_t *retval;
...@@ -689,7 +679,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) ...@@ -689,7 +679,6 @@ sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
retval->subh.shutdown_hdr = retval->subh.shutdown_hdr =
sctp_addto_chunk(retval, sizeof(shut), &shut); sctp_addto_chunk(retval, sizeof(shut), &shut);
nodata: nodata:
return retval; return retval;
} }
...@@ -1180,6 +1169,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc, ...@@ -1180,6 +1169,9 @@ int sctp_datachunks_from_user(sctp_association_t *asoc,
over = msg_len % max; over = msg_len % max;
offset = 0; offset = 0;
if (whole && over)
SCTP_INC_STATS_USER(SctpFragUsrMsgs);
/* Create chunks for all the full sized DATA chunks. */ /* Create chunks for all the full sized DATA chunks. */
for (i=0, len=first_len; i < whole; i++) { for (i=0, len=first_len; i < whole; i++) {
frag = SCTP_DATA_MIDDLE_FRAG; frag = SCTP_DATA_MIDDLE_FRAG;
...@@ -1284,7 +1276,7 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) ...@@ -1284,7 +1276,7 @@ void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
* assign a TSN. * assign a TSN.
*/ */
chunk->subh.data_hdr->tsn = chunk->subh.data_hdr->tsn =
htonl(__sctp_association_get_next_tsn(chunk->asoc)); htonl(sctp_association_get_next_tsn(chunk->asoc));
chunk->has_tsn = 1; chunk->has_tsn = 1;
} }
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <net/sctp/structs.h> #include <net/sctp/structs.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
extern sctp_protocol_t sctp_proto; extern struct sctp_protocol sctp_proto;
static ctl_table sctp_table[] = { static ctl_table sctp_table[] = {
{ {
......
...@@ -83,7 +83,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -83,7 +83,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr, const union sctp_addr *addr,
int priority) int priority)
{ {
sctp_protocol_t *proto = sctp_get_protocol(); struct sctp_protocol *proto = sctp_get_protocol();
/* Copy in the address. */ /* Copy in the address. */
peer->ipaddr = *addr; peer->ipaddr = *addr;
...@@ -262,7 +262,7 @@ void sctp_transport_put(struct sctp_transport *transport) ...@@ -262,7 +262,7 @@ void sctp_transport_put(struct sctp_transport *transport)
/* Update transport's RTO based on the newly calculated RTT. */ /* Update transport's RTO based on the newly calculated RTT. */
void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
{ {
sctp_protocol_t *proto = sctp_get_protocol(); struct sctp_protocol *proto = sctp_get_protocol();
/* Check for valid transport. */ /* Check for valid transport. */
SCTP_ASSERT(tp, "NULL transport", return); SCTP_ASSERT(tp, "NULL transport", return);
......
...@@ -3,40 +3,40 @@ ...@@ -3,40 +3,40 @@
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* These functions manipulate sctp tsn mapping array. * These functions manipulate sctp tsn mapping array.
* *
* 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:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
* 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.
*/ */
...@@ -45,21 +45,21 @@ ...@@ -45,21 +45,21 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void _sctp_tsnmap_update(sctp_tsnmap_t *map); static void sctp_tsnmap_update(struct sctp_tsnmap *map);
static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map); static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map);
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, __u16 len, __u16 base,
int *started, __u16 *start, int *started, __u16 *start,
int *ended, __u16 *end); int *ended, __u16 *end);
/* Create a new sctp_tsnmap. /* Create a new sctp_tsnmap.
* Allocate room to store at least 'len' contiguous TSNs. * 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), sctp_tsnmap_storage_size(len),
priority); priority);
if (!retval) if (!retval)
...@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) ...@@ -72,13 +72,13 @@ sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
fail_map: fail_map:
kfree(retval); kfree(retval);
fail: fail:
return NULL; return NULL;
} }
/* Initialize a block of memory as a tsnmap. */ /* 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->tsn_map = map->raw_map;
map->overflow_map = map->tsn_map + len; 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 ...@@ -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->max_tsn_seen = map->cumulative_tsn_ack_point;
map->malloced = 0; map->malloced = 0;
map->pending_data = 0; map->pending_data = 0;
map->num_dup_tsns = 0;
return map; return map;
} }
...@@ -104,7 +105,7 @@ sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn ...@@ -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 has been seen (duplicate)
* <0 if the TSN is invalid (too large to track) * <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; __s32 gap;
int dup; int dup;
...@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn) ...@@ -136,7 +137,7 @@ int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
} }
/* Is there a gap in the TSN map? */ /* 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; int has_gap;
...@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map) ...@@ -145,7 +146,7 @@ int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
} }
/* Mark this TSN as seen. */ /* 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; __s32 gap;
...@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn) ...@@ -173,40 +174,45 @@ void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
/* Go fixup any internal TSN mapping variables including /* Go fixup any internal TSN mapping variables including
* cumulative_tsn_ack_point. * 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. */ /* 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; return map->cumulative_tsn_ack_point;
} }
/* Retrieve the highest TSN we've seen. */ /* 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; return map->max_tsn_seen;
} }
/* Dispose of a tsnmap. */ /* Dispose of a tsnmap. */
void sctp_tsnmap_free(sctp_tsnmap_t *map) void sctp_tsnmap_free(struct sctp_tsnmap *map)
{ {
if (map->malloced) if (map->malloced)
kfree(map); kfree(map);
} }
/* Initialize a Gap Ack Block iterator from memory being provided. */ /* 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. */ /* Only start looking one past the Cumulative TSN Ack Point. */
iter->start = map->cumulative_tsn_ack_point + 1; iter->start = map->cumulative_tsn_ack_point + 1;
} }
/* Get the next Gap Ack Blocks. Returns 0 if there was not /* Get the next Gap Ack Blocks. Returns 0 if there was not another block
* another block to get. * to get.
*/ */
int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
__u16 *start, __u16 *end) struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
{ {
int started, ended; int started, ended;
__u16 _start, _end, offset; __u16 _start, _end, offset;
...@@ -216,12 +222,10 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, ...@@ -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. */ /* Search the first mapping array. */
if (iter->start - map->base_tsn < map->len) { if (iter->start - map->base_tsn < map->len) {
offset = iter->start - map->base_tsn; offset = iter->start - map->base_tsn;
_sctp_tsnmap_find_gap_ack(map->tsn_map, sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0,
offset, &started, &_start, &ended, &_end);
map->len, 0,
&started, &_start,
&ended, &_end);
} }
/* Do we need to check the overflow map? */ /* Do we need to check the overflow map? */
...@@ -235,12 +239,12 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, ...@@ -235,12 +239,12 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
offset = iter->start - map->base_tsn - map->len; offset = iter->start - map->base_tsn - map->len;
/* Search the overflow map. */ /* Search the overflow map. */
_sctp_tsnmap_find_gap_ack(map->overflow_map, sctp_tsnmap_find_gap_ack(map->overflow_map,
offset, offset,
map->len, map->len,
map->len, map->len,
&started, &_start, &started, &_start,
&ended, &_end); &ended, &_end);
} }
/* The Gap Ack Block happens to end at the end of the /* The Gap Ack Block happens to end at the end of the
...@@ -278,7 +282,7 @@ int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter, ...@@ -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 /* This private helper function updates the tsnmap buffers and
* the Cumulative TSN Ack Point. * 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; __u32 ctsn;
...@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map) ...@@ -301,10 +305,10 @@ static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
} while (map->tsn_map[ctsn - map->base_tsn]); } while (map->tsn_map[ctsn - map->base_tsn]);
map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ 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 cum_tsn = map->cumulative_tsn_ack_point;
__u32 max_tsn = map->max_tsn_seen; __u32 max_tsn = map->max_tsn_seen;
...@@ -324,7 +328,7 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) ...@@ -324,7 +328,7 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
for (i = start; i < end; i++) { for (i = start; i < end; i++) {
if (map->tsn_map[i]) if (map->tsn_map[i])
pending_data--; pending_data--;
} }
if (gap >= map->len) { if (gap >= map->len) {
start = 0; start = 0;
...@@ -345,14 +349,14 @@ static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map) ...@@ -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 * The flags "started" and "ended" tell is if we found the beginning
* or (respectively) the end of a Gap Ack Block. * 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, __u16 len, __u16 base,
int *started, __u16 *start, int *started, __u16 *start,
int *ended, __u16 *end) int *ended, __u16 *end)
{ {
int i = off; 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. * early if we have found the end of the Gap Ack Block.
*/ */
...@@ -381,3 +385,23 @@ static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, ...@@ -381,3 +385,23 @@ static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
} }
} }
} }
/* Renege that we have seen a TSN. */
void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
{
__s32 gap;
if (TSN_lt(tsn, map->base_tsn))
return;
if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
return;
/* Assert: TSN is in range. */
gap = tsn - map->base_tsn;
/* Pretend we never saw the TSN. */
if (gap < map->len)
map->tsn_map[gap] = 0;
else
map->overflow_map[gap - map->len] = 0;
}
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