[SCTP]: Use struct list_head for chunk lists, not sk_buff_head.
David S. Miller [Sat, 9 Jul 2005 04:47:49 +0000 (21:47 -0700)]
Signed-off-by: David S. Miller <davem@davemloft.net>

include/net/sctp/structs.h
net/sctp/associola.c
net/sctp/input.c
net/sctp/inqueue.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/sm_make_chunk.c
net/sctp/socket.c

index 47727c7..7435528 100644 (file)
@@ -582,7 +582,6 @@ void sctp_datamsg_track(struct sctp_chunk *);
 void sctp_chunk_fail(struct sctp_chunk *, int error);
 int sctp_chunk_abandoned(struct sctp_chunk *);
 
-
 /* RFC2960 1.4 Key Terms
  *
  * o Chunk: A unit of information within an SCTP packet, consisting of
@@ -592,13 +591,8 @@ int sctp_chunk_abandoned(struct sctp_chunk *);
  * each chunk as well as a few other header pointers...
  */
 struct sctp_chunk {
-       /* These first three elements MUST PRECISELY match the first
-        * 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;
+       struct list_head list;
+
        atomic_t refcnt;
 
        /* This is our link to the per-transport transmitted list.  */
@@ -717,7 +711,7 @@ struct sctp_packet {
        __u32 vtag;
 
        /* 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. */
        size_t overhead;
@@ -974,7 +968,7 @@ struct sctp_inq {
        /* This is actually a queue of sctp_chunk each
         * 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
         * being worked on through the inbound chunk processing.
         */
@@ -1017,7 +1011,7 @@ struct sctp_outq {
        struct sctp_association *asoc;
 
        /* 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. */
 
@@ -1025,7 +1019,7 @@ struct sctp_outq {
        unsigned error;
 
        /* 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
         * CTSN, or cumulative tsn ack point.
@@ -1672,7 +1666,7 @@ struct sctp_association {
         *  which already resides in sctp_outq.  Please move this
         *  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
         *
index 7ae6aa7..4b47dd6 100644 (file)
@@ -203,7 +203,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         */
        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.  */
        INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
index 339f7ac..5e085e0 100644 (file)
@@ -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);
 }
 
+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.
  */
@@ -243,6 +254,7 @@ int sctp_rcv(struct sk_buff *skb)
                ret = -ENOMEM;
                goto discard_release;
        }
+       SCTP_INPUT_CB(skb)->chunk = chunk;
 
        sctp_rcv_set_owner_r(skb,sk);
 
@@ -265,9 +277,9 @@ int sctp_rcv(struct sk_buff *skb)
        sctp_bh_lock_sock(sk);
 
        if (sock_owned_by_user(sk))
-               sk_add_backlog(sk, (struct sk_buff *) chunk);
+               sk_add_backlog(sk, skb);
        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
         * lookup calls.
@@ -302,14 +314,8 @@ discard_release:
  */
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
-       struct sctp_chunk *chunk;
-       struct sctp_inq *inqueue;
-
-       /* One day chunk will live inside the skb, but for
-        * now this works.
-        */
-       chunk = (struct sctp_chunk *) skb;
-       inqueue = &chunk->rcvr->inqueue;
+       struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
+       struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
 
        sctp_inq_push(inqueue, chunk);
         return 0;
index cedf435..2d33922 100644 (file)
@@ -50,7 +50,7 @@
 /* Initialize an SCTP inqueue.  */
 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;
 
        /* Create a task for delivering data.  */
@@ -62,11 +62,13 @@ void sctp_inq_init(struct sctp_inq *queue)
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
-       struct sctp_chunk *chunk;
+       struct sctp_chunk *chunk, *tmp;
 
        /* 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);
+       }
 
        /* If there is a packet which is currently being worked on,
         * free it as well.
@@ -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
         * 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);
 }
 
@@ -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? */
        if (!chunk) {
+               struct list_head *entry;
+
                /* Is the queue empty?  */
-               if (skb_queue_empty(&queue->in))
+               if (list_empty(&queue->in_chunk_list))
                        return NULL;
 
+               entry = queue->in_chunk_list.next;
                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.  */
                chunk->singleton = 1;
index 84b5b37..9313716 100644 (file)
@@ -108,7 +108,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
        packet->transport = transport;
        packet->source_port = sport;
        packet->destination_port = dport;
-       skb_queue_head_init(&packet->chunks);
+       INIT_LIST_HEAD(&packet->chunk_list);
        if (asoc) {
                struct sctp_sock *sp = sctp_sk(asoc->base.sk);  
                overhead = sp->pf->af->net_header_len; 
@@ -129,12 +129,14 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
 /* Free a 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);
 
-        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);
+       }
 
        if (packet->malloced)
                kfree(packet);
@@ -276,7 +278,7 @@ append:
                packet->has_sack = 1;
 
        /* 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;
        chunk->transport = packet->transport;
 finish:
@@ -295,7 +297,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        struct sctphdr *sh;
        __u32 crc32;
        struct sk_buff *nskb;
-       struct sctp_chunk *chunk;
+       struct sctp_chunk *chunk, *tmp;
        struct sock *sk;
        int err = 0;
        int padding;            /* How much padding do we need?  */
@@ -305,11 +307,11 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        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))
+       if (list_empty(&packet->chunk_list))
                return err;
 
        /* Set up convenience variables... */
+       chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list);
        sk = chunk->skb->sk;
 
        /* Allocate the new skb.  */
@@ -370,7 +372,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
         * [This whole comment explains WORD_ROUND() below.]
         */
        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 (!chunk->has_tsn) {
@@ -511,7 +514,8 @@ err:
         * 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))
                        sctp_chunk_free(chunk);
        }
