X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsctp%2Foutqueue.c;h=e5faa351aaadeffd1f1b5a2bc1636c39384d0cae;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=1b2d4adc4ddbaf013e802d8e1da8df756d395e77;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1b2d4adc4..e5faa351a 100644 --- a/net/sctp/outqueue.c +++ b/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); } @@ -399,7 +406,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, * chunks that are not yet acked should be added to the * retransmit queue. */ - if ((fast_retransmit && chunk->fast_retransmit) || + if ((fast_retransmit && (chunk->fast_retransmit > 0)) || (!fast_retransmit && !chunk->tsn_gap_acked)) { /* RFC 2960 6.2.1 Processing a Received SACK * @@ -596,7 +603,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, /* Mark the chunk as ineligible for fast retransmit * after it is retransmitted. */ - chunk->fast_retransmit = 0; + if (chunk->fast_retransmit > 0) + chunk->fast_retransmit = -1; *start_timer = 1; q->empty = 0; @@ -614,7 +622,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, list_for_each(lchunk1, lqueue) { chunk1 = list_entry(lchunk1, struct sctp_chunk, transmitted_list); - chunk1->fast_retransmit = 0; + if (chunk1->fast_retransmit > 0) + chunk1->fast_retransmit = -1; } } } @@ -650,10 +659,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,16 +683,17 @@ 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; if (!new_transport) { new_transport = asoc->peer.active_path; - } else if (!new_transport->active) { - /* If the chunk is Heartbeat or Heartbeat Ack, - * send it to chunk->transport, even if it's + } else if (new_transport->state == SCTP_INACTIVE) { + /* If the chunk is Heartbeat or Heartbeat Ack, + * send it to chunk->transport, even if it's * inactive. * * 3.3.6 Heartbeat Acknowledgement: @@ -814,8 +823,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. @@ -840,7 +847,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - if (!new_transport || !new_transport->active) + if (!new_transport || + new_transport->state == SCTP_INACTIVE) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -1148,8 +1156,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; @@ -1253,6 +1262,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, if (!tchunk->tsn_gap_acked && !tchunk->resent && tchunk->rtt_in_progress) { + tchunk->rtt_in_progress = 0; rtt = jiffies - tchunk->sent_at; sctp_transport_update_rto(transport, rtt); @@ -1454,7 +1464,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, /* Mark the destination transport address as * active if it is not so marked. */ - if (!transport->active) { + if (transport->state == SCTP_INACTIVE) { sctp_assoc_control_transport( transport->asoc, transport, @@ -1555,11 +1565,11 @@ static void sctp_mark_missing(struct sctp_outq *q, /* * M4) If any DATA chunk is found to have a * 'TSN.Missing.Report' - * value larger than or equal to 4, mark that chunk for + * value larger than or equal to 3, mark that chunk for * retransmission and start the fast retransmit procedure. */ - if (chunk->tsn_missing_report >= 4) { + if (chunk->tsn_missing_report >= 3) { chunk->fast_retransmit = 1; do_fast_retransmit = 1; } @@ -1678,9 +1688,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 { @@ -1728,7 +1738,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); } }