sctp: fix association hangs due to errors when reneging events from the 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>
This commit is contained in:
parent
e67f85ecd8
commit
95ac7b859f
|
@ -962,8 +962,8 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
|
||||||
struct sk_buff_head *list, __u16 needed)
|
struct sk_buff_head *list, __u16 needed)
|
||||||
{
|
{
|
||||||
__u16 freed = 0;
|
__u16 freed = 0;
|
||||||
__u32 tsn;
|
__u32 tsn, last_tsn;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb, *flist, *last;
|
||||||
struct sctp_ulpevent *event;
|
struct sctp_ulpevent *event;
|
||||||
struct sctp_tsnmap *tsnmap;
|
struct sctp_tsnmap *tsnmap;
|
||||||
|
|
||||||
|
@ -977,10 +977,28 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
|
||||||
if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap)))
|
if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap)))
|
||||||
break;
|
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);
|
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_ulpevent_free(event);
|
||||||
sctp_tsnmap_renege(tsnmap, tsn);
|
while (TSN_lte(tsn, last_tsn)) {
|
||||||
|
sctp_tsnmap_renege(tsnmap, tsn);
|
||||||
|
tsn++;
|
||||||
|
}
|
||||||
if (freed >= needed)
|
if (freed >= needed)
|
||||||
return freed;
|
return freed;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue