diff options
Diffstat (limited to 'net/sctp/outqueue.c')
| -rw-r--r-- | net/sctp/outqueue.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 4eb81a1407b7..efb72faba20c 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); | |||
| 75 | static inline void sctp_outq_head_data(struct sctp_outq *q, | 75 | static inline void sctp_outq_head_data(struct sctp_outq *q, |
| 76 | struct sctp_chunk *ch) | 76 | struct sctp_chunk *ch) |
| 77 | { | 77 | { |
| 78 | __skb_queue_head(&q->out, (struct sk_buff *)ch); | 78 | list_add(&ch->list, &q->out_chunk_list); |
| 79 | q->out_qlen += ch->skb->len; | 79 | q->out_qlen += ch->skb->len; |
| 80 | return; | 80 | return; |
| 81 | } | 81 | } |
| @@ -83,17 +83,22 @@ static inline void sctp_outq_head_data(struct sctp_outq *q, | |||
| 83 | /* Take data from the front of the queue. */ | 83 | /* Take data from the front of the queue. */ |
| 84 | static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q) | 84 | static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q) |
| 85 | { | 85 | { |
| 86 | struct sctp_chunk *ch; | 86 | struct sctp_chunk *ch = NULL; |
| 87 | ch = (struct sctp_chunk *)__skb_dequeue(&q->out); | 87 | |
| 88 | if (ch) | 88 | if (!list_empty(&q->out_chunk_list)) { |
| 89 | struct list_head *entry = q->out_chunk_list.next; | ||
| 90 | |||
| 91 | ch = list_entry(entry, struct sctp_chunk, list); | ||
| 92 | list_del_init(entry); | ||
| 89 | q->out_qlen -= ch->skb->len; | 93 | q->out_qlen -= ch->skb->len; |
| 94 | } | ||
| 90 | return ch; | 95 | return ch; |
| 91 | } | 96 | } |
| 92 | /* Add data chunk to the end of the queue. */ | 97 | /* Add data chunk to the end of the queue. */ |
| 93 | static inline void sctp_outq_tail_data(struct sctp_outq *q, | 98 | static inline void sctp_outq_tail_data(struct sctp_outq *q, |
| 94 | struct sctp_chunk *ch) | 99 | struct sctp_chunk *ch) |
| 95 | { | 100 | { |
| 96 | __skb_queue_tail(&q->out, (struct sk_buff *)ch); | 101 | list_add_tail(&ch->list, &q->out_chunk_list); |
| 97 | q->out_qlen += ch->skb->len; | 102 | q->out_qlen += ch->skb->len; |
| 98 | return; | 103 | return; |
| 99 | } | 104 | } |
| @@ -197,8 +202,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary, | |||
| 197 | void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) | 202 | void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) |
| 198 | { | 203 | { |
| 199 | q->asoc = asoc; | 204 | q->asoc = asoc; |
| 200 | skb_queue_head_init(&q->out); | 205 | INIT_LIST_HEAD(&q->out_chunk_list); |
| 201 | skb_queue_head_init(&q->control); | 206 | INIT_LIST_HEAD(&q->control_chunk_list); |
| 202 | INIT_LIST_HEAD(&q->retransmit); | 207 | INIT_LIST_HEAD(&q->retransmit); |
| 203 | INIT_LIST_HEAD(&q->sacked); | 208 | INIT_LIST_HEAD(&q->sacked); |
| 204 | INIT_LIST_HEAD(&q->abandoned); | 209 | INIT_LIST_HEAD(&q->abandoned); |
| @@ -217,7 +222,7 @@ void sctp_outq_teardown(struct sctp_outq *q) | |||
| 217 | { | 222 | { |
| 218 | struct sctp_transport *transport; | 223 | struct sctp_transport *transport; |
| 219 | struct list_head *lchunk, *pos, *temp; | 224 | struct list_head *lchunk, *pos, *temp; |
| 220 | struct sctp_chunk *chunk; | 225 | struct sctp_chunk *chunk, *tmp; |
| 221 | 226 | ||
| 222 | /* Throw away unacknowledged chunks. */ | 227 | /* Throw away unacknowledged chunks. */ |
| 223 | list_for_each(pos, &q->asoc->peer.transport_addr_list) { | 228 | list_for_each(pos, &q->asoc->peer.transport_addr_list) { |
| @@ -269,8 +274,10 @@ void sctp_outq_teardown(struct sctp_outq *q) | |||
| 269 | q->error = 0; | 274 | q->error = 0; |
| 270 | 275 | ||
| 271 | /* Throw away any leftover control chunks. */ | 276 | /* Throw away any leftover control chunks. */ |
| 272 | while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL) | 277 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { |
| 278 | list_del_init(&chunk->list); | ||
| 273 | sctp_chunk_free(chunk); | 279 | sctp_chunk_free(chunk); |
| 280 | } | ||
| 274 | } | 281 | } |
| 275 | 282 | ||
| 276 | /* Free the outqueue structure and any related pending chunks. */ | 283 | /* 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 | break; | 340 | break; |
| 334 | }; | 341 | }; |
| 335 | } else { | 342 | } else { |
| 336 | __skb_queue_tail(&q->control, (struct sk_buff *) chunk); | 343 | list_add_tail(&chunk->list, &q->control_chunk_list); |
| 337 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 344 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
| 338 | } | 345 | } |
| 339 | 346 | ||
| @@ -650,10 +657,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
| 650 | __u16 sport = asoc->base.bind_addr.port; | 657 | __u16 sport = asoc->base.bind_addr.port; |
| 651 | __u16 dport = asoc->peer.port; | 658 | __u16 dport = asoc->peer.port; |
| 652 | __u32 vtag = asoc->peer.i.init_tag; | 659 | __u32 vtag = asoc->peer.i.init_tag; |
| 653 | struct sk_buff_head *queue; | ||
| 654 | struct sctp_transport *transport = NULL; | 660 | struct sctp_transport *transport = NULL; |
| 655 | struct sctp_transport *new_transport; | 661 | struct sctp_transport *new_transport; |
| 656 | struct sctp_chunk *chunk; | 662 | struct sctp_chunk *chunk, *tmp; |
| 657 | sctp_xmit_t status; | 663 | sctp_xmit_t status; |
| 658 | int error = 0; | 664 | int error = 0; |
| 659 | int start_timer = 0; | 665 | int start_timer = 0; |
| @@ -675,8 +681,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
| 675 | * ... | 681 | * ... |
| 676 | */ | 682 | */ |
| 677 | 683 | ||
| 678 | queue = &q->control; | 684 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { |
| 679 | while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) { | 685 | list_del_init(&chunk->list); |
| 686 | |||
| 680 | /* Pick the right transport to use. */ | 687 | /* Pick the right transport to use. */ |
| 681 | new_transport = chunk->transport; | 688 | new_transport = chunk->transport; |
| 682 | 689 | ||
| @@ -814,8 +821,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
| 814 | 821 | ||
| 815 | /* Finally, transmit new packets. */ | 822 | /* Finally, transmit new packets. */ |
| 816 | start_timer = 0; | 823 | start_timer = 0; |
| 817 | queue = &q->out; | ||
| 818 | |||
| 819 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { | 824 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { |
| 820 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 825 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
| 821 | * stream identifier. | 826 | * stream identifier. |
| @@ -1149,8 +1154,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) | |||
| 1149 | /* See if all chunks are acked. | 1154 | /* See if all chunks are acked. |
| 1150 | * Make sure the empty queue handler will get run later. | 1155 | * Make sure the empty queue handler will get run later. |
| 1151 | */ | 1156 | */ |
| 1152 | q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) && | 1157 | q->empty = (list_empty(&q->out_chunk_list) && |
| 1153 | list_empty(&q->retransmit); | 1158 | list_empty(&q->control_chunk_list) && |
| 1159 | list_empty(&q->retransmit)); | ||
| 1154 | if (!q->empty) | 1160 | if (!q->empty) |
| 1155 | goto finish; | 1161 | goto finish; |
| 1156 | 1162 | ||
| @@ -1679,9 +1685,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) | |||
| 1679 | if (TSN_lte(tsn, ctsn)) { | 1685 | if (TSN_lte(tsn, ctsn)) { |
| 1680 | list_del_init(lchunk); | 1686 | list_del_init(lchunk); |
| 1681 | if (!chunk->tsn_gap_acked) { | 1687 | if (!chunk->tsn_gap_acked) { |
| 1682 | chunk->transport->flight_size -= | 1688 | chunk->transport->flight_size -= |
| 1683 | sctp_data_size(chunk); | 1689 | sctp_data_size(chunk); |
| 1684 | q->outstanding_bytes -= sctp_data_size(chunk); | 1690 | q->outstanding_bytes -= sctp_data_size(chunk); |
| 1685 | } | 1691 | } |
| 1686 | sctp_chunk_free(chunk); | 1692 | sctp_chunk_free(chunk); |
| 1687 | } else { | 1693 | } else { |
| @@ -1729,7 +1735,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) | |||
| 1729 | nskips, &ftsn_skip_arr[0]); | 1735 | nskips, &ftsn_skip_arr[0]); |
| 1730 | 1736 | ||
| 1731 | if (ftsn_chunk) { | 1737 | if (ftsn_chunk) { |
| 1732 | __skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk); | 1738 | list_add_tail(&ftsn_chunk->list, &q->control_chunk_list); |
| 1733 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 1739 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
| 1734 | } | 1740 | } |
| 1735 | } | 1741 | } |
