Browse Source

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

Signed-off-by: David S. Miller <davem@davemloft.net>
David S. Miller 20 years ago
parent
commit
79af02c253
8 changed files with 86 additions and 66 deletions
  1. 7 13
      include/net/sctp/structs.h
  2. 1 1
      net/sctp/associola.c
  3. 16 10
      net/sctp/input.c
  4. 12 6
      net/sctp/inqueue.c
  5. 13 9
      net/sctp/output.c
  6. 28 22
      net/sctp/outqueue.c
  7. 8 4
      net/sctp/sm_make_chunk.c
  8. 1 1
      net/sctp/socket.c

+ 7 - 13
include/net/sctp/structs.h

@@ -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
 	 *

+ 1 - 1
net/sctp/associola.c

@@ -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);

+ 16 - 10
net/sctp/input.c

@@ -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;

+ 12 - 6
net/sctp/inqueue.c

@@ -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;

+ 13 - 9
net/sctp/output.c

@@ -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);
 	}

+ 28 - 22
net/sctp/outqueue.c

@@ -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);
 	}
 }

+ 8 - 4
net/sctp/sm_make_chunk.c

@@ -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))

+ 1 - 1
net/sctp/socket.c

@@ -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;	
 	}