Commit 1c5f1800 authored by Jon Grimm's avatar Jon Grimm Committed by Sridhar Samudrala

[SCTP] Fix hardcoded stream counts.

Code had hardcoded limits to the maximum stream that could be used, 
and consequent static data structures.   Now dynamically allocate
storage for the SSN maps until _after_ we know what they are.  
Protocols such as SIP want to use all possible streams.  
parent 4cc42719
...@@ -56,8 +56,10 @@ ...@@ -56,8 +56,10 @@
#include <linux/ipv6.h> /* For ipv6hdr. */ #include <linux/ipv6.h> /* For ipv6hdr. */
#include <net/sctp/user.h> #include <net/sctp/user.h>
/* What a hack! Jiminy Cricket! */ /* Value used for stream negotiation. */
enum { SCTP_MAX_STREAM = 10 }; enum { SCTP_MAX_STREAM = 0xffff };
enum { SCTP_DEFAULT_OUTSTREAMS = 10 };
enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
/* Define the amount of space to reserve for SCTP, IP, LL. /* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating * There is a little bit of waste that we are always allocating
......
...@@ -269,6 +269,7 @@ extern atomic_t sctp_dbg_objcnt_transport; ...@@ -269,6 +269,7 @@ extern atomic_t sctp_dbg_objcnt_transport;
extern atomic_t sctp_dbg_objcnt_chunk; extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_bind_addr;
extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap;
/* Macros to atomically increment/decrement objcnt counters. */ /* Macros to atomically increment/decrement objcnt counters. */
#define SCTP_DBG_OBJCNT_INC(name) \ #define SCTP_DBG_OBJCNT_INC(name) \
......
...@@ -269,6 +269,7 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, ...@@ -269,6 +269,7 @@ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *,
const void *payload, const void *payload,
size_t paylen); size_t paylen);
void sctp_chunk_assign_tsn(sctp_chunk_t *); void sctp_chunk_assign_tsn(sctp_chunk_t *);
void sctp_chunk_assign_ssn(sctp_chunk_t *);
/* Prototypes for statetable processing. */ /* Prototypes for statetable processing. */
......
This diff is collapsed.
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* These are the definitions needed for the sctp_ulpqueue type. The * These are the definitions needed for the sctp_ulpq type. The
* sctp_ulpqueue is the interface between the Upper Layer Protocol, or ULP, * sctp_ulpq is the interface between the Upper Layer Protocol, or ULP,
* and the core SCTP state machine. This is the component which handles * and the core SCTP state machine. This is the component which handles
* reassembly and ordering. * reassembly and ordering.
* *
* 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 addresses:
* * 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:
* * http://www.sf.net/projects/lksctp
*
* Written or modified by:
* Jon Grimm <jgrimm@us.ibm.com>
* La Monte H.P. Yarroll <piggy@acm.org>
*
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -42,46 +47,26 @@ ...@@ -42,46 +47,26 @@
#define __sctp_ulpqueue_h__ #define __sctp_ulpqueue_h__
/* A structure to carry information to the ULP (e.g. Sockets API) */ /* A structure to carry information to the ULP (e.g. Sockets API) */
typedef struct sctp_ulpqueue { struct sctp_ulpq {
int malloced; int malloced;
spinlock_t lock;
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;
__u16 ssn[0]; };
} sctp_ulpqueue_t;
/* This macro assists in creation of external storage for variable length
* internal buffers.
*/
#define sctp_ulpqueue_storage_size(inbound) (sizeof(__u16) * (inbound))
sctp_ulpqueue_t *sctp_ulpqueue_new(sctp_association_t *asoc,
__u16 inbound,
int priority);
sctp_ulpqueue_t *sctp_ulpqueue_init(sctp_ulpqueue_t *ulpq,
sctp_association_t *asoc,
__u16 inbound);
void sctp_ulpqueue_free(sctp_ulpqueue_t *);
/* Prototypes. */
struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority);
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */ /* Add a new DATA chunk for processing. */
int sctp_ulpqueue_tail_data(sctp_ulpqueue_t *, int sctp_ulpq_tail_data(struct sctp_ulpq *, sctp_chunk_t *chunk, int priority);
sctp_chunk_t *chunk,
int priority);
/* Add a new event for propogation to the ULP. */ /* Add a new event for propogation to the ULP. */
int sctp_ulpqueue_tail_event(sctp_ulpqueue_t *, int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
sctp_ulpevent_t *event);
/* Is the ulpqueue empty. */ /* Is the ulpqueue empty. */
int sctp_ulpqueue_is_empty(sctp_ulpqueue_t *); int sctp_ulpqueue_is_empty(struct sctp_ulpq *);
int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
#endif /* __sctp_ulpqueue_h__ */ #endif /* __sctp_ulpqueue_h__ */
...@@ -90,4 +75,4 @@ int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *); ...@@ -90,4 +75,4 @@ int sctp_ulpqueue_is_data_empty(sctp_ulpqueue_t *);
...@@ -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 debug.o ssnmap.o
ifeq ($(CONFIG_SCTP_ADLER32), y) ifeq ($(CONFIG_SCTP_ADLER32), y)
sctp-y += adler32.o sctp-y += adler32.o
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines Corp. * Copyright (c) 2001-2003 International Business Machines Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
...@@ -166,15 +166,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -166,15 +166,10 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; asoc->max_init_attempts = sp->initmsg.sinit_max_attempts;
asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ; asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ;
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number /* Allocate storage for the ssnmap after the inbound and outbound
* * streams have been negotiated during Init.
* The stream sequence number in all the streams shall start
* from 0 when the association is established. Also, when the
* stream sequence number reaches the value 65535 the next
* stream sequence number shall be set to 0.
*/ */
for (i = 0; i < SCTP_MAX_STREAM; i++) asoc->ssnmap = NULL;
asoc->ssn[i] = 0;
/* Set the local window size for receive. /* Set the local window size for receive.
* This is also the rcvbuf space per association. * This is also the rcvbuf space per association.
...@@ -252,15 +247,15 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -252,15 +247,15 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc); asoc);
/* Create an output queue. */ /* Create an output queue. */
sctp_outqueue_init(asoc, &asoc->outqueue); sctp_outq_init(asoc, &asoc->outqueue);
sctp_outqueue_set_output_handlers(&asoc->outqueue, sctp_outq_set_output_handlers(&asoc->outqueue,
sctp_packet_init, sctp_packet_init,
sctp_packet_config, sctp_packet_config,
sctp_packet_append_chunk, sctp_packet_append_chunk,
sctp_packet_transmit_chunk, sctp_packet_transmit_chunk,
sctp_packet_transmit); sctp_packet_transmit);
if (NULL == sctp_ulpqueue_init(&asoc->ulpq, asoc, SCTP_MAX_STREAM)) if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc))
goto fail_init; goto fail_init;
/* Set up the tsn tracking. */ /* Set up the tsn tracking. */
...@@ -310,14 +305,17 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -310,14 +305,17 @@ void sctp_association_free(sctp_association_t *asoc)
asoc->base.dead = 1; asoc->base.dead = 1;
/* Dispose of any data lying around in the outqueue. */ /* Dispose of any data lying around in the outqueue. */
sctp_outqueue_free(&asoc->outqueue); sctp_outq_free(&asoc->outqueue);
/* Dispose of any pending messages for the upper layer. */ /* Dispose of any pending messages for the upper layer. */
sctp_ulpqueue_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_inqueue_free(&asoc->base.inqueue);
/* Free ssnmap storage. */
sctp_ssnmap_free(asoc->ssnmap);
/* Clean up the bound address list. */ /* Clean up the bound address list. */
sctp_bind_addr_free(&asoc->base.bind_addr); sctp_bind_addr_free(&asoc->base.bind_addr);
...@@ -524,7 +522,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -524,7 +522,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
break; break;
default: default:
BUG(); return;
}; };
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
...@@ -534,7 +532,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc, ...@@ -534,7 +532,7 @@ void sctp_assoc_control_transport(sctp_association_t *asoc,
(struct sockaddr_storage *) &transport->ipaddr, (struct sockaddr_storage *) &transport->ipaddr,
0, spc_state, error, GFP_ATOMIC); 0, spc_state, error, GFP_ATOMIC);
if (event) if (event)
sctp_ulpqueue_tail_event(&asoc->ulpq, event); sctp_ulpq_tail_event(&asoc->ulpq, event);
/* Select new active and retran paths. */ /* Select new active and retran paths. */
...@@ -634,7 +632,7 @@ __u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num) ...@@ -634,7 +632,7 @@ __u32 __sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
/* Fetch the next Stream Sequence Number for stream number 'sid'. */ /* Fetch the next Stream Sequence Number for stream number 'sid'. */
__u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
{ {
return asoc->ssn[sid]++; return sctp_ssn_next(&asoc->ssnmap->out, sid);
} }
/* Compare two addresses to see if they match. Wildcard addresses /* Compare two addresses to see if they match. Wildcard addresses
...@@ -852,8 +850,6 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) ...@@ -852,8 +850,6 @@ void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
/* Update an association (possibly from unexpected COOKIE-ECHO processing). */ /* Update an association (possibly from unexpected COOKIE-ECHO processing). */
void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
{ {
int i;
/* 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;
...@@ -872,23 +868,28 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) ...@@ -872,23 +868,28 @@ void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
/* If the case is A (association restart), use /* If the case is A (association restart), use
* initial_tsn as next_tsn. If the case is B, use * initial_tsn as next_tsn. If the case is B, use
* current next_tsn in case there is data sent to peer * current next_tsn in case data sent to peer
* has been discarded and needs retransmission. * has been discarded and needs retransmission.
*/ */
if (SCTP_STATE_ESTABLISHED == asoc->state) { if (SCTP_STATE_ESTABLISHED == asoc->state) {
asoc->next_tsn = new->next_tsn; asoc->next_tsn = new->next_tsn;
asoc->ctsn_ack_point = new->ctsn_ack_point; asoc->ctsn_ack_point = new->ctsn_ack_point;
/* Reinitialize SSN for both local streams /* Reinitialize SSN for both local streams
* and peer's streams. * and peer's streams.
*/ */
for (i = 0; i < SCTP_MAX_STREAM; i++) { sctp_ssnmap_clear(asoc->ssnmap);
asoc->ssn[i] = 0;
asoc->ulpq.ssn[i] = 0;
}
} else { } else {
asoc->ctsn_ack_point = asoc->next_tsn - 1; asoc->ctsn_ack_point = asoc->next_tsn - 1;
if (!asoc->ssnmap) {
/* Move the ssnmap. */
asoc->ssnmap = new->ssnmap;
new->ssnmap = NULL;
}
} }
} }
/* Choose the transport for sending a shutdown packet. /* Choose the transport for sending a shutdown packet.
......
...@@ -47,8 +47,8 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) ...@@ -47,8 +47,8 @@ sctp_cmd_seq_t *sctp_new_cmd_seq(int priority)
{ {
sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority); sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority);
/* XXX Check for NULL? -DaveM */ if (retval)
sctp_init_cmd_seq(retval); sctp_init_cmd_seq(retval);
return retval; return retval;
} }
......
...@@ -113,14 +113,14 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -113,14 +113,14 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
/* FIXME: Currently, ip6_route_output() doesn't fill in the source /* FIXME: Currently, ip6_route_output() doesn't fill in the source
* address in the returned route entry. So we call ipv6_get_saddr() * address in the returned route entry. So we call ipv6_get_saddr()
* to get an appropriate source address. It is possible that this address * to get an appropriate source address. It is possible that this
* may not be part of the bind address list of the association. * address may not be part of the bind address list of the association.
* Once ip6_route_ouput() is fixed so that it returns a route entry * Once ip6_route_ouput() is fixed so that it returns a route entry
* with an appropriate source address, the following if condition can * with an appropriate source address, the following if condition can
* be removed. With ip6_route_output() returning a source address filled * be removed. With ip6_route_output() returning a source address
* route entry, sctp_transport_route() can do real source address * filled route entry, sctp_transport_route() can do real source
* selection for v6. * address selection for v6.
*/ */
if (ipv6_addr_any(&rt6->rt6i_src.addr)) { if (ipv6_addr_any(&rt6->rt6i_src.addr)) {
err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr); err = ipv6_get_saddr(dst, fl.fl6_dst, &saddr);
...@@ -130,7 +130,6 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -130,7 +130,6 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
__FUNCTION__, NIP6(fl.fl6_src)); __FUNCTION__, NIP6(fl.fl6_src));
return err; return err;
} }
fl.fl6_src = &saddr; fl.fl6_src = &saddr;
} else { } else {
fl.fl6_src = &rt6->rt6i_src.addr; fl.fl6_src = &rt6->rt6i_src.addr;
...@@ -572,7 +571,7 @@ int sctp_v6_init(void) ...@@ -572,7 +571,7 @@ int sctp_v6_init(void)
/* Register the SCTP specfic AF_INET6 functions. */ /* Register the SCTP specfic AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific); sctp_register_af(&sctp_ipv6_specific);
/* Register notifier for inet6 address additions/deletions. */ /* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inetaddr_notifier); register_inet6addr_notifier(&sctp_inetaddr_notifier);
return 0; return 0;
......
...@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc); ...@@ -54,6 +54,7 @@ SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT(bind_addr); SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap);
/* An array to make it easy to pretty print the debug information /* An array to make it easy to pretty print the debug information
* to the proc fs. * to the proc fs.
...@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { ...@@ -66,6 +67,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(chunk), SCTP_DBG_OBJCNT_ENTRY(chunk),
SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap),
}; };
/* Callback from procfs to read out objcount information. /* Callback from procfs to read out objcount information.
......
...@@ -227,7 +227,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -227,7 +227,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
} }
/* All packets are sent to the network through this function from /* All packets are sent to the network through this function from
* sctp_push_outqueue(). * sctp_outq_tail().
* *
* The return value is a normal kernel error return value. * The return value is a normal kernel error return value.
*/ */
......
This diff is collapsed.
...@@ -82,7 +82,7 @@ struct sock *sctp_get_ctl_sock(void) ...@@ -82,7 +82,7 @@ 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. */
void sctp_proc_init(void) __init void sctp_proc_init(void)
{ {
if (!proc_net_sctp) { if (!proc_net_sctp) {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
...@@ -95,7 +95,7 @@ void sctp_proc_init(void) ...@@ -95,7 +95,7 @@ void sctp_proc_init(void)
} }
/* 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) __exit void sctp_proc_exit(void)
{ {
if (proc_net_sctp) { if (proc_net_sctp) {
proc_net_sctp = NULL; proc_net_sctp = NULL;
...@@ -688,7 +688,7 @@ static void cleanup_sctp_mibs(void) ...@@ -688,7 +688,7 @@ static void cleanup_sctp_mibs(void)
} }
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
int sctp_init(void) __init int sctp_init(void)
{ {
int i; int i;
int status = 0; int status = 0;
...@@ -750,13 +750,9 @@ int sctp_init(void) ...@@ -750,13 +750,9 @@ int sctp_init(void)
/* Implementation specific variables. */ /* Implementation specific variables. */
/* Initialize default stream count setup information. /* Initialize default stream count setup information. */
* Note: today the stream accounting data structures are very sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS;
* fixed size, so one really does need to make sure that these have sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
* upper/lower limits when changing.
*/
sctp_proto.max_instreams = SCTP_MAX_STREAM;
sctp_proto.max_outstreams = SCTP_MAX_STREAM;
/* Allocate and initialize the association hash table. */ /* Allocate and initialize the association hash table. */
sctp_proto.assoc_hashsize = 4096; sctp_proto.assoc_hashsize = 4096;
...@@ -852,7 +848,7 @@ int sctp_init(void) ...@@ -852,7 +848,7 @@ int sctp_init(void)
} }
/* Exit handler for the SCTP protocol. */ /* Exit handler for the SCTP protocol. */
void sctp_exit(void) __exit void sctp_exit(void)
{ {
/* BUG. This should probably do something useful like clean /* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory. * up all the remaining associations and all that memory.
...@@ -889,4 +885,3 @@ module_exit(sctp_exit); ...@@ -889,4 +885,3 @@ module_exit(sctp_exit);
MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>"); MODULE_AUTHOR("Linux Kernel SCTP developers <lksctp-developers@lists.sourceforge.net>");
MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)"); MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -82,12 +82,12 @@ static const sctp_supported_addrs_param_t sat_param = { ...@@ -82,12 +82,12 @@ static const sctp_supported_addrs_param_t sat_param = {
/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above /* 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 * structure is split and the address types array is initialized using a
* fixed length array. * fixed length array.
*/ */
static const __u16 sat_addr_types[2] = { static const __u16 sat_addr_types[2] = {
SCTP_PARAM_IPV4_ADDRESS, SCTP_PARAM_IPV4_ADDRESS,
SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,)
}; };
/* RFC 2960 3.3.2 Initiation (INIT) (1) /* RFC 2960 3.3.2 Initiation (INIT) (1)
* *
...@@ -540,7 +540,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, ...@@ -540,7 +540,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
dp.stream = htons(sinfo->sinfo_stream); dp.stream = htons(sinfo->sinfo_stream);
dp.ppid = htonl(sinfo->sinfo_ppid); dp.ppid = htonl(sinfo->sinfo_ppid);
dp.ssn = htons(ssn); dp.ssn = htons(ssn);
/* Set the flags for an unordered send. */ /* Set the flags for an unordered send. */
if (sinfo->sinfo_flags & MSG_UNORDERED) if (sinfo->sinfo_flags & MSG_UNORDERED)
flags |= SCTP_DATA_UNORDERED; flags |= SCTP_DATA_UNORDERED;
...@@ -552,7 +552,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, ...@@ -552,7 +552,7 @@ sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp); retval->subh.data_hdr = sctp_addto_chunk(retval, sizeof(dp), &dp);
memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo)); memcpy(&retval->sinfo, sinfo, sizeof(struct sctp_sndrcvinfo));
nodata: nodata:
return retval; return retval;
} }
...@@ -607,12 +607,12 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, ...@@ -607,12 +607,12 @@ sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc,
* ordered send and a new ssn is generated. The flags field is set * ordered send and a new ssn is generated. The flags field is set
* in the inner routine - sctp_make_datafrag_empty(). * in the inner routine - sctp_make_datafrag_empty().
*/ */
if (sinfo->sinfo_flags & MSG_UNORDERED) { // if (sinfo->sinfo_flags & MSG_UNORDERED) {
ssn = 0; ssn = 0;
} else { // } else {
ssn = __sctp_association_get_next_ssn(asoc, // ssn = __sctp_association_get_next_ssn(asoc,
sinfo->sinfo_stream); // sinfo->sinfo_stream);
} // }
return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
} }
...@@ -1013,6 +1013,7 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, ...@@ -1013,6 +1013,7 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
retval->asoc = (sctp_association_t *) asoc; retval->asoc = (sctp_association_t *) asoc;
retval->num_times_sent = 0; retval->num_times_sent = 0;
retval->has_tsn = 0; retval->has_tsn = 0;
retval->has_ssn = 0;
retval->rtt_in_progress = 0; retval->rtt_in_progress = 0;
retval->sent_at = jiffies; retval->sent_at = jiffies;
retval->singleton = 1; retval->singleton = 1;
...@@ -1214,6 +1215,29 @@ int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data) ...@@ -1214,6 +1215,29 @@ int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data)
return err; return err;
} }
/* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned.
*/
void sctp_chunk_assign_ssn(sctp_chunk_t *chunk)
{
__u16 ssn;
__u16 sid;
if (chunk->has_ssn)
return;
/* This is the last possible instant to assign a SSN. */
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
ssn = 0;
} else {
sid = htons(chunk->subh.data_hdr->stream);
ssn = htons(__sctp_association_get_next_ssn(chunk->asoc, sid));
}
chunk->subh.data_hdr->ssn = ssn;
chunk->has_ssn = 1;
}
/* Helper function to assign a TSN if needed. This assumes that both /* Helper function to assign a TSN if needed. This assumes that both
* the data_hdr and association have already been assigned. * the data_hdr and association have already been assigned.
*/ */
...@@ -1654,6 +1678,7 @@ int sctp_verify_init(const sctp_association_t *asoc, ...@@ -1654,6 +1678,7 @@ int sctp_verify_init(const sctp_association_t *asoc,
/* Unpack the parameters in an INIT packet into an association. /* Unpack the parameters in an INIT packet into an association.
* Returns 0 on failure, else success. * Returns 0 on failure, else success.
* FIXME: This is an association method.
*/ */
int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
const union sctp_addr *peer_addr, const union sctp_addr *peer_addr,
...@@ -1710,6 +1735,12 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1710,6 +1735,12 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
ntohs(peer_init->init_hdr.num_inbound_streams); ntohs(peer_init->init_hdr.num_inbound_streams);
} }
if (asoc->c.sinit_max_instreams >
ntohs(peer_init->init_hdr.num_outbound_streams)) {
asoc->c.sinit_max_instreams =
ntohs(peer_init->init_hdr.num_outbound_streams);
}
/* Copy Initiation tag from INIT to VT_peer in cookie. */ /* Copy Initiation tag from INIT to VT_peer in cookie. */
asoc->c.peer_vtag = asoc->peer.i.init_tag; asoc->c.peer_vtag = asoc->peer.i.init_tag;
...@@ -1738,6 +1769,21 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1738,6 +1769,21 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
asoc->peer.i.initial_tsn); asoc->peer.i.initial_tsn);
/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
*
* The stream sequence number in all the streams shall start
* from 0 when the association is established. Also, when the
* stream sequence number reaches the value 65535 the next
* stream sequence number shall be set to 0.
*/
/* Allocate storage for the negotiated streams. */
asoc->ssnmap = sctp_ssnmap_new(asoc->peer.i.num_outbound_streams,
asoc->c.sinit_num_ostreams,
priority);
if (!asoc->ssnmap)
goto nomem_ssnmap;
/* ADDIP Section 4.1 ASCONF Chunk Procedures /* ADDIP Section 4.1 ASCONF Chunk Procedures
* *
* When an endpoint has an ASCONF signaled change to be sent to the * When an endpoint has an ASCONF signaled change to be sent to the
...@@ -1751,6 +1797,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1751,6 +1797,7 @@ int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1; asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;
return 1; return 1;
nomem_ssnmap:
clean_up: clean_up:
/* Release the transport structures. */ /* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
......
...@@ -296,7 +296,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -296,7 +296,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_PURGE_OUTQUEUE: case SCTP_CMD_PURGE_OUTQUEUE:
sctp_outqueue_teardown(&asoc->outqueue); sctp_outq_teardown(&asoc->outqueue);
break; break;
case SCTP_CMD_DELETE_TCB: case SCTP_CMD_DELETE_TCB:
...@@ -395,9 +395,9 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -395,9 +395,9 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
command->obj.ptr, command->obj.ptr,
"ulpq:", "ulpq:",
&asoc->ulpq); &asoc->ulpq);
sctp_ulpqueue_tail_data(&asoc->ulpq, sctp_ulpq_tail_data(&asoc->ulpq,
command->obj.ptr, command->obj.ptr,
GFP_ATOMIC); GFP_ATOMIC);
break; break;
case SCTP_CMD_EVENT_ULP: case SCTP_CMD_EVENT_ULP:
...@@ -407,14 +407,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -407,14 +407,14 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
command->obj.ptr, command->obj.ptr,
"ulpq:", "ulpq:",
&asoc->ulpq); &asoc->ulpq);
sctp_ulpqueue_tail_event(&asoc->ulpq, sctp_ulpq_tail_event(&asoc->ulpq,
command->obj.ptr); command->obj.ptr);
break; break;
case SCTP_CMD_REPLY: case SCTP_CMD_REPLY:
/* Send a chunk to our peer. */ /* Send a chunk to our peer. */
error = sctp_push_outqueue(&asoc->outqueue, error = sctp_outq_tail(&asoc->outqueue,
command->obj.ptr); command->obj.ptr);
break; break;
case SCTP_CMD_SEND_PKT: case SCTP_CMD_SEND_PKT:
...@@ -432,7 +432,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -432,7 +432,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_TRANSMIT: case SCTP_CMD_TRANSMIT:
/* Kick start transmission. */ /* Kick start transmission. */
error = sctp_flush_outqueue(&asoc->outqueue, 0); error = sctp_outq_flush(&asoc->outqueue, 0);
break; break;
case SCTP_CMD_ECN_CE: case SCTP_CMD_ECN_CE:
...@@ -599,7 +599,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -599,7 +599,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_RTO_PENDING: case SCTP_CMD_RTO_PENDING:
t = command->obj.transport; t = command->obj.transport;
t->rto_pending = 1; t->rto_pending = 1;
break; break;
default: default:
...@@ -743,7 +743,7 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands) ...@@ -743,7 +743,7 @@ int sctp_gen_sack(sctp_association_t *asoc, int force, sctp_cmd_seq_t *commands)
asoc->peer.sack_needed = 0; asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0; asoc->peer.next_dup_tsn = 0;
error = sctp_push_outqueue(&asoc->outqueue, sack); error = sctp_outq_tail(&asoc->outqueue, sack);
/* Stop the SACK timer. */ /* Stop the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
...@@ -1095,7 +1095,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1095,7 +1095,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
/* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT /* Process an init chunk (may be real INIT/INIT-ACK or an embedded INIT
* inside the cookie. In reality, this is only used for INIT-ACK processing * inside the cookie. In reality, this is only used for INIT-ACK processing
* since all other cases use "temporary" associations and can do all * since all other cases use "temporary" associations and can do all
* their work in statefuns directly. * their work in statefuns directly.
*/ */
static int sctp_cmd_process_init(sctp_cmd_seq_t *commands, static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
sctp_association_t *asoc, sctp_association_t *asoc,
...@@ -1218,7 +1218,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, ...@@ -1218,7 +1218,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
{ {
int err; int err;
if (sctp_sack_outqueue(&asoc->outqueue, sackh)) { if (sctp_outq_sack(&asoc->outqueue, sackh)) {
/* There are no more TSNs awaiting SACK. */ /* There are no more TSNs awaiting SACK. */
err = sctp_do_sm(SCTP_EVENT_T_OTHER, err = sctp_do_sm(SCTP_EVENT_T_OTHER,
SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN), SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
...@@ -1228,7 +1228,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, ...@@ -1228,7 +1228,7 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
/* Windows may have opened, so we need /* Windows may have opened, so we need
* to check if we have DATA to transmit * to check if we have DATA to transmit
*/ */
err = sctp_flush_outqueue(&asoc->outqueue, 0); err = sctp_outq_flush(&asoc->outqueue, 0);
} }
return err; return err;
......
...@@ -191,7 +191,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -191,7 +191,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
int len; int len;
/* If the packet is an OOTB packet which is temporarily on the /* If the packet is an OOTB packet which is temporarily on the
* control endpoint, responding with an ABORT. * control endpoint, respond with an ABORT.
*/ */
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands); return sctp_sf_ootb(ep, asoc, type, arg, commands);
...@@ -506,7 +506,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -506,7 +506,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
sctp_chunk_t *err_chk_p; sctp_chunk_t *err_chk_p;
/* If the packet is an OOTB packet which is temporarily on the /* If the packet is an OOTB packet which is temporarily on the
* control endpoint, responding with an ABORT. * control endpoint, respond with an ABORT.
*/ */
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands); return sctp_sf_ootb(ep, asoc, type, arg, commands);
...@@ -1337,7 +1337,7 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, ...@@ -1337,7 +1337,7 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
/* Unexpected COOKIE-ECHO handlerfor peer restart (Table 2, action 'A') /* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
* *
* Section 5.2.4 * Section 5.2.4
* A) In this case, the peer may have restarted. * A) In this case, the peer may have restarted.
...@@ -2030,7 +2030,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, ...@@ -2030,7 +2030,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED)); SCTP_STATE(SCTP_STATE_SHUTDOWN_RECEIVED));
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_shutdown_ack(ep, asoc, type, disposition = sctp_sf_do_9_2_shutdown_ack(ep, asoc, type,
arg, commands); arg, commands);
} }
...@@ -3429,7 +3429,7 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, ...@@ -3429,7 +3429,7 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type, disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands); arg, commands);
} }
...@@ -4203,7 +4203,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, ...@@ -4203,7 +4203,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outq_is_empty(&asoc->outqueue)) {
disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type, disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands); arg, commands);
} }
......
...@@ -869,13 +869,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -869,13 +869,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_unlock; goto out_unlock;
} }
} else { } else {
/* Check against the defaults. */
if (sinfo->sinfo_stream >=
sp->initmsg.sinit_num_ostreams) {
err = -EINVAL;
goto out_unlock;
}
/* Check against the requested. */ /* Check against the requested. */
if (sinfo->sinfo_stream >= if (sinfo->sinfo_stream >=
sinit->sinit_num_ostreams) { sinit->sinit_num_ostreams) {
...@@ -916,14 +909,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -916,14 +909,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
sinit->sinit_num_ostreams; sinit->sinit_num_ostreams;
} }
if (sinit->sinit_max_instreams) { if (sinit->sinit_max_instreams) {
if (sinit->sinit_max_instreams <= asoc->c.sinit_max_instreams =
SCTP_MAX_STREAM) { sinit->sinit_max_instreams;
asoc->c.sinit_max_instreams =
sinit->sinit_max_instreams;
} else {
asoc->c.sinit_max_instreams =
SCTP_MAX_STREAM;
}
} }
if (sinit->sinit_max_attempts) { if (sinit->sinit_max_attempts) {
asoc->max_init_attempts asoc->max_init_attempts
......
/* SCTP kernel reference Implementation
* Copyright (c) 2003 International Business Machines, Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
* These functions manipulate sctp SSN tracker.
*
* 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:
* Jon Grimm <jgrimm@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 <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Storage size needed for map includes 2 headers and then the
* specific needs of in or out streams.
*/
static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
{
return sizeof(struct sctp_ssnmap) + (in + out) * sizeof(__u16);
}
/* Create a new sctp_ssnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority)
{
struct sctp_ssnmap *retval;
retval = kmalloc(sctp_ssnmap_size(in, out), priority);
if (!retval)
goto fail;
if (!sctp_ssnmap_init(retval, in, out))
goto fail_map;
retval->malloced = 1;
SCTP_DBG_OBJCNT_INC(ssnmap);
return retval;
fail_map:
kfree(retval);
fail:
return NULL;
}
/* Initialize a block of memory as a ssnmap. */
struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
__u16 out)
{
memset(map, 0x00, sctp_ssnmap_size(in, out));
/* Start 'in' stream just after the map header. */
map->in.ssn = (__u16 *)&map[1];
map->in.len = in;
/* Start 'out' stream just after 'in'. */
map->out.ssn = &map->in.ssn[in];
map->out.len = out;
return map;
}
/* Clear out the ssnmap streams. */
void sctp_ssnmap_clear(struct sctp_ssnmap *map)
{
size_t size;
size = (map->in.len + map->out.len) * sizeof(__u16);
memset(map->in.ssn, 0x00, size);
}
/* Dispose of a ssnmap. */
void sctp_ssnmap_free(struct sctp_ssnmap *map)
{
if (map && map->malloced) {
kfree(map);
SCTP_DBG_OBJCNT_DEC(ssnmap);
}
}
...@@ -800,8 +800,8 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -800,8 +800,8 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
/* 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 Section 4.2.3.3 * The algorithm used is similar to the one described in
* of RFC 1122. * Section 4.2.3.3 of RFC 1122.
*/ */
if ((asoc->state == SCTP_STATE_ESTABLISHED) && if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
(asoc->rwnd > asoc->a_rwnd) && (asoc->rwnd > asoc->a_rwnd) &&
...@@ -819,7 +819,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb) ...@@ -819,7 +819,7 @@ static void sctp_rcvmsg_rfree(struct sk_buff *skb)
asoc->peer.sack_needed = 0; asoc->peer.sack_needed = 0;
asoc->peer.next_dup_tsn = 0; asoc->peer.next_dup_tsn = 0;
sctp_push_outqueue(&asoc->outqueue, sack); sctp_outq_tail(&asoc->outqueue, sack);
/* Stop the SACK timer. */ /* Stop the SACK timer. */
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
......
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