Commit 020fec6e authored by Jon Grimm's avatar Jon Grimm

[SCTP] Add SCTP_NODELAY sockopt and message delay (ardelle.fan)

Submitted by Ardelle Fan.  Add Nagle-like delay to SCTP so small
messages try to bundle together.   Add sockopt to enable/disable
the delay functionality.
parent 1026ffaf
...@@ -110,13 +110,13 @@ typedef union { ...@@ -110,13 +110,13 @@ typedef union {
sctp_event_timeout_t to; sctp_event_timeout_t to;
sctp_counter_t counter; sctp_counter_t counter;
void *ptr; void *ptr;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
sctp_association_t *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
sctp_bind_addr_t *bp; struct sctp_bind_addr *bp;
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
struct sctp_ulpevent *ulpevent; struct sctp_ulpevent *ulpevent;
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_sackhdr_t *sackh; sctp_sackhdr_t *sackh;
} sctp_arg_t; } sctp_arg_t;
...@@ -158,13 +158,13 @@ SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) ...@@ -158,13 +158,13 @@ SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state)
SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter)
SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to)
SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr)
SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk) SCTP_ARG_CONSTRUCTOR(CHUNK, struct sctp_chunk *, chunk)
SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) SCTP_ARG_CONSTRUCTOR(ASOC, struct sctp_association *, 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, struct sctp_bind_addr *, 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, struct sctp_ulpevent *, ulpevent) SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent)
SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet) SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet)
SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh)
typedef struct { typedef struct {
......
...@@ -345,6 +345,7 @@ typedef enum { ...@@ -345,6 +345,7 @@ typedef enum {
SCTP_XMIT_PMTU_FULL, SCTP_XMIT_PMTU_FULL,
SCTP_XMIT_RWND_FULL, SCTP_XMIT_RWND_FULL,
SCTP_XMIT_MUST_FRAG, SCTP_XMIT_MUST_FRAG,
SCTP_XMIT_NAGLE_DELAY,
} sctp_xmit_t; } sctp_xmit_t;
/* These are the commands for manipulating transports. */ /* These are the commands for manipulating transports. */
......
...@@ -313,31 +313,21 @@ static inline void sctp_sysctl_unregister(void) { return; } ...@@ -313,31 +313,21 @@ static inline void sctp_sysctl_unregister(void) { return; }
#endif #endif
/* Size of Supported Address Parameter for 'x' address types. */
#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16))
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
extern int sctp_v6_init(void); extern int sctp_v6_init(void);
extern void sctp_v6_exit(void); extern void sctp_v6_exit(void);
static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) 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);
} }
/* 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. */
/* Use this macro to enclose code fragments which are V6-dependent. */
#define SCTP_V6(m...) m
#define SCTP_V6_SUPPORT 1
#else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
#define sctp_ipv6_addr_type(a) 0 #define sctp_ipv6_addr_type(a) 0
#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16))
#define SCTP_V6(m...) /* Do nothing. */
#undef SCTP_V6_SUPPORT
static inline int sctp_v6_init(void) { return 0; } static inline int sctp_v6_init(void) { return 0; }
static inline void sctp_v6_exit(void) { return; } static inline void sctp_v6_exit(void) { return; }
......
...@@ -313,18 +313,18 @@ void sctp_generate_t3_rtx_event(unsigned long peer); ...@@ -313,18 +313,18 @@ void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer);
sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *);
sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
const sctp_association_t *asoc, const struct sctp_association *,
sctp_chunk_t *chunk, struct sctp_chunk *chunk,
const void *payload, const void *payload,
size_t paylen); size_t paylen);
sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *,
const sctp_chunk_t *chunk); const struct sctp_chunk *);
void sctp_ootb_pkt_free(sctp_packet_t *packet); void sctp_ootb_pkt_free(struct sctp_packet *);
sctp_cookie_param_t * sctp_cookie_param_t *
sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
const sctp_chunk_t *, int *cookie_len, const struct sctp_chunk *, int *cookie_len,
const __u8 *, int addrs_len); const __u8 *, int addrs_len);
sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *,
const sctp_association_t *, const sctp_association_t *,
......
...@@ -88,7 +88,6 @@ struct sctp_ssnmap; ...@@ -88,7 +88,6 @@ struct sctp_ssnmap;
typedef struct sctp_endpoint sctp_endpoint_t; typedef struct sctp_endpoint sctp_endpoint_t;
typedef struct sctp_association sctp_association_t; typedef struct sctp_association sctp_association_t;
typedef struct sctp_packet sctp_packet_t;
typedef struct sctp_chunk sctp_chunk_t; typedef struct sctp_chunk sctp_chunk_t;
typedef struct sctp_bind_addr sctp_bind_addr_t; typedef struct sctp_bind_addr sctp_bind_addr_t;
typedef struct sctp_endpoint_common sctp_endpoint_common_t; typedef struct sctp_endpoint_common sctp_endpoint_common_t;
...@@ -602,26 +601,26 @@ struct sctp_packet { ...@@ -602,26 +601,26 @@ struct sctp_packet {
typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *); typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *);
typedef int (sctp_outq_ehandler_t)(struct sctp_outq *); typedef int (sctp_outq_ehandler_t)(struct sctp_outq *);
typedef sctp_packet_t *(sctp_outq_ohandler_init_t) typedef struct sctp_packet *(sctp_outq_ohandler_init_t)
(sctp_packet_t *, (struct sctp_packet *,
struct sctp_transport *, struct sctp_transport *,
__u16 sport, __u16 sport,
__u16 dport); __u16 dport);
typedef sctp_packet_t *(sctp_outq_ohandler_config_t) typedef struct sctp_packet *(sctp_outq_ohandler_config_t)
(sctp_packet_t *, (struct sctp_packet *,
__u32 vtag, __u32 vtag,
int ecn_capable, int ecn_capable,
sctp_packet_phandler_t *get_prepend_chunk); sctp_packet_phandler_t *get_prepend_chunk);
typedef sctp_xmit_t (sctp_outq_ohandler_t)(sctp_packet_t *, typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
sctp_chunk_t *); sctp_chunk_t *);
typedef int (sctp_outq_ohandler_force_t)(sctp_packet_t *); typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
sctp_outq_ohandler_init_t sctp_packet_init; sctp_outq_ohandler_init_t sctp_packet_init;
sctp_outq_ohandler_config_t sctp_packet_config; sctp_outq_ohandler_config_t sctp_packet_config;
sctp_outq_ohandler_t sctp_packet_append_chunk; sctp_outq_ohandler_t sctp_packet_append_chunk;
sctp_outq_ohandler_t sctp_packet_transmit_chunk; sctp_outq_ohandler_t sctp_packet_transmit_chunk;
sctp_outq_ohandler_force_t sctp_packet_transmit; sctp_outq_ohandler_force_t sctp_packet_transmit;
void sctp_packet_free(sctp_packet_t *); void sctp_packet_free(struct sctp_packet *);
/* This represents a remote transport address. /* This represents a remote transport address.
...@@ -787,7 +786,7 @@ struct sctp_transport { ...@@ -787,7 +786,7 @@ struct sctp_transport {
struct list_head transmitted; struct list_head transmitted;
/* We build bundle-able packets for this transport here. */ /* We build bundle-able packets for this transport here. */
sctp_packet_t packet; struct sctp_packet packet;
/* This is the list of transports that have chunks to send. */ /* This is the list of transports that have chunks to send. */
struct list_head send_ready; struct list_head send_ready;
...@@ -863,12 +862,11 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); ...@@ -863,12 +862,11 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
struct sctp_outq { struct sctp_outq {
sctp_association_t *asoc; sctp_association_t *asoc;
/* BUG: This really should be an array of streams. /* Data pending that has never been transmitted. */
* This really holds a list of chunks (one stream).
* FIXME: If true, why so?
*/
struct sk_buff_head out; struct sk_buff_head out;
unsigned out_qlen; /* Total length of queued data chunks. */
/* These are control chunks we want to send. */ /* These are control chunks we want to send. */
struct sk_buff_head control; struct sk_buff_head control;
...@@ -883,7 +881,7 @@ struct sctp_outq { ...@@ -883,7 +881,7 @@ struct sctp_outq {
struct list_head retransmit; struct list_head retransmit;
/* Call these functions to send chunks down to the next lower /* Call these functions to send chunks down to the next lower
* layer. This is always SCTP_packet, but we separate the two * layer. This is always sctp_packet, but we separate the two
* structures to make testing simpler. * structures to make testing simpler.
*/ */
sctp_outq_ohandler_init_t *init_output; sctp_outq_ohandler_init_t *init_output;
......
...@@ -108,6 +108,8 @@ enum sctp_optname { ...@@ -108,6 +108,8 @@ enum sctp_optname {
#define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM
SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */
#define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS
SCTP_NODELAY, /* Get/set nodelay option. */
#define SCTP_NODELAY SCTP_NODELAY
}; };
......
...@@ -62,16 +62,15 @@ ...@@ -62,16 +62,15 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Forward declarations for private helpers. */ /* Forward declarations for private helpers. */
static void sctp_packet_reset(sctp_packet_t *packet); static void sctp_packet_reset(struct sctp_packet *packet);
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
sctp_chunk_t *chunk); struct sctp_chunk *chunk);
/* Config a packet. /* Config a packet.
* This appears to be a followup set of initializations.) * This appears to be a followup set of initializations.)
*/ */
sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
__u32 vtag, __u32 vtag, int ecn_capable,
int ecn_capable,
sctp_packet_phandler_t *prepend_handler) sctp_packet_phandler_t *prepend_handler)
{ {
int packet_empty = (packet->size == SCTP_IP_OVERHEAD); int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
...@@ -89,10 +88,9 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, ...@@ -89,10 +88,9 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet,
} }
/* Initialize the packet structure. */ /* Initialize the packet structure. */
sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
struct sctp_transport *transport, struct sctp_transport *transport,
__u16 sport, __u16 sport, __u16 dport)
__u16 dport)
{ {
packet->transport = transport; packet->transport = transport;
packet->source_port = sport; packet->source_port = sport;
...@@ -109,14 +107,12 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, ...@@ -109,14 +107,12 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet,
} }
/* Free a packet. */ /* Free a packet. */
void sctp_packet_free(sctp_packet_t *packet) void sctp_packet_free(struct sctp_packet *packet)
{ {
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
while (NULL != while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
(chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) {
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
}
if (packet->malloced) if (packet->malloced)
kfree(packet); kfree(packet);
...@@ -129,8 +125,8 @@ void sctp_packet_free(sctp_packet_t *packet) ...@@ -129,8 +125,8 @@ void sctp_packet_free(sctp_packet_t *packet)
* as it can fit in the packet, but any more data that does not fit in this * as it can fit in the packet, but any more data that does not fit in this
* packet can be sent only after receiving the COOKIE_ACK. * packet can be sent only after receiving the COOKIE_ACK.
*/ */
sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
sctp_chunk_t *chunk) struct sctp_chunk *chunk)
{ {
sctp_xmit_t retval; sctp_xmit_t retval;
int error = 0; int error = 0;
...@@ -152,6 +148,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, ...@@ -152,6 +148,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
case SCTP_XMIT_MUST_FRAG: case SCTP_XMIT_MUST_FRAG:
case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_RWND_FULL:
case SCTP_XMIT_OK: case SCTP_XMIT_OK:
case SCTP_XMIT_NAGLE_DELAY:
break; break;
}; };
...@@ -161,7 +158,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, ...@@ -161,7 +158,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
/* Append a chunk to the offered packet reporting back any inability to do /* Append a chunk to the offered packet reporting back any inability to do
* so. * so.
*/ */
sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
struct sctp_chunk *chunk)
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
__u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
...@@ -223,7 +221,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -223,7 +221,7 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
} }
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); __skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
packet->size += chunk_len; packet->size += chunk_len;
finish: finish:
return retval; return retval;
...@@ -234,18 +232,18 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -234,18 +232,18 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
* *
* The return value is a normal kernel error return value. * The return value is a normal kernel error return value.
*/ */
int sctp_packet_transmit(sctp_packet_t *packet) int sctp_packet_transmit(struct sctp_packet *packet)
{ {
struct sctp_transport *transport = packet->transport; struct sctp_transport *transport = packet->transport;
sctp_association_t *asoc = transport->asoc; struct sctp_association *asoc = transport->asoc;
struct sctphdr *sh; struct sctphdr *sh;
__u32 crc32; __u32 crc32;
struct sk_buff *nskb; struct sk_buff *nskb;
sctp_chunk_t *chunk; struct sctp_chunk *chunk;
struct sock *sk; struct sock *sk;
int err = 0; int err = 0;
int padding; /* How much padding do we need? */ int padding; /* How much padding do we need? */
__u8 packet_has_data = 0; __u8 has_data = 0;
struct dst_entry *dst; struct dst_entry *dst;
/* Do NOT generate a chunkless packet... */ /* Do NOT generate a chunkless packet... */
...@@ -253,7 +251,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -253,7 +251,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
return err; return err;
/* Set up convenience variables... */ /* Set up convenience variables... */
chunk = (sctp_chunk_t *) (packet->chunks.next); chunk = (struct sctp_chunk *) (packet->chunks.next);
sk = chunk->skb->sk; sk = chunk->skb->sk;
/* Allocate the new skb. */ /* Allocate the new skb. */
...@@ -291,8 +289,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -291,8 +289,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
* [This whole comment explains WORD_ROUND() below.] * [This whole comment explains WORD_ROUND() below.]
*/ */
SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
while (NULL != (chunk = (sctp_chunk_t *) while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
skb_dequeue(&packet->chunks))) {
chunk->num_times_sent++; chunk->num_times_sent++;
chunk->sent_at = jiffies; chunk->sent_at = jiffies;
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
...@@ -309,7 +306,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -309,7 +306,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
chunk->rtt_in_progress = 1; chunk->rtt_in_progress = 1;
transport->rto_pending = 1; transport->rto_pending = 1;
} }
packet_has_data = 1; has_data = 1;
} }
memcpy(skb_put(nskb, chunk->skb->len), memcpy(skb_put(nskb, chunk->skb->len),
chunk->skb->data, chunk->skb->len); chunk->skb->data, chunk->skb->len);
...@@ -399,7 +396,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -399,7 +396,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
asoc->peer.last_sent_to = transport; asoc->peer.last_sent_to = transport;
} }
if (packet_has_data) { if (has_data) {
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
...@@ -456,9 +453,9 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -456,9 +453,9 @@ int sctp_packet_transmit(sctp_packet_t *packet)
/* /*
* This private function resets the packet to a fresh state. * This private function resets the packet to a fresh state.
*/ */
static void sctp_packet_reset(sctp_packet_t *packet) static void sctp_packet_reset(struct sctp_packet *packet)
{ {
sctp_chunk_t *chunk = NULL; struct sctp_chunk *chunk = NULL;
packet->size = SCTP_IP_OVERHEAD; packet->size = SCTP_IP_OVERHEAD;
...@@ -473,13 +470,15 @@ static void sctp_packet_reset(sctp_packet_t *packet) ...@@ -473,13 +470,15 @@ static void sctp_packet_reset(sctp_packet_t *packet)
} }
/* This private function handles the specifics of appending DATA chunks. */ /* This private function handles the specifics of appending DATA chunks. */
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
sctp_chunk_t *chunk) struct sctp_chunk *chunk)
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight; size_t datasize, rwnd, inflight;
struct sctp_transport *transport = packet->transport; struct sctp_transport *transport = packet->transport;
__u32 max_burst_bytes; __u32 max_burst_bytes;
struct sctp_opt *sp = sctp_sk(transport->asoc->base.sk);
struct sctp_outq *q = &transport->asoc->outqueue;
/* RFC 2960 6.1 Transmission of DATA Chunks /* RFC 2960 6.1 Transmission of DATA Chunks
* *
...@@ -543,11 +542,34 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, ...@@ -543,11 +542,34 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
* When a Fast Retransmit is being performed the sender SHOULD * When a Fast Retransmit is being performed the sender SHOULD
* ignore the value of cwnd and SHOULD NOT delay retransmission. * ignore the value of cwnd and SHOULD NOT delay retransmission.
*/ */
if (!chunk->fast_retransmit) { if (!chunk->fast_retransmit)
if (transport->flight_size >= transport->cwnd) { if (transport->flight_size >= transport->cwnd) {
retval = SCTP_XMIT_RWND_FULL; retval = SCTP_XMIT_RWND_FULL;
goto finish; goto finish;
} }
/* Nagle's algorithm to solve small-packet problem:
* inhibit the sending of new chunks when new outgoing data arrives
* if any proeviously transmitted data on the connection remains
* unacknowledged. Unless the connection was previously idle. Check
* whether the connection is idle. No outstanding means idle, flush
* it. If outstanding bytes are less than half cwnd, the connection
* is not in the state of congestion, so also flush it.
*/
if (!sp->nodelay && q->outstanding_bytes >= transport->cwnd >> 1) {
/* Check whether this chunk and all the rest of pending
* data will fit or whether we'll choose to delay in
* hopes of bundling a full sized packet.
*/
if ((datasize + q->out_qlen) < transport->asoc->frag_point) {
/* If the the chunk should be delay
* for future sending, we could not
* append it.
*/
retval = SCTP_XMIT_NAGLE_DELAY;
goto finish;
}
} }
/* Keep track of how many bytes are in flight over this transport. */ /* Keep track of how many bytes are in flight over this transport. */
......
/* 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 Intel Corp. * Copyright (c) 2001-2003 Intel Corp.
* Copyright (c) 2001-2003 International Business Machines Corp. * Copyright (c) 2001-2003 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
...@@ -62,6 +62,33 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -62,6 +62,33 @@ static void sctp_check_transmitted(struct sctp_outq *q,
sctp_sackhdr_t *sack, sctp_sackhdr_t *sack,
__u32 highest_new_tsn); __u32 highest_new_tsn);
/* Add data to the front of the queue. */
static inline void sctp_outq_head_data(struct sctp_outq *q,
struct sctp_chunk *ch)
{
__skb_queue_head(&q->out, (struct sk_buff *)ch);
q->out_qlen += ch->skb->len;
return;
}
/* Take data from the front of the queue. */
static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
{
struct sctp_chunk *ch;
ch = (struct sctp_chunk *)__skb_dequeue(&q->out);
if (ch)
q->out_qlen -= ch->skb->len;
return ch;
}
/* Add data chunk to the end of the queue. */
static inline void sctp_outq_tail_data(struct sctp_outq *q,
struct sctp_chunk *ch)
{
__skb_queue_tail(&q->out, (struct sk_buff *)ch);
q->out_qlen += ch->skb->len;
return;
}
/* Generate a new outqueue. */ /* Generate a new outqueue. */
struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) struct sctp_outq *sctp_outq_new(sctp_association_t *asoc)
{ {
...@@ -97,6 +124,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) ...@@ -97,6 +124,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
q->empty = 1; q->empty = 1;
q->malloced = 0; q->malloced = 0;
q->out_qlen = 0;
} }
/* Free the outqueue structure and any related pending chunks. /* Free the outqueue structure and any related pending chunks.
...@@ -133,7 +161,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -133,7 +161,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
} }
/* Throw away any leftover data chunks. */ /* Throw away any leftover data chunks. */
while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out))) while ((chunk = sctp_outq_dequeue_data(q)))
sctp_free_chunk(chunk); sctp_free_chunk(chunk);
/* Throw away any leftover control chunks. */ /* Throw away any leftover control chunks. */
...@@ -192,7 +220,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) ...@@ -192,7 +220,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type))
: "Illegal Chunk"); : "Illegal Chunk");
skb_queue_tail(&q->out, (struct sk_buff *) chunk); sctp_outq_tail_data(q, chunk);
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
SCTP_INC_STATS(SctpOutUnorderChunks); SCTP_INC_STATS(SctpOutUnorderChunks);
else else
...@@ -201,7 +229,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) ...@@ -201,7 +229,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
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); SCTP_INC_STATS(SctpOutCtrlChunks);
} }
...@@ -351,7 +379,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -351,7 +379,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* *
* The return value is a normal kernel error return value. * The return value is a normal kernel error return value.
*/ */
static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
int rtx_timeout, int *start_timer) int rtx_timeout, int *start_timer)
{ {
struct list_head *lqueue; struct list_head *lqueue;
...@@ -385,17 +413,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, ...@@ -385,17 +413,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
while (lchunk) { while (lchunk) {
chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
#if 0
/* If a chunk has been tried for more than SCTP_DEF_MAX_SEND
* times, discard it, and check the empty flag of the outqueue.
*
* --xguo
*/
if (chunk->snd_count > SCTP_DEF_MAX_SEND) {
sctp_free_chunk(chunk);
continue;
}
#endif
/* Make sure that Gap Acked TSNs are not retransmitted. A /* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the * simple approach is just to move such TSNs out of the
...@@ -462,7 +479,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, ...@@ -462,7 +479,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt,
* chunk that is currently in the process of fragmentation. * chunk that is currently in the process of fragmentation.
*/ */
void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
sctp_packet_t *packet, sctp_chunk_t *frag, __u32 tsn) struct sctp_packet *packet, sctp_chunk_t *frag, __u32 tsn)
{ {
struct sctp_transport *transport = packet->transport; struct sctp_transport *transport = packet->transport;
struct sk_buff_head *queue = &q->out; struct sk_buff_head *queue = &q->out;
...@@ -480,11 +497,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, ...@@ -480,11 +497,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. "
"adding 0x%x to outqueue\n", "adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn)); ntohl(frag->subh.data_hdr->tsn));
if (pos) { if (pos)
skb_insert(pos, (struct sk_buff *) frag); __skb_insert((struct sk_buff *)frag, pos->prev,
} else { pos, pos->list);
skb_queue_tail(queue, (struct sk_buff *) frag); else
} __skb_queue_tail(queue, (struct sk_buff *) frag);
return; return;
} }
...@@ -496,11 +513,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, ...@@ -496,11 +513,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. "
"adding 0x%x to outqueue\n", "adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn)); ntohl(frag->subh.data_hdr->tsn));
if (pos) { if (pos)
skb_insert(pos, (struct sk_buff *) frag); __skb_insert((struct sk_buff *)frag, pos->prev,
} else { pos, pos->list);
skb_queue_tail(queue, (struct sk_buff *) frag); else
} __skb_queue_tail(queue, (struct sk_buff *)frag);
break; break;
case SCTP_XMIT_OK: case SCTP_XMIT_OK:
...@@ -512,11 +529,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, ...@@ -512,11 +529,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
"failed. adding 0x%x to outqueue\n", "failed. adding 0x%x to outqueue\n",
ntohl(frag->subh.data_hdr->tsn)); ntohl(frag->subh.data_hdr->tsn));
if (pos) { if (pos)
skb_insert(pos, (struct sk_buff *) frag); __skb_insert((struct sk_buff *)frag, pos->prev,
} else { pos, pos->list);
skb_queue_tail(queue, (struct sk_buff *) frag); else
} __skb_queue_tail(queue,(struct sk_buff *)frag);
} else { } else {
SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
"success. 0x%x sent\n", "success. 0x%x sent\n",
...@@ -537,7 +554,7 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, ...@@ -537,7 +554,7 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos,
* The argument 'frag' point to the first fragment and it holds the list * The argument 'frag' point to the first fragment and it holds the list
* of all the other fragments in the 'frag_list' field. * of all the other fragments in the 'frag_list' field.
*/ */
void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet, void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt,
sctp_chunk_t *frag) sctp_chunk_t *frag)
{ {
sctp_association_t *asoc = frag->asoc; sctp_association_t *asoc = frag->asoc;
...@@ -557,13 +574,13 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet, ...@@ -557,13 +574,13 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet,
pos = skb_peek(&q->out); pos = skb_peek(&q->out);
/* Transmit the first fragment. */ /* Transmit the first fragment. */
sctp_xmit_frag(q, pos, packet, frag, tsn++); sctp_xmit_frag(q, pos, pkt, frag, tsn++);
/* Transmit the rest of fragments. */ /* Transmit the rest of fragments. */
frag_list = &frag->frag_list; frag_list = &frag->frag_list;
list_for_each(lfrag, frag_list) { list_for_each(lfrag, frag_list) {
frag = list_entry(lfrag, sctp_chunk_t, frag_list); frag = list_entry(lfrag, sctp_chunk_t, frag_list);
sctp_xmit_frag(q, pos, packet, frag, tsn++); sctp_xmit_frag(q, pos, pkt, frag, tsn++);
} }
} }
...@@ -672,15 +689,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, ...@@ -672,15 +689,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
* *
* Description: Send everything in q which we legally can, subject to * Description: Send everything in q which we legally can, subject to
* congestion limitations. * congestion limitations.
* * * Note: This function can be called from multiple contexts so appropriate
* Note: This function can be called from multiple contexts so appropriate
* locking concerns must be made. Today we use the sock lock to protect * locking concerns must be made. Today we use the sock lock to protect
* this function. * this function.
*/ */
int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
{ {
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_packet_t singleton; struct sctp_packet singleton;
sctp_association_t *asoc = q->asoc; sctp_association_t *asoc = q->asoc;
int ecn_capable = asoc->peer.ecn_capable; int ecn_capable = asoc->peer.ecn_capable;
__u16 sport = asoc->base.bind_addr.port; __u16 sport = asoc->base.bind_addr.port;
...@@ -852,7 +868,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -852,7 +868,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
/* Finally, transmit new packets. */ /* Finally, transmit new packets. */
start_timer = 0; start_timer = 0;
queue = &q->out; queue = &q->out;
while (NULL != (chunk = (sctp_chunk_t *) skb_dequeue(queue))) {
while (NULL != (chunk = sctp_outq_dequeue_data(q))) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier. * stream identifier.
*/ */
...@@ -925,6 +942,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -925,6 +942,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
switch (status) { switch (status) {
case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_PMTU_FULL:
case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_RWND_FULL:
case SCTP_XMIT_NAGLE_DELAY:
/* We could not append this chunk, so put /* We could not append this chunk, so put
* the chunk back on the output queue. * the chunk back on the output queue.
*/ */
...@@ -932,7 +950,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -932,7 +950,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
"not transmit TSN: 0x%x, status: %d\n", "not transmit TSN: 0x%x, status: %d\n",
ntohl(chunk->subh.data_hdr->tsn), ntohl(chunk->subh.data_hdr->tsn),
status); status);
skb_queue_head(queue, (struct sk_buff *)chunk); sctp_outq_head_data(q, chunk);
goto sctp_flush_out; goto sctp_flush_out;
break; break;
...@@ -994,6 +1012,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -994,6 +1012,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
} }
sctp_flush_out: sctp_flush_out:
/* Before returning, examine all the transports touched in /* Before returning, examine all the transports touched in
* this call. Right now, we bluntly force clear all the * this call. Right now, we bluntly force clear all the
* transports. Things might change after we implement Nagle. * transports. Things might change after we implement Nagle.
...@@ -1163,11 +1182,10 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) ...@@ -1163,11 +1182,10 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
sack_a_rwnd = ntohl(sack->a_rwnd); sack_a_rwnd = ntohl(sack->a_rwnd);
outstanding = q->outstanding_bytes; outstanding = q->outstanding_bytes;
if (outstanding < sack_a_rwnd) { if (outstanding < sack_a_rwnd)
sack_a_rwnd -= outstanding; sack_a_rwnd -= outstanding;
} else { else
sack_a_rwnd = 0; sack_a_rwnd = 0;
}
asoc->peer.rwnd = sack_a_rwnd; asoc->peer.rwnd = sack_a_rwnd;
......
...@@ -502,10 +502,13 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event, ...@@ -502,10 +502,13 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event,
*/ */
int sctp_ctl_sock_init(void) int sctp_ctl_sock_init(void)
{ {
int err = 0; int err;
int family = PF_INET; sa_family_t family;
SCTP_V6(family = PF_INET6;) if (sctp_get_pf_specific(PF_INET6))
family = PF_INET6;
else
family = PF_INET;
err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP,
&sctp_ctl_socket); &sctp_ctl_socket);
......
...@@ -256,7 +256,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -256,7 +256,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_cmd_t *cmd; sctp_cmd_t *cmd;
sctp_chunk_t *new_obj; sctp_chunk_t *new_obj;
sctp_chunk_t *chunk = NULL; sctp_chunk_t *chunk = NULL;
sctp_packet_t *packet; struct sctp_packet *packet;
struct list_head *pos; struct list_head *pos;
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
......
...@@ -189,7 +189,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, ...@@ -189,7 +189,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
sctp_chunk_t *repl; sctp_chunk_t *repl;
sctp_association_t *new_asoc; sctp_association_t *new_asoc;
sctp_chunk_t *err_chunk; sctp_chunk_t *err_chunk;
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param; sctp_unrecognized_param_t *unk_param;
int len; int len;
...@@ -354,10 +354,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, ...@@ -354,10 +354,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
sctp_init_chunk_t *initchunk; sctp_init_chunk_t *initchunk;
__u32 init_tag; __u32 init_tag;
sctp_chunk_t *err_chunk; sctp_chunk_t *err_chunk;
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_disposition_t ret; sctp_disposition_t ret;
/* 6.10 Bundling /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
...@@ -912,14 +911,14 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, ...@@ -912,14 +911,14 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
int len; int len;
sctp_packet_t *pkt; struct sctp_packet *pkt;
sctp_addr_param_t *addrparm; sctp_addr_param_t *addrparm;
sctp_errhdr_t *errhdr; sctp_errhdr_t *errhdr;
sctp_endpoint_t *ep; sctp_endpoint_t *ep;
char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)];
/* Build the error on the stack. We are way to malloc /* Build the error on the stack. We are way to malloc crazy
* malloc crazy throughout the code today. * throughout the code today.
*/ */
errhdr = (sctp_errhdr_t *)buffer; errhdr = (sctp_errhdr_t *)buffer;
addrparm = (sctp_addr_param_t *)errhdr->variable; addrparm = (sctp_addr_param_t *)errhdr->variable;
...@@ -1105,11 +1104,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1105,11 +1104,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_chunk_t *repl; sctp_chunk_t *repl;
sctp_association_t *new_asoc; sctp_association_t *new_asoc;
sctp_chunk_t *err_chunk; sctp_chunk_t *err_chunk;
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_unrecognized_param_t *unk_param; sctp_unrecognized_param_t *unk_param;
int len; int len;
/* 6.10 Bundling /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
...@@ -2751,7 +2749,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, ...@@ -2751,7 +2749,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_packet_t *packet = NULL; struct sctp_packet *packet = NULL;
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sctp_chunk_t *abort; sctp_chunk_t *abort;
...@@ -2953,7 +2951,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, ...@@ -2953,7 +2951,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_packet_t *packet = NULL; struct sctp_packet *packet = NULL;
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
sctp_chunk_t *shut; sctp_chunk_t *shut;
...@@ -4377,13 +4375,13 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) ...@@ -4377,13 +4375,13 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
/* Create an ABORT packet to be sent as a response, with the specified /* Create an ABORT packet to be sent as a response, with the specified
* error causes. * error causes.
*/ */
sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
const sctp_association_t *asoc, const sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk,
const void *payload, const void *payload,
size_t paylen) size_t paylen)
{ {
sctp_packet_t *packet; struct sctp_packet *packet;
sctp_chunk_t *abort; sctp_chunk_t *abort;
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
...@@ -4413,10 +4411,10 @@ sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, ...@@ -4413,10 +4411,10 @@ sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
} }
/* Allocate a packet for responding in the OOTB conditions. */ /* Allocate a packet for responding in the OOTB conditions. */
sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc,
const sctp_chunk_t *chunk) const sctp_chunk_t *chunk)
{ {
sctp_packet_t *packet; struct sctp_packet *packet;
struct sctp_transport *transport; struct sctp_transport *transport;
__u16 sport; __u16 sport;
__u16 dport; __u16 dport;
...@@ -4449,7 +4447,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, ...@@ -4449,7 +4447,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
goto nomem; goto nomem;
/* Allocate a new packet for sending the response. */ /* Allocate a new packet for sending the response. */
packet = t_new(sctp_packet_t, GFP_ATOMIC); packet = t_new(struct sctp_packet, GFP_ATOMIC);
if (!packet) if (!packet)
goto nomem_packet; goto nomem_packet;
...@@ -4471,7 +4469,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, ...@@ -4471,7 +4469,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
} }
/* Free the packet allocated earlier for responding in the OOTB condition. */ /* Free the packet allocated earlier for responding in the OOTB condition. */
void sctp_ootb_pkt_free(sctp_packet_t *packet) void sctp_ootb_pkt_free(struct sctp_packet *packet)
{ {
sctp_transport_free(packet->transport); sctp_transport_free(packet->transport);
sctp_packet_free(packet); sctp_packet_free(packet);
...@@ -4484,7 +4482,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, ...@@ -4484,7 +4482,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
sctp_chunk_t *err_chunk) sctp_chunk_t *err_chunk)
{ {
sctp_packet_t *packet; struct sctp_packet *packet;
if (err_chunk) { if (err_chunk) {
packet = sctp_ootb_pkt_new(asoc, chunk); packet = sctp_ootb_pkt_new(asoc, chunk);
......
...@@ -1221,7 +1221,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr ...@@ -1221,7 +1221,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
return err; return err;
} }
static inline int sctp_setsockopt_disable_fragments(struct sock *sk, static int sctp_setsockopt_disable_fragments(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
int val; int val;
...@@ -1237,7 +1237,7 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, ...@@ -1237,7 +1237,7 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
return 0; return 0;
} }
static inline int sctp_setsockopt_events(struct sock *sk, char *optval, static int sctp_setsockopt_events(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
if (optlen != sizeof(struct sctp_event_subscribe)) if (optlen != sizeof(struct sctp_event_subscribe))
...@@ -1247,7 +1247,7 @@ static inline int sctp_setsockopt_events(struct sock *sk, char *optval, ...@@ -1247,7 +1247,7 @@ static inline int sctp_setsockopt_events(struct sock *sk, char *optval,
return 0; return 0;
} }
static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
...@@ -1264,7 +1264,7 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1264,7 +1264,7 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return 0; return 0;
} }
static inline int sctp_setsockopt_peer_addr_params(struct sock *sk, static int sctp_setsockopt_peer_addr_params(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
...@@ -1323,7 +1323,7 @@ static inline int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1323,7 +1323,7 @@ static inline int sctp_setsockopt_peer_addr_params(struct sock *sk,
return 0; return 0;
} }
static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, static int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
if (optlen != sizeof(struct sctp_initmsg)) if (optlen != sizeof(struct sctp_initmsg))
...@@ -1348,7 +1348,7 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, ...@@ -1348,7 +1348,7 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
* sinfo_timetolive. The user must provide the sinfo_assoc_id field in * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model. * to this call if the caller is using the UDP model.
*/ */
static inline int sctp_setsockopt_default_send_param(struct sock *sk, static int sctp_setsockopt_default_send_param(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
...@@ -1406,6 +1406,31 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) ...@@ -1406,6 +1406,31 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
return 0; return 0;
} }
/*
*
* 7.1.5 SCTP_NODELAY
*
* Turn on/off any Nagle-like algorithm. This means that packets are
* generally sent as soon as possible and no unnecessary delays are
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
int optlen)
{
__u8 val;
if (optlen < sizeof(__u8))
return -EINVAL;
if (get_user(val, (__u8 *)optval))
return -EFAULT;
sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
return 0;
}
/* API 6.2 setsockopt(), getsockopt() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * Applications use setsockopt() and getsockopt() to set or retrieve
...@@ -1505,6 +1530,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1505,6 +1530,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_peer_prim(sk, optval, optlen); retval = sctp_setsockopt_peer_prim(sk, optval, optlen);
break; break;
case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -1715,7 +1744,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1715,7 +1744,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->disable_fragments = 0; sp->disable_fragments = 0;
/* Turn on/off any Nagle-like algorithm. */ /* Turn on/off any Nagle-like algorithm. */
sp->nodelay = 0; sp->nodelay = 1;
/* Auto-close idle associations after the configured /* Auto-close idle associations after the configured
* number of seconds. A value of 0 disables this * number of seconds. A value of 0 disables this
...@@ -1834,7 +1863,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -1834,7 +1863,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
return (retval); return (retval);
} }
static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
int val; int val;
...@@ -1851,7 +1880,7 @@ static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, ...@@ -1851,7 +1880,7 @@ static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
return 0; return 0;
} }
static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen)
{ {
if (len != sizeof(struct sctp_event_subscribe)) if (len != sizeof(struct sctp_event_subscribe))
return -EINVAL; return -EINVAL;
...@@ -1860,7 +1889,7 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt ...@@ -1860,7 +1889,7 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt
return 0; return 0;
} }
static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
{ {
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) if (SCTP_SOCKET_TCP == sctp_sk(sk)->type)
...@@ -1973,7 +2002,7 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso ...@@ -1973,7 +2002,7 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
return err; return err;
} }
static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen)
{ {
sctp_peeloff_arg_t peeloff; sctp_peeloff_arg_t peeloff;
struct socket *newsock; struct socket *newsock;
...@@ -2016,7 +2045,7 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval ...@@ -2016,7 +2045,7 @@ static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval
return retval; return retval;
} }
static inline int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
...@@ -2060,7 +2089,7 @@ static inline int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2060,7 +2089,7 @@ static inline int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
return 0; return 0;
} }
static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen)
{ {
if (len != sizeof(struct sctp_initmsg)) if (len != sizeof(struct sctp_initmsg))
return -EINVAL; return -EINVAL;
...@@ -2139,7 +2168,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, ...@@ -2139,7 +2168,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
return 0; return 0;
} }
static inline int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_assoc_t id; sctp_assoc_t id;
...@@ -2178,7 +2207,7 @@ static inline int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, ...@@ -2178,7 +2207,7 @@ static inline int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
return 0; return 0;
} }
static inline int sctp_getsockopt_local_addrs(struct sock *sk, int len, static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_bind_addr_t *bp; sctp_bind_addr_t *bp;
...@@ -2280,7 +2309,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len, ...@@ -2280,7 +2309,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len,
* *
* For getsockopt, it get the default sctp_sndrcvinfo structure. * For getsockopt, it get the default sctp_sndrcvinfo structure.
*/ */
static inline int sctp_getsockopt_default_send_param(struct sock *sk, static int sctp_getsockopt_default_send_param(struct sock *sk,
int len, char *optval, int *optlen) int len, char *optval, int *optlen)
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
...@@ -2307,6 +2336,33 @@ static inline int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -2307,6 +2336,33 @@ static inline int sctp_getsockopt_default_send_param(struct sock *sk,
return 0; return 0;
} }
/*
*
* 7.1.5 SCTP_NODELAY
*
* Turn on/off any Nagle-like algorithm. This means that packets are
* generally sent as soon as possible and no unnecessary delays are
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
static int sctp_getsockopt_nodelay(struct sock *sk, int len,
char *optval, int *optlen)
{
__u8 val;
if (len < sizeof(__u8))
return -EINVAL;
len = sizeof(__u8);
val = (sctp_sk(sk)->nodelay == 1);
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT;
return 0;
}
SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
...@@ -2380,6 +2436,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -2380,6 +2436,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_SET_PEER_PRIMARY_ADDR: case SCTP_SET_PEER_PRIMARY_ADDR:
retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen); retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen);
break; break;
case SCTP_NODELAY:
retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -2650,7 +2709,6 @@ int sctp_inet_listen(struct socket *sock, int backlog) ...@@ -2650,7 +2709,6 @@ int sctp_inet_listen(struct socket *sock, int backlog)
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
err = sctp_seqpacket_listen(sk, backlog); err = sctp_seqpacket_listen(sk, backlog);
break; break;
case SOCK_STREAM: case SOCK_STREAM:
/* FIXME for TCP-style sockets. */ /* FIXME for TCP-style sockets. */
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -3038,7 +3096,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -3038,7 +3096,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
} }
/* Verify that this is a valid address. */ /* Verify that this is a valid address. */
static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
int len)
{ {
struct sctp_af *af; struct sctp_af *af;
......
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