Commit 982f0efd authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] Cleanup sctp_packet and sctp_outq infrastructure.

parent fe276637
......@@ -346,7 +346,6 @@ typedef enum {
SCTP_XMIT_OK,
SCTP_XMIT_PMTU_FULL,
SCTP_XMIT_RWND_FULL,
SCTP_XMIT_MUST_FRAG,
SCTP_XMIT_NAGLE_DELAY,
} sctp_xmit_t;
......
......@@ -679,16 +679,6 @@ struct sctp_packet {
*/
struct sctp_transport *transport;
/* Allow a callback for getting a high priority chunk
* bundled early into the packet (This is used for ECNE).
*/
sctp_packet_phandler_t *get_prepend_chunk;
/* This packet should advertise ECN capability to the network
* via the ECT bit.
*/
char ecn_capable;
/* This packet contains a COOKIE-ECHO chunk. */
char has_cookie_echo;
......@@ -701,27 +691,15 @@ struct sctp_packet {
int malloced;
};
typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *);
typedef int (sctp_outq_ehandler_t)(struct sctp_outq *);
typedef struct sctp_packet *(sctp_outq_ohandler_init_t)
(struct sctp_packet *,
struct sctp_transport *,
__u16 sport,
__u16 dport);
typedef struct sctp_packet *(sctp_outq_ohandler_config_t)
(struct sctp_packet *,
__u32 vtag,
int ecn_capable,
sctp_packet_phandler_t *get_prepend_chunk);
typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
struct sctp_chunk *);
typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
sctp_outq_ohandler_init_t sctp_packet_init;
sctp_outq_ohandler_config_t sctp_packet_config;
sctp_outq_ohandler_t sctp_packet_append_chunk;
sctp_outq_ohandler_t sctp_packet_transmit_chunk;
sctp_outq_ohandler_force_t sctp_packet_transmit;
struct sctp_packet *sctp_packet_init(struct sctp_packet *,
struct sctp_transport *,
__u16 sport, __u16 dport);
struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int);
sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *,
struct sctp_chunk *);
sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *,
struct sctp_chunk *);
int sctp_packet_transmit(struct sctp_packet *);
void sctp_packet_free(struct sctp_packet *);
static inline int sctp_packet_empty(struct sctp_packet *packet)
......@@ -1015,16 +993,6 @@ struct sctp_outq {
*/
struct list_head retransmit;
/* Call these functions to send chunks down to the next lower
* layer. This is always sctp_packet, but we separate the two
* structures to make testing simpler.
*/
sctp_outq_ohandler_init_t *init_output;
sctp_outq_ohandler_config_t *config_output;
sctp_outq_ohandler_t *append_output;
sctp_outq_ohandler_t *build_output;
sctp_outq_ohandler_force_t *force_output;
/* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes;
......@@ -1046,12 +1014,6 @@ int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk);
int sctp_outq_flush(struct sctp_outq *, int);
int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *);
int sctp_outq_is_empty(const struct sctp_outq *);
int sctp_outq_set_output_handlers(struct sctp_outq *,
sctp_outq_ohandler_init_t init,
sctp_outq_ohandler_config_t config,
sctp_outq_ohandler_t append,
sctp_outq_ohandler_t build,
sctp_outq_ohandler_force_t force);
void sctp_outq_restart(struct sctp_outq *);
void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
......
......@@ -261,12 +261,6 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
/* Create an output queue. */
sctp_outq_init(asoc, &asoc->outqueue);
sctp_outq_set_output_handlers(&asoc->outqueue,
sctp_packet_init,
sctp_packet_config,
sctp_packet_append_chunk,
sctp_packet_transmit_chunk,
sctp_packet_transmit);
if (!sctp_ulpq_init(&asoc->ulpq, asoc))
goto fail_init;
......@@ -482,10 +476,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
/* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway.
*/
(asoc->outqueue.init_output)(&peer->packet,
peer,
asoc->base.bind_addr.port,
asoc->peer.port);
sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port,
asoc->peer.port);
/* 7.2.1 Slow-Start
*
......
......@@ -62,27 +62,35 @@
#include <net/sctp/sm.h>
/* Forward declarations for private helpers. */
static void sctp_packet_reset(struct sctp_packet *packet);
static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk);
/* Config a packet.
* This appears to be a followup set of initializations.)
* This appears to be a followup set of initializations.
*/
struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
__u32 vtag, int ecn_capable,
sctp_packet_phandler_t *prepend_handler)
__u32 vtag, int ecn_capable)
{
struct sctp_chunk *chunk = NULL;
SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__,
packet, vtag);
packet->vtag = vtag;
packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */
if (sctp_packet_empty(packet))
sctp_packet_reset(packet);
if (ecn_capable && sctp_packet_empty(packet)) {
chunk = sctp_get_ecne_prepend(packet->transport->asoc);
/* If there a is a prepend chunk stick it on the list before
* any other chunks get appended.
*/
if (chunk)
sctp_packet_append_chunk(packet, chunk);
}
return packet;
}
......@@ -94,6 +102,9 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
struct sctp_association *asoc = transport->asoc;
size_t overhead;
SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__,
packet, transport);
packet->transport = transport;
packet->source_port = sport;
packet->destination_port = dport;
......@@ -108,13 +119,10 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->overhead = overhead;
packet->size = overhead;
packet->vtag = 0;
packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0;
packet->malloced = 0;
sctp_packet_reset(packet);
return packet;
}
......@@ -123,6 +131,8 @@ void sctp_packet_free(struct sctp_packet *packet)
{
struct sctp_chunk *chunk;
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
sctp_chunk_free(chunk);
......@@ -143,6 +153,9 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
sctp_xmit_t retval;
int error = 0;
SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__,
packet, chunk);
switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
case SCTP_XMIT_PMTU_FULL:
if (!packet->has_cookie_echo) {
......@@ -157,7 +170,6 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
}
break;
case SCTP_XMIT_MUST_FRAG:
case SCTP_XMIT_RWND_FULL:
case SCTP_XMIT_OK:
case SCTP_XMIT_NAGLE_DELAY:
......@@ -210,6 +222,9 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
size_t pmtu;
int too_big;
SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
chunk);
retval = sctp_packet_bundle_sack(packet, chunk);
psize = packet->size;
......@@ -239,9 +254,6 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
retval = SCTP_XMIT_PMTU_FULL;
goto finish;
}
} else {
/* The chunk fits in the packet. */
goto append;
}
append:
......@@ -289,6 +301,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
__u8 has_data = 0;
struct dst_entry *dst;
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
/* Do NOT generate a chunkless packet. */
chunk = (struct sctp_chunk *)skb_peek(&packet->chunks);
if (unlikely(!chunk))
......@@ -510,25 +524,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* 2nd Level Abstractions
********************************************************************/
/*
* This private function resets the packet to a fresh state.
*/
static void sctp_packet_reset(struct sctp_packet *packet)
{
struct sctp_chunk *chunk = NULL;
packet->size = packet->overhead;
if (packet->get_prepend_chunk)
chunk = packet->get_prepend_chunk(packet->transport->asoc);
/* If there a is a prepend chunk stick it on the list before
* any other chunks get appended.
*/
if (chunk)
sctp_packet_append_chunk(packet, chunk);
}
/* This private function handles the specifics of appending DATA chunks. */
static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
struct sctp_chunk *chunk)
......
......@@ -223,12 +223,6 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked);
q->init_output = NULL;
q->config_output = NULL;
q->append_output = NULL;
q->build_output = NULL;
q->force_output = NULL;
q->outstanding_bytes = 0;
q->empty = 1;
q->cork = 0;
......@@ -552,12 +546,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
}
/* Attempt to append this chunk to the packet. */
status = (*q->append_output)(pkt, chunk);
status = sctp_packet_append_chunk(pkt, chunk);
switch (status) {
case SCTP_XMIT_PMTU_FULL:
/* Send this packet. */
if ((error = (*q->force_output)(pkt)) == 0)
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
/* If we are retransmitting, we should only
......@@ -573,7 +567,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
case SCTP_XMIT_RWND_FULL:
/* Send this packet. */
if ((error = (*q->force_output)(pkt)) == 0)
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
/* Stop sending DATA as there is no more room
......@@ -583,6 +577,16 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
lchunk = NULL;
break;
case SCTP_XMIT_NAGLE_DELAY:
/* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
/* Stop sending DATA because of nagle delay. */
list_add(lchunk, lqueue);
lchunk = NULL;
break;
default:
/* The append was successful, so add this chunk to
* the transmitted list.
......@@ -625,13 +629,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
struct sctp_packet *packet;
struct sctp_packet singleton;
struct sctp_association *asoc = q->asoc;
int ecn_capable = asoc->peer.ecn_capable;
__u16 sport = asoc->base.bind_addr.port;
__u16 dport = asoc->peer.port;
__u32 vtag = asoc->peer.i.init_tag;
/* This is the ECNE handler for singleton packets. */
sctp_packet_phandler_t *s_ecne_handler = NULL;
sctp_packet_phandler_t *ecne_handler = NULL;
struct sk_buff_head *queue;
struct sctp_transport *transport = NULL;
struct sctp_transport *new_transport;
......@@ -656,10 +656,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
* within a SCTP packet in increasing order of TSN.
* ...
*/
if (ecn_capable) {
s_ecne_handler = &sctp_get_no_prepend;
ecne_handler = &sctp_get_ecne_prepend;
}
queue = &q->control;
while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) {
......@@ -686,8 +682,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
&transport_list);
}
packet = &transport->packet;
(*q->config_output)(packet, vtag,
ecn_capable, ecne_handler);
sctp_packet_config(packet, vtag,
asoc->peer.ecn_capable);
}
switch (chunk->chunk_hdr->type) {
......@@ -700,11 +696,10 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_SHUTDOWN_COMPLETE:
(*q->init_output)(&singleton, transport, sport, dport);
(*q->config_output)(&singleton, vtag, ecn_capable,
s_ecne_handler);
(void) (*q->build_output)(&singleton, chunk);
error = (*q->force_output)(&singleton);
sctp_packet_init(&singleton, transport, sport, dport);
sctp_packet_config(&singleton, vtag, 0);
sctp_packet_append_chunk(&singleton, chunk);
error = sctp_packet_transmit(&singleton);
if (error < 0)
return error;
break;
......@@ -720,12 +715,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
case SCTP_CID_COOKIE_ACK:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ECN_CWR:
(void) (*q->build_output)(packet, chunk);
break;
case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK:
(void) (*q->build_output)(packet, chunk);
sctp_packet_transmit_chunk(packet, chunk);
break;
default:
......@@ -770,8 +762,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
}
packet = &transport->packet;
(*q->config_output)(packet, vtag,
ecn_capable, ecne_handler);
sctp_packet_config(packet, vtag,
asoc->peer.ecn_capable);
retran:
error = sctp_outq_flush_rtx(q, packet,
rtx_timeout, &start_timer);
......@@ -836,11 +828,11 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
}
packet = &transport->packet;
(*q->config_output)(packet, vtag,
ecn_capable, ecne_handler);
sctp_packet_config(packet, vtag,
asoc->peer.ecn_capable);
}
SCTP_DEBUG_PRINTK("sctp_transmit_packet(%p, %p[%s]), ",
SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",
q, chunk,
chunk && chunk->chunk_hdr ?
sctp_cname(SCTP_ST_CHUNK(
......@@ -855,7 +847,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
atomic_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */
status = (*q->build_output)(packet, chunk);
status = sctp_packet_transmit_chunk(packet, chunk);
switch (status) {
case SCTP_XMIT_PMTU_FULL:
......@@ -879,7 +871,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
BUG();
}
/* BUG: We assume that the (*q->force_output())
/* BUG: We assume that the sctp_packet_transmit()
* call below will succeed all the time and add the
* chunk to the transmitted list and restart the
* timers.
......@@ -922,33 +914,14 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
struct sctp_transport *t = list_entry(ltransport,
struct sctp_transport,
send_ready);
if (t != transport)
transport = t;
packet = &transport->packet;
packet = &t->packet;
if (!sctp_packet_empty(packet))
error = (*q->force_output)(packet);
error = sctp_packet_transmit(packet);
}
return error;
}
/* Set the various output handling callbacks. */
int sctp_outq_set_output_handlers(struct sctp_outq *q,
sctp_outq_ohandler_init_t init,
sctp_outq_ohandler_config_t config,
sctp_outq_ohandler_t append,
sctp_outq_ohandler_t build,
sctp_outq_ohandler_force_t force)
{
q->init_output = init;
q->config_output = config;
q->append_output = append;
q->build_output = build;
q->force_output = force;
return 0;
}
/* Update unack_data based on the incoming SACK chunk */
static void sctp_sack_update_unack_data(struct sctp_association *assoc,
struct sctp_sackhdr *sack)
......
......@@ -4671,28 +4671,20 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
/* Make a transport for the bucket, Eliza... */
transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC);
if (!transport)
goto nomem;
/* Allocate a new packet for sending the response. */
packet = t_new(struct sctp_packet, GFP_ATOMIC);
if (!packet)
goto nomem_packet;
/* Cache a route for the transport with the chunk's destination as
* the source address.
*/
sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
sctp_sk(sctp_get_ctl_sock()));
packet = sctp_packet_init(packet, transport, sport, dport);
packet = sctp_packet_config(packet, vtag, 0, NULL);
packet = sctp_packet_init(&transport->packet, transport, sport, dport);
packet = sctp_packet_config(packet, vtag, 0);
return packet;
nomem_packet:
sctp_transport_free(transport);
nomem:
return NULL;
}
......@@ -4701,7 +4693,6 @@ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
void sctp_ootb_pkt_free(struct sctp_packet *packet)
{
sctp_transport_free(packet->transport);
sctp_packet_free(packet);
}
/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */
......
......@@ -118,7 +118,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
INIT_LIST_HEAD(&peer->transmitted);
INIT_LIST_HEAD(&peer->send_ready);
INIT_LIST_HEAD(&peer->transports);
sctp_packet_init(&peer->packet, peer, 0, 0);
/* Set up the retransmission timer. */
init_timer(&peer->T3_rtx_timer);
......@@ -169,6 +168,8 @@ void sctp_transport_destroy(struct sctp_transport *transport)
if (transport->asoc)
sctp_association_put(transport->asoc);
sctp_packet_free(&transport->packet);
dst_release(transport->dst);
kfree(transport);
SCTP_DBG_OBJCNT_DEC(transport);
......
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