index 4eb81a1..efb72fa 100644 (file)
@@ -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,
                                        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;
        return;
 }
@@ -83,17 +83,22 @@ static inline void sctp_outq_head_data(struct sctp_outq *q,
 /* 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)
+       struct sctp_chunk *ch = NULL;
+
+       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;
+       }
        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);
+       list_add_tail(&ch->list, &q->out_chunk_list);
        q->out_qlen += ch->skb->len;
        return;
 }
@@ -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)
 {
        q->asoc = asoc;
-       skb_queue_head_init(&q->out);
-       skb_queue_head_init(&q->control);
+       INIT_LIST_HEAD(&q->out_chunk_list);
+       INIT_LIST_HEAD(&q->control_chunk_list);
        INIT_LIST_HEAD(&q->retransmit);
        INIT_LIST_HEAD(&q->sacked);
        INIT_LIST_HEAD(&q->abandoned);
@@ -217,7 +222,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
 {
        struct sctp_transport *transport;
        struct list_head *lchunk, *pos, *temp;
-       struct sctp_chunk *chunk;
+       struct sctp_chunk *chunk, *tmp;
 
        /* Throw away unacknowledged chunks. */
        list_for_each(pos, &q->asoc->peer.transport_addr_list) {
@@ -269,8 +274,10 @@ void sctp_outq_teardown(struct sctp_outq *q)
        q->error = 0;
 
        /* 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);
+       }
 }
 
 /* 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)
                        break;
                };
        } 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);
        }
 
@@ -650,10 +657,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
        __u16 sport = asoc->base.bind_addr.port;
        __u16 dport = asoc->peer.port;
        __u32 vtag = asoc->peer.i.init_tag;
-       struct sk_buff_head *queue;
        struct sctp_transport *transport = NULL;
        struct sctp_transport *new_transport;
-       struct sctp_chunk *chunk;
+       struct sctp_chunk *chunk, *tmp;
        sctp_xmit_t status;
        int error = 0;
        int start_timer = 0;
@@ -675,8 +681,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
         *   ...
         */
 
-       queue = &q->control;
-       while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) {
+       list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+               list_del_init(&chunk->list);
+
                /* Pick the right transport to use. */
                new_transport = chunk->transport;
 
@@ -814,8 +821,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
 
                /* Finally, transmit new packets.  */
                start_timer = 0;
-               queue = &q->out;
-
                while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
                        /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
                         * stream identifier.
@@ -1149,8 +1154,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        /* See if all chunks are acked.
         * Make sure the empty queue handler will get run later.
         */
-       q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) &&
-                       list_empty(&q->retransmit);
+       q->empty = (list_empty(&q->out_chunk_list) &&
+                   list_empty(&q->control_chunk_list) &&
+                   list_empty(&q->retransmit));
        if (!q->empty)
                goto finish;
 
@@ -1679,9 +1685,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
                if (TSN_lte(tsn, ctsn)) {
                        list_del_init(lchunk);
                        if (!chunk->tsn_gap_acked) {
-                       chunk->transport->flight_size -=
-                                                sctp_data_size(chunk);
-                       q->outstanding_bytes -= sctp_data_size(chunk);
+                               chunk->transport->flight_size -=
+                                       sctp_data_size(chunk);
+                               q->outstanding_bytes -= sctp_data_size(chunk);
                        }
                        sctp_chunk_free(chunk);
                } else {
@@ -1729,7 +1735,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
                                              nskips, &ftsn_skip_arr[0]); 
 
        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);
        }
 }
index 5baed9b..773cd93 100644 (file)
@@ -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);
        }
 
+       INIT_LIST_HEAD(&retval->list);
        retval->skb             = skb;
        retval->asoc            = (struct sctp_association *)asoc;
        retval->resent          = 0;
@@ -1116,8 +1117,7 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
 /* Possibly, free the chunk.  */
 void sctp_chunk_free(struct sctp_chunk *chunk)
 {
-       /* Make sure that we are not on any list.  */
-       skb_unlink((struct sk_buff *) chunk);
+       BUG_ON(!list_empty(&chunk->list));
        list_del_init(&chunk->transmitted_list);
 
        /* Release our reference on the message tracker. */
@@ -2739,8 +2739,12 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
        asoc->addip_last_asconf = NULL;
 
        /* Send the next asconf chunk from the addip chunk queue. */
-       asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks);
-       if (asconf) {
+       if (!list_empty(&asoc->addip_chunk_list)) {
+               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. */
                sctp_chunk_hold(asconf);
                if (sctp_primitive_ASCONF(asoc, asconf))
index aad55dc..091a66f 100644 (file)
@@ -406,7 +406,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
         * transmission.
         */     
        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;       
        }