aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/sctp/ulpqueue.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 63afddcbcd2c..f221fbbc80ac 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -962,8 +962,8 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
962 struct sk_buff_head *list, __u16 needed) 962 struct sk_buff_head *list, __u16 needed)
963{ 963{
964 __u16 freed = 0; 964 __u16 freed = 0;
965 __u32 tsn; 965 __u32 tsn, last_tsn;
966 struct sk_buff *skb; 966 struct sk_buff *skb, *flist, *last;
967 struct sctp_ulpevent *event; 967 struct sctp_ulpevent *event;
968 struct sctp_tsnmap *tsnmap; 968 struct sctp_tsnmap *tsnmap;
969 969
@@ -977,10 +977,28 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
977 if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap))) 977 if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap)))
978 break; 978 break;
979 979
980 __skb_unlink(skb, list); 980 /* Events in ordering queue may have multiple fragments
981 * corresponding to additional TSNs. Sum the total
982 * freed space; find the last TSN.
983 */
981 freed += skb_headlen(skb); 984 freed += skb_headlen(skb);
985 flist = skb_shinfo(skb)->frag_list;
986 for (last = flist; flist; flist = flist->next) {
987 last = flist;
988 freed += skb_headlen(last);
989 }
990 if (last)
991 last_tsn = sctp_skb2event(last)->tsn;
992 else
993 last_tsn = tsn;
994
995 /* Unlink the event, then renege all applicable TSNs. */
996 __skb_unlink(skb, list);
982 sctp_ulpevent_free(event); 997 sctp_ulpevent_free(event);
983 sctp_tsnmap_renege(tsnmap, tsn); 998 while (TSN_lte(tsn, last_tsn)) {
999 sctp_tsnmap_renege(tsnmap, tsn);
1000 tsn++;
1001 }
984 if (freed >= needed) 1002 if (freed >= needed)
985 return freed; 1003 return freed;
986 } 1004 }