Commit 79af02c2 authored by David S. Miller's avatar David S. Miller

[SCTP]: Use struct list_head for chunk lists, not sk_buff_head.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9c05989b
...@@ -582,7 +582,6 @@ void sctp_datamsg_track(struct sctp_chunk *); ...@@ -582,7 +582,6 @@ void sctp_datamsg_track(struct sctp_chunk *);
void sctp_chunk_fail(struct sctp_chunk *, int error); void sctp_chunk_fail(struct sctp_chunk *, int error);
int sctp_chunk_abandoned(struct sctp_chunk *); int sctp_chunk_abandoned(struct sctp_chunk *);
/* RFC2960 1.4 Key Terms /* RFC2960 1.4 Key Terms
* *
* o Chunk: A unit of information within an SCTP packet, consisting of * o Chunk: A unit of information within an SCTP packet, consisting of
...@@ -592,13 +591,8 @@ int sctp_chunk_abandoned(struct sctp_chunk *); ...@@ -592,13 +591,8 @@ int sctp_chunk_abandoned(struct sctp_chunk *);
* each chunk as well as a few other header pointers... * each chunk as well as a few other header pointers...
*/ */
struct sctp_chunk { struct sctp_chunk {
/* These first three elements MUST PRECISELY match the first struct list_head list;
* three elements of struct sk_buff. This allows us to reuse
* all the skb_* queue management functions.
*/
struct sctp_chunk *next;
struct sctp_chunk *prev;
struct sk_buff_head *list;
atomic_t refcnt; atomic_t refcnt;
/* This is our link to the per-transport transmitted list. */ /* This is our link to the per-transport transmitted list. */
...@@ -717,7 +711,7 @@ struct sctp_packet { ...@@ -717,7 +711,7 @@ struct sctp_packet {
__u32 vtag; __u32 vtag;
/* This contains the payload chunks. */ /* This contains the payload chunks. */
struct sk_buff_head chunks; struct list_head chunk_list;
/* This is the overhead of the sctp and ip headers. */ /* This is the overhead of the sctp and ip headers. */
size_t overhead; size_t overhead;
...@@ -974,7 +968,7 @@ struct sctp_inq { ...@@ -974,7 +968,7 @@ struct sctp_inq {
/* This is actually a queue of sctp_chunk each /* This is actually a queue of sctp_chunk each
* containing a partially decoded packet. * containing a partially decoded packet.
*/ */
struct sk_buff_head in; struct list_head in_chunk_list;
/* This is the packet which is currently off the in queue and is /* This is the packet which is currently off the in queue and is
* being worked on through the inbound chunk processing. * being worked on through the inbound chunk processing.
*/ */
...@@ -1017,7 +1011,7 @@ struct sctp_outq { ...@@ -1017,7 +1011,7 @@ struct sctp_outq {
struct sctp_association *asoc; struct sctp_association *asoc;
/* Data pending that has never been transmitted. */ /* Data pending that has never been transmitted. */
struct sk_buff_head out; struct list_head out_chunk_list;
unsigned out_qlen; /* Total length of queued data chunks. */ unsigned out_qlen; /* Total length of queued data chunks. */
...@@ -1025,7 +1019,7 @@ struct sctp_outq { ...@@ -1025,7 +1019,7 @@ struct sctp_outq {
unsigned error; unsigned error;
/* These are control chunks we want to send. */ /* These are control chunks we want to send. */
struct sk_buff_head control; struct list_head control_chunk_list;
/* These are chunks that have been sacked but are above the /* These are chunks that have been sacked but are above the
* CTSN, or cumulative tsn ack point. * CTSN, or cumulative tsn ack point.
...@@ -1672,7 +1666,7 @@ struct sctp_association { ...@@ -1672,7 +1666,7 @@ struct sctp_association {
* which already resides in sctp_outq. Please move this * which already resides in sctp_outq. Please move this
* queue and its supporting logic down there. --piggy] * queue and its supporting logic down there. --piggy]
*/ */
struct sk_buff_head addip_chunks; struct list_head addip_chunk_list;
/* ADDIP Section 4.1 ASCONF Chunk Procedures /* ADDIP Section 4.1 ASCONF Chunk Procedures
* *
......
...@@ -203,7 +203,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a ...@@ -203,7 +203,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
*/ */
asoc->addip_serial = asoc->c.initial_tsn; asoc->addip_serial = asoc->c.initial_tsn;
skb_queue_head_init(&asoc->addip_chunks); INIT_LIST_HEAD(&asoc->addip_chunk_list);
/* Make an empty list of remote transport addresses. */ /* Make an empty list of remote transport addresses. */
INIT_LIST_HEAD(&asoc->peer.transport_addr_list); INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
......
...@@ -115,6 +115,17 @@ static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk) ...@@ -115,6 +115,17 @@ static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc); atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
} }
struct sctp_input_cb {
union {
struct inet_skb_parm h4;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
struct inet6_skb_parm h6;
#endif
} header;
struct sctp_chunk *chunk;
};
#define SCTP_INPUT_CB(__skb) ((struct sctp_input_cb *)&((__skb)->cb[0]))
/* /*
* This is the routine which IP calls when receiving an SCTP packet. * This is the routine which IP calls when receiving an SCTP packet.
*/ */
...@@ -243,6 +254,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -243,6 +254,7 @@ int sctp_rcv(struct sk_buff *skb)
ret = -ENOMEM; ret = -ENOMEM;
goto discard_release; goto discard_release;
} }
SCTP_INPUT_CB(skb)->chunk = chunk;
sctp_rcv_set_owner_r(skb,sk); sctp_rcv_set_owner_r(skb,sk);
...@@ -265,9 +277,9 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -265,9 +277,9 @@ int sctp_rcv(struct sk_buff *skb)
sctp_bh_lock_sock(sk); sctp_bh_lock_sock(sk);
if (sock_owned_by_user(sk)) if (sock_owned_by_user(sk))
sk_add_backlog(sk, (struct sk_buff *) chunk); sk_add_backlog(sk, skb);
else else
sctp_backlog_rcv(sk, (struct sk_buff *) chunk); sctp_backlog_rcv(sk, skb);
/* Release the sock and any reference counts we took in the /* Release the sock and any reference counts we took in the
* lookup calls. * lookup calls.
...@@ -302,14 +314,8 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -302,14 +314,8 @@ int sctp_rcv(struct sk_buff *skb)
*/ */
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{ {
struct sctp_chunk *chunk; struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
struct sctp_inq *inqueue; struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
/* One day chunk will live inside the skb, but for
* now this works.
*/
chunk = (struct sctp_chunk *) skb;
inqueue = &chunk->rcvr->inqueue;
sctp_inq_push(inqueue, chunk); sctp_inq_push(inqueue, chunk);
return 0; return 0;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
/* Initialize an SCTP inqueue. */ /* Initialize an SCTP inqueue. */
void sctp_inq_init(struct sctp_inq *queue) void sctp_inq_init(struct sctp_inq *queue)
{ {
skb_queue_head_init(&queue->in); INIT_LIST_HEAD(&queue->in_chunk_list);
queue->in_progress = NULL; queue->in_progress = NULL;
/* Create a task for delivering data. */ /* Create a task for delivering data. */
...@@ -62,11 +62,13 @@ void sctp_inq_init(struct sctp_inq *queue) ...@@ -62,11 +62,13 @@ void sctp_inq_init(struct sctp_inq *queue)
/* Release the memory associated with an SCTP inqueue. */ /* Release the memory associated with an SCTP inqueue. */
void sctp_inq_free(struct sctp_inq *queue) void sctp_inq_free(struct sctp_inq *queue)
{ {
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *tmp;
/* Empty the queue. */ /* Empty the queue. */
while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL) list_for_each_entry_safe(chunk, tmp, &queue->in_chunk_list, list) {
list_del_init(&chunk->list);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
}
/* If there is a packet which is currently being worked on, /* If there is a packet which is currently being worked on,
* free it as well. * free it as well.
...@@ -92,7 +94,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) ...@@ -92,7 +94,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet)
* Eventually, we should clean up inqueue to not rely * Eventually, we should clean up inqueue to not rely
* on the BH related data structures. * on the BH related data structures.
*/ */
skb_queue_tail(&(q->in), (struct sk_buff *) packet); list_add_tail(&packet->list, &q->in_chunk_list);
q->immediate.func(q->immediate.data); q->immediate.func(q->immediate.data);
} }
...@@ -131,12 +133,16 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) ...@@ -131,12 +133,16 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
/* Do we need to take the next packet out of the queue to process? */ /* Do we need to take the next packet out of the queue to process? */
if (!chunk) { if (!chunk) {
struct list_head *entry;
/* Is the queue empty? */ /* Is the queue empty? */
if (skb_queue_empty(&queue->in)) if (list_empty(&queue->in_chunk_list))
return NULL; return NULL;
entry = queue->in_chunk_list.next;
chunk = queue->in_progress = chunk = queue->in_progress =
(struct sctp_chunk *) skb_dequeue(&queue->in); list_entry(entry, struct sctp_chunk, list);
list_del_init(entry);
/* This is the first chunk in the packet. */ /* This is the first chunk in the packet. */
chunk->singleton = 1; chunk->singleton = 1;
......
...@@ -108,7 +108,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, ...@@ -108,7 +108,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->transport = transport; packet->transport = transport;
packet->source_port = sport; packet->source_port = sport;
packet->destination_port = dport; packet->destination_port = dport;
skb_queue_head_init(&packet->chunks); INIT_LIST_HEAD(&packet->chunk_list);
if (asoc) { if (asoc) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk); struct sctp_sock *sp = sctp_sk(asoc->base.sk);
overhead = sp->pf->af->net_header_len; overhead = sp->pf->af->net_header_len;
...@@ -129,12 +129,14 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, ...@@ -129,12 +129,14 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
/* Free a packet. */ /* Free a packet. */
void sctp_packet_free(struct sctp_packet *packet) void sctp_packet_free(struct sctp_packet *packet)
{ {
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *tmp;
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
list_del_init(&chunk->list);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
}
if (packet->malloced) if (packet->malloced)
kfree(packet); kfree(packet);
...@@ -276,7 +278,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -276,7 +278,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
packet->has_sack = 1; packet->has_sack = 1;
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); list_add_tail(&chunk->list, &packet->chunk_list);
packet->size += chunk_len; packet->size += chunk_len;
chunk->transport = packet->transport; chunk->transport = packet->transport;
finish: finish:
...@@ -295,7 +297,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -295,7 +297,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
struct sctphdr *sh; struct sctphdr *sh;
__u32 crc32; __u32 crc32;
struct sk_buff *nskb; struct sk_buff *nskb;
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *tmp;
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? */
...@@ -305,11 +307,11 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -305,11 +307,11 @@ int sctp_packet_transmit(struct sctp_packet *packet)
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
/* Do NOT generate a chunkless packet. */ /* Do NOT generate a chunkless packet. */
chunk = (struct sctp_chunk *)skb_peek(&packet->chunks); if (list_empty(&packet->chunk_list))
if (unlikely(!chunk))
return err; return err;
/* Set up convenience variables... */ /* Set up convenience variables... */
chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list);
sk = chunk->skb->sk; sk = chunk->skb->sk;
/* Allocate the new skb. */ /* Allocate the new skb. */
...@@ -370,7 +372,8 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -370,7 +372,8 @@ int sctp_packet_transmit(struct sctp_packet *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 ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
list_del_init(&chunk->list);
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
if (!chunk->has_tsn) { if (!chunk->has_tsn) {
...@@ -511,7 +514,8 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -511,7 +514,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* will get resent or dropped later. * will get resent or dropped later.
*/ */
while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) { list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
list_del_init(&chunk->list);
if (!sctp_chunk_is_data(chunk)) if (!sctp_chunk_is_data(chunk))
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
......
...@@ -75,7 +75,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn); ...@@ -75,7 +75,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
static inline void sctp_outq_head_data(struct sctp_outq *q, static inline void sctp_outq_head_data(struct sctp_outq *q,
struct sctp_chunk *ch) struct sctp_chunk *ch)
{ {
__skb_queue_head(&q->out, (struct sk_buff *)ch); list_add(&ch->list, &q->out_chunk_list);
q->out_qlen += ch->skb->len; q->out_qlen += ch->skb->len;
return; return;
} }
...@@ -83,17 +83,22 @@ static inline void sctp_outq_head_data(struct sctp_outq *q, ...@@ -83,17 +83,22 @@ static inline void sctp_outq_head_data(struct sctp_outq *q,
/* Take data from the front of the queue. */ /* Take data from the front of the queue. */
static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q) static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
{ {
struct sctp_chunk *ch; struct sctp_chunk *ch = NULL;
ch = (struct sctp_chunk *)__skb_dequeue(&q->out);
if (ch) if (!list_empty(&q->out_chunk_list)) {
struct list_head *entry = q->out_chunk_list.next;
ch = list_entry(entry, struct sctp_chunk, list);
list_del_init(entry);
q->out_qlen -= ch->skb->len; q->out_qlen -= ch->skb->len;
}
return ch; return ch;
} }
/* Add data chunk to the end of the queue. */ /* Add data chunk to the end of the queue. */
static inline void sctp_outq_tail_data(struct sctp_outq *q, static inline void sctp_outq_tail_data(struct sctp_outq *q,
struct sctp_chunk *ch) struct sctp_chunk *ch)
{ {
__skb_queue_tail(&q->out, (struct sk_buff *)ch); list_add_tail(&ch->list, &q->out_chunk_list);
q->out_qlen += ch->skb->len; q->out_qlen += ch->skb->len;
return; return;
} }
...@@ -197,8 +202,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary, ...@@ -197,8 +202,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary,
void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
{ {
q->asoc = asoc; q->asoc = asoc;
skb_queue_head_init(&q->out); INIT_LIST_HEAD(&q->out_chunk_list);
skb_queue_head_init(&q->control); INIT_LIST_HEAD(&q->control_chunk_list);
INIT_LIST_HEAD(&q->retransmit); INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked); INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned); INIT_LIST_HEAD(&q->abandoned);
...@@ -217,7 +222,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -217,7 +222,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
{ {
struct sctp_transport *transport; struct sctp_transport *transport;
struct list_head *lchunk, *pos, *temp; struct list_head *lchunk, *pos, *temp;
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *tmp;
/* Throw away unacknowledged chunks. */ /* Throw away unacknowledged chunks. */
list_for_each(pos, &q->asoc->peer.transport_addr_list) { list_for_each(pos, &q->asoc->peer.transport_addr_list) {
...@@ -269,8 +274,10 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -269,8 +274,10 @@ void sctp_outq_teardown(struct sctp_outq *q)
q->error = 0; q->error = 0;
/* Throw away any leftover control chunks. */ /* Throw away any leftover control chunks. */
while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL) list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
list_del_init(&chunk->list);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
}
} }
/* Free the outqueue structure and any related pending chunks. */ /* Free the outqueue structure and any related pending chunks. */
...@@ -333,7 +340,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -333,7 +340,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
break; break;
}; };
} else { } else {
__skb_queue_tail(&q->control, (struct sk_buff *) chunk); list_add_tail(&chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
} }
...@@ -650,10 +657,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -650,10 +657,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
__u16 sport = asoc->base.bind_addr.port; __u16 sport = asoc->base.bind_addr.port;
__u16 dport = asoc->peer.port; __u16 dport = asoc->peer.port;
__u32 vtag = asoc->peer.i.init_tag; __u32 vtag = asoc->peer.i.init_tag;
struct sk_buff_head *queue;
struct sctp_transport *transport = NULL; struct sctp_transport *transport = NULL;
struct sctp_transport *new_transport; struct sctp_transport *new_transport;
struct sctp_chunk *chunk; struct sctp_chunk *chunk, *tmp;
sctp_xmit_t status; sctp_xmit_t status;
int error = 0; int error = 0;
int start_timer = 0; int start_timer = 0;
...@@ -675,8 +681,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -675,8 +681,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
* ... * ...
*/ */
queue = &q->control; list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) { list_del_init(&chunk->list);
/* Pick the right transport to use. */ /* Pick the right transport to use. */
new_transport = chunk->transport; new_transport = chunk->transport;
...@@ -814,8 +821,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -814,8 +821,6 @@ 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;
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
/* 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.
...@@ -1149,8 +1154,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1149,8 +1154,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
/* See if all chunks are acked. /* See if all chunks are acked.
* Make sure the empty queue handler will get run later. * Make sure the empty queue handler will get run later.
*/ */
q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) && q->empty = (list_empty(&q->out_chunk_list) &&
list_empty(&q->retransmit); list_empty(&q->control_chunk_list) &&
list_empty(&q->retransmit));
if (!q->empty) if (!q->empty)
goto finish; goto finish;
...@@ -1679,9 +1685,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) ...@@ -1679,9 +1685,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
if (TSN_lte(tsn, ctsn)) { if (TSN_lte(tsn, ctsn)) {
list_del_init(lchunk); list_del_init(lchunk);
if (!chunk->tsn_gap_acked) { if (!chunk->tsn_gap_acked) {
chunk->transport->flight_size -= chunk->transport->flight_size -=
sctp_data_size(chunk); sctp_data_size(chunk);
q->outstanding_bytes -= sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk);
} }
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} else { } else {
...@@ -1729,7 +1735,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) ...@@ -1729,7 +1735,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
nskips, &ftsn_skip_arr[0]); nskips, &ftsn_skip_arr[0]);
if (ftsn_chunk) { if (ftsn_chunk) {
__skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk); list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
} }
} }
...@@ -1003,6 +1003,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, ...@@ -1003,6 +1003,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
} }
INIT_LIST_HEAD(&retval->list);
retval->skb = skb; retval->skb = skb;
retval->asoc = (struct sctp_association *)asoc; retval->asoc = (struct sctp_association *)asoc;
retval->resent = 0; retval->resent = 0;
...@@ -1116,8 +1117,7 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk) ...@@ -1116,8 +1117,7 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
/* Possibly, free the chunk. */ /* Possibly, free the chunk. */
void sctp_chunk_free(struct sctp_chunk *chunk) void sctp_chunk_free(struct sctp_chunk *chunk)
{ {
/* Make sure that we are not on any list. */ BUG_ON(!list_empty(&chunk->list));
skb_unlink((struct sk_buff *) chunk);
list_del_init(&chunk->transmitted_list); list_del_init(&chunk->transmitted_list);
/* Release our reference on the message tracker. */ /* Release our reference on the message tracker. */
...@@ -2739,8 +2739,12 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, ...@@ -2739,8 +2739,12 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
asoc->addip_last_asconf = NULL; asoc->addip_last_asconf = NULL;
/* Send the next asconf chunk from the addip chunk queue. */ /* Send the next asconf chunk from the addip chunk queue. */
asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks); if (!list_empty(&asoc->addip_chunk_list)) {
if (asconf) { struct list_head *entry = asoc->addip_chunk_list.next;
asconf = list_entry(entry, struct sctp_chunk, list);
list_del_init(entry);
/* Hold the chunk until an ASCONF_ACK is received. */ /* Hold the chunk until an ASCONF_ACK is received. */
sctp_chunk_hold(asconf); sctp_chunk_hold(asconf);
if (sctp_primitive_ASCONF(asoc, asconf)) if (sctp_primitive_ASCONF(asoc, asconf))
......
...@@ -406,7 +406,7 @@ static int sctp_send_asconf(struct sctp_association *asoc, ...@@ -406,7 +406,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
* transmission. * transmission.
*/ */
if (asoc->addip_last_asconf) { if (asoc->addip_last_asconf) {
__skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk); list_add_tail(&chunk->list, &asoc->addip_chunk_list);
goto out; goto out;
} }
......
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