Skip to content

Commit

Permalink
sctp: fix association hangs due to errors when reneging events from t…
Browse files Browse the repository at this point in the history
…he ordering queue

In sctp_ulpq_renege_list(), events being reneged from the
ordering queue may correspond to multiple TSNs.  Identify
all affected packets; sum freed space and renege from the
tsnmap.

Signed-off-by: Lee A. Roberts <lee.roberts@hp.com>
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
  • Loading branch information
Lee A. Roberts authored and David S. Miller committed Feb 28, 2013
1 parent e67f85e commit 95ac7b8
Showing 1 changed file with 22 additions and 4 deletions.
26 changes: 22 additions & 4 deletions net/sctp/ulpqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,8 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
struct sk_buff_head *list, __u16 needed)
{
__u16 freed = 0;
__u32 tsn;
struct sk_buff *skb;
__u32 tsn, last_tsn;
struct sk_buff *skb, *flist, *last;
struct sctp_ulpevent *event;
struct sctp_tsnmap *tsnmap;

Expand All @@ -977,10 +977,28 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap)))
break;

__skb_unlink(skb, list);
/* Events in ordering queue may have multiple fragments
* corresponding to additional TSNs. Sum the total
* freed space; find the last TSN.
*/
freed += skb_headlen(skb);
flist = skb_shinfo(skb)->frag_list;
for (last = flist; flist; flist = flist->next) {
last = flist;
freed += skb_headlen(last);
}
if (last)
last_tsn = sctp_skb2event(last)->tsn;
else
last_tsn = tsn;

/* Unlink the event, then renege all applicable TSNs. */
__skb_unlink(skb, list);
sctp_ulpevent_free(event);
sctp_tsnmap_renege(tsnmap, tsn);
while (TSN_lte(tsn, last_tsn)) {
sctp_tsnmap_renege(tsnmap, tsn);
tsn++;
}
if (freed >= needed)
return freed;
}
Expand Down

0 comments on commit 95ac7b8

Please sign in to comment.