diff options
| author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2007-12-16 14:05:45 -0800 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2007-12-16 14:05:45 -0800 | 
| commit | ef5d4cf2f9aae4e09883d2d664e367a16b47d857 (patch) | |
| tree | b6e83cf4f8b975c8bec0045c8a74d11496524f10 /net | |
| parent | 215f7b08f2a142ec19f4bd3d6de263e68b877955 (diff) | |
| download | olio-linux-3.10-ef5d4cf2f9aae4e09883d2d664e367a16b47d857.tar.xz olio-linux-3.10-ef5d4cf2f9aae4e09883d2d664e367a16b47d857.zip  | |
[SCTP]: Flush fragment queue when exiting partial delivery.
At the end of partial delivery, we may have complete messages
sitting on the fragment queue.  These messages are stuck there
until a new fragment arrives.  This can comletely stall a
given association.  When clearing partial delivery state, flush
any complete messages from the fragment queue and send them on
their way up.
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/sctp/ulpqueue.c | 33 | 
1 files changed, 33 insertions, 0 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 4908041ffb3..1733fa29a50 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -53,6 +53,7 @@ static struct sctp_ulpevent * sctp_ulpq_reasm(struct sctp_ulpq *ulpq,  					      struct sctp_ulpevent *);  static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *,  					      struct sctp_ulpevent *); +static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq);  /* 1st Level Abstractions */ @@ -190,6 +191,7 @@ static void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq)  static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)  {  	ulpq->pd_mode = 0; +	sctp_ulpq_reasm_drain(ulpq);  	return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc);  } @@ -699,6 +701,37 @@ void sctp_ulpq_reasm_flushtsn(struct sctp_ulpq *ulpq, __u32 fwd_tsn)  	}  } +/* + * Drain the reassembly queue.  If we just cleared parted delivery, it + * is possible that the reassembly queue will contain already reassembled + * messages.  Retrieve any such messages and give them to the user. + */ +static void sctp_ulpq_reasm_drain(struct sctp_ulpq *ulpq) +{ +	struct sctp_ulpevent *event = NULL; +	struct sk_buff_head temp; + +	if (skb_queue_empty(&ulpq->reasm)) +		return; + +	while ((event = sctp_ulpq_retrieve_reassembled(ulpq)) != NULL) { +		/* Do ordering if needed.  */ +		if ((event) && (event->msg_flags & MSG_EOR)){ +			skb_queue_head_init(&temp); +			__skb_queue_tail(&temp, sctp_event2skb(event)); + +			event = sctp_ulpq_order(ulpq, event); +		} + +		/* Send event to the ULP.  'event' is the +		 * sctp_ulpevent for  very first SKB on the  temp' list. +		 */ +		if (event) +			sctp_ulpq_tail_event(ulpq, event); +	} +} + +  /* Helper function to gather skbs that have possibly become   * ordered by an an incoming chunk.   */  |