xref: /openbmc/linux/net/sctp/tsnmap.c (revision c37fe6aff89cb0d842993fe2f69e48bf3ebe0ab0)
147505b8bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
260c778b2SVlad Yasevich /* SCTP kernel implementation
31da177e4SLinus Torvalds  * (C) Copyright IBM Corp. 2001, 2004
41da177e4SLinus Torvalds  * Copyright (c) 1999-2000 Cisco, Inc.
51da177e4SLinus Torvalds  * Copyright (c) 1999-2001 Motorola, Inc.
61da177e4SLinus Torvalds  * Copyright (c) 2001 Intel Corp.
71da177e4SLinus Torvalds  *
860c778b2SVlad Yasevich  * This file is part of the SCTP kernel implementation
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * These functions manipulate sctp tsn mapping array.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Please send any bug reports or fixes you make to the
131da177e4SLinus Torvalds  * email address(es):
1491705c61SDaniel Borkmann  *    lksctp developers <linux-sctp@vger.kernel.org>
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * Written or modified by:
171da177e4SLinus Torvalds  *    La Monte H.P. Yarroll <piggy@acm.org>
181da177e4SLinus Torvalds  *    Jon Grimm             <jgrimm@us.ibm.com>
191da177e4SLinus Torvalds  *    Karl Knutson          <karl@athena.chicago.il.us>
201da177e4SLinus Torvalds  *    Sridhar Samudrala     <sri@us.ibm.com>
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
235a0e3ad6STejun Heo #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/types.h>
258e1ee18cSVlad Yasevich #include <linux/bitmap.h>
261da177e4SLinus Torvalds #include <net/sctp/sctp.h>
271da177e4SLinus Torvalds #include <net/sctp/sm.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds static void sctp_tsnmap_update(struct sctp_tsnmap *map);
308e1ee18cSVlad Yasevich static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
318e1ee18cSVlad Yasevich 				     __u16 len, __u16 *start, __u16 *end);
3270fc69bcSLee A. Roberts static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size);
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds /* Initialize a block of memory as a tsnmap.  */
sctp_tsnmap_init(struct sctp_tsnmap * map,__u16 len,__u32 initial_tsn,gfp_t gfp)351da177e4SLinus Torvalds struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
368e1ee18cSVlad Yasevich 				     __u32 initial_tsn, gfp_t gfp)
371da177e4SLinus Torvalds {
388e1ee18cSVlad Yasevich 	if (!map->tsn_map) {
398e1ee18cSVlad Yasevich 		map->tsn_map = kzalloc(len>>3, gfp);
408e1ee18cSVlad Yasevich 		if (map->tsn_map == NULL)
418e1ee18cSVlad Yasevich 			return NULL;
421da177e4SLinus Torvalds 
438e1ee18cSVlad Yasevich 		map->len = len;
448e1ee18cSVlad Yasevich 	} else {
458e1ee18cSVlad Yasevich 		bitmap_zero(map->tsn_map, map->len);
468e1ee18cSVlad Yasevich 	}
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	/* Keep track of TSNs represented by tsn_map.  */
491da177e4SLinus Torvalds 	map->base_tsn = initial_tsn;
501da177e4SLinus Torvalds 	map->cumulative_tsn_ack_point = initial_tsn - 1;
511da177e4SLinus Torvalds 	map->max_tsn_seen = map->cumulative_tsn_ack_point;
521da177e4SLinus Torvalds 	map->num_dup_tsns = 0;
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	return map;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
sctp_tsnmap_free(struct sctp_tsnmap * map)578e1ee18cSVlad Yasevich void sctp_tsnmap_free(struct sctp_tsnmap *map)
588e1ee18cSVlad Yasevich {
598e1ee18cSVlad Yasevich 	map->len = 0;
608e1ee18cSVlad Yasevich 	kfree(map->tsn_map);
618e1ee18cSVlad Yasevich }
628e1ee18cSVlad Yasevich 
631da177e4SLinus Torvalds /* Test the tracking state of this TSN.
641da177e4SLinus Torvalds  * Returns:
651da177e4SLinus Torvalds  *   0 if the TSN has not yet been seen
661da177e4SLinus Torvalds  *  >0 if the TSN has been seen (duplicate)
671da177e4SLinus Torvalds  *  <0 if the TSN is invalid (too large to track)
681da177e4SLinus Torvalds  */
sctp_tsnmap_check(const struct sctp_tsnmap * map,__u32 tsn)691da177e4SLinus Torvalds int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
701da177e4SLinus Torvalds {
718e1ee18cSVlad Yasevich 	u32 gap;
728e1ee18cSVlad Yasevich 
738e1ee18cSVlad Yasevich 	/* Check to see if this is an old TSN */
748e1ee18cSVlad Yasevich 	if (TSN_lte(tsn, map->cumulative_tsn_ack_point))
758e1ee18cSVlad Yasevich 		return 1;
768e1ee18cSVlad Yasevich 
778e1ee18cSVlad Yasevich 	/* Verify that we can hold this TSN and that it will not
78*d93ef301SDrew Fustini 	 * overflow our map
798e1ee18cSVlad Yasevich 	 */
808e1ee18cSVlad Yasevich 	if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
818e1ee18cSVlad Yasevich 		return -1;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	/* Calculate the index into the mapping arrays.  */
841da177e4SLinus Torvalds 	gap = tsn - map->base_tsn;
851da177e4SLinus Torvalds 
868e1ee18cSVlad Yasevich 	/* Check to see if TSN has already been recorded.  */
878e1ee18cSVlad Yasevich 	if (gap < map->len && test_bit(gap, map->tsn_map))
888e1ee18cSVlad Yasevich 		return 1;
891da177e4SLinus Torvalds 	else
908e1ee18cSVlad Yasevich 		return 0;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds /* Mark this TSN as seen.  */
sctp_tsnmap_mark(struct sctp_tsnmap * map,__u32 tsn,struct sctp_transport * trans)954244854dSNeil Horman int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
964244854dSNeil Horman 		     struct sctp_transport *trans)
971da177e4SLinus Torvalds {
988e1ee18cSVlad Yasevich 	u16 gap;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	if (TSN_lt(tsn, map->base_tsn))
1018e1ee18cSVlad Yasevich 		return 0;
1021da177e4SLinus Torvalds 
1038e1ee18cSVlad Yasevich 	gap = tsn - map->base_tsn;
1048e1ee18cSVlad Yasevich 
10570fc69bcSLee A. Roberts 	if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1))
1068e1ee18cSVlad Yasevich 		return -ENOMEM;
1078e1ee18cSVlad Yasevich 
1088e1ee18cSVlad Yasevich 	if (!sctp_tsnmap_has_gap(map) && gap == 0) {
1098e1ee18cSVlad Yasevich 		/* In this case the map has no gaps and the tsn we are
1108e1ee18cSVlad Yasevich 		 * recording is the next expected tsn.  We don't touch
1118e1ee18cSVlad Yasevich 		 * the map but simply bump the values.
1128e1ee18cSVlad Yasevich 		 */
1138e1ee18cSVlad Yasevich 		map->max_tsn_seen++;
1148e1ee18cSVlad Yasevich 		map->cumulative_tsn_ack_point++;
1154244854dSNeil Horman 		if (trans)
1164244854dSNeil Horman 			trans->sack_generation =
1174244854dSNeil Horman 				trans->asoc->peer.sack_generation;
1188e1ee18cSVlad Yasevich 		map->base_tsn++;
1198e1ee18cSVlad Yasevich 	} else {
1208e1ee18cSVlad Yasevich 		/* Either we already have a gap, or about to record a gap, so
1218e1ee18cSVlad Yasevich 		 * have work to do.
1228e1ee18cSVlad Yasevich 		 *
1238e1ee18cSVlad Yasevich 		 * Bump the max.
1248e1ee18cSVlad Yasevich 		 */
1251da177e4SLinus Torvalds 		if (TSN_lt(map->max_tsn_seen, tsn))
1261da177e4SLinus Torvalds 			map->max_tsn_seen = tsn;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 		/* Mark the TSN as received.  */
1298e1ee18cSVlad Yasevich 		set_bit(gap, map->tsn_map);
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 		/* Go fixup any internal TSN mapping variables including
1321da177e4SLinus Torvalds 		 * cumulative_tsn_ack_point.
1331da177e4SLinus Torvalds 		 */
1341da177e4SLinus Torvalds 		sctp_tsnmap_update(map);
1351da177e4SLinus Torvalds 	}
1361da177e4SLinus Torvalds 
1378e1ee18cSVlad Yasevich 	return 0;
1388e1ee18cSVlad Yasevich }
1398e1ee18cSVlad Yasevich 
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds /* Initialize a Gap Ack Block iterator from memory being provided.  */
sctp_tsnmap_iter_init(const struct sctp_tsnmap * map,struct sctp_tsnmap_iter * iter)142dda91928SDaniel Borkmann static void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
1431da177e4SLinus Torvalds 				  struct sctp_tsnmap_iter *iter)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds 	/* Only start looking one past the Cumulative TSN Ack Point.  */
1461da177e4SLinus Torvalds 	iter->start = map->cumulative_tsn_ack_point + 1;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /* Get the next Gap Ack Blocks. Returns 0 if there was not another block
1501da177e4SLinus Torvalds  * to get.
1511da177e4SLinus Torvalds  */
sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap * map,struct sctp_tsnmap_iter * iter,__u16 * start,__u16 * end)152dda91928SDaniel Borkmann static int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
1531da177e4SLinus Torvalds 				    struct sctp_tsnmap_iter *iter,
1541da177e4SLinus Torvalds 				    __u16 *start, __u16 *end)
1551da177e4SLinus Torvalds {
1568e1ee18cSVlad Yasevich 	int ended = 0;
1578e1ee18cSVlad Yasevich 	__u16 start_ = 0, end_ = 0, offset;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	/* If there are no more gap acks possible, get out fast.  */
1601da177e4SLinus Torvalds 	if (TSN_lte(map->max_tsn_seen, iter->start))
1611da177e4SLinus Torvalds 		return 0;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	offset = iter->start - map->base_tsn;
1648e1ee18cSVlad Yasevich 	sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len,
1658e1ee18cSVlad Yasevich 				 &start_, &end_);
1661da177e4SLinus Torvalds 
1678e1ee18cSVlad Yasevich 	/* The Gap Ack Block happens to end at the end of the map. */
1688e1ee18cSVlad Yasevich 	if (start_ && !end_)
1698e1ee18cSVlad Yasevich 		end_ = map->len - 1;
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	/* If we found a Gap Ack Block, return the start and end and
1721da177e4SLinus Torvalds 	 * bump the iterator forward.
1731da177e4SLinus Torvalds 	 */
1748e1ee18cSVlad Yasevich 	if (end_) {
1751da177e4SLinus Torvalds 		/* Fix up the start and end based on the
1768e1ee18cSVlad Yasevich 		 * Cumulative TSN Ack which is always 1 behind base.
1771da177e4SLinus Torvalds 		 */
1788e1ee18cSVlad Yasevich 		*start = start_ + 1;
1798e1ee18cSVlad Yasevich 		*end = end_ + 1;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 		/* Move the iterator forward.  */
1821da177e4SLinus Torvalds 		iter->start = map->cumulative_tsn_ack_point + *end + 1;
1838e1ee18cSVlad Yasevich 		ended = 1;
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	return ended;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds /* Mark this and any lower TSN as seen.  */
sctp_tsnmap_skip(struct sctp_tsnmap * map,__u32 tsn)1901da177e4SLinus Torvalds void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
1911da177e4SLinus Torvalds {
1928e1ee18cSVlad Yasevich 	u32 gap;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	if (TSN_lt(tsn, map->base_tsn))
1951da177e4SLinus Torvalds 		return;
1968e1ee18cSVlad Yasevich 	if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
1971da177e4SLinus Torvalds 		return;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	/* Bump the max.  */
2001da177e4SLinus Torvalds 	if (TSN_lt(map->max_tsn_seen, tsn))
2011da177e4SLinus Torvalds 		map->max_tsn_seen = tsn;
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	gap = tsn - map->base_tsn + 1;
2041da177e4SLinus Torvalds 
2058e1ee18cSVlad Yasevich 	map->base_tsn += gap;
2068e1ee18cSVlad Yasevich 	map->cumulative_tsn_ack_point += gap;
2078e1ee18cSVlad Yasevich 	if (gap >= map->len) {
2088e1ee18cSVlad Yasevich 		/* If our gap is larger then the map size, just
2098e1ee18cSVlad Yasevich 		 * zero out the map.
2101da177e4SLinus Torvalds 		 */
2118e1ee18cSVlad Yasevich 		bitmap_zero(map->tsn_map, map->len);
2128e1ee18cSVlad Yasevich 	} else {
213025dfdafSFrederik Schwarzer 		/* If the gap is smaller than the map size,
2148e1ee18cSVlad Yasevich 		 * shift the map by 'gap' bits and update further.
2158e1ee18cSVlad Yasevich 		 */
2168e1ee18cSVlad Yasevich 		bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len);
2171da177e4SLinus Torvalds 		sctp_tsnmap_update(map);
2181da177e4SLinus Torvalds 	}
2198e1ee18cSVlad Yasevich }
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds /********************************************************************
2221da177e4SLinus Torvalds  * 2nd Level Abstractions
2231da177e4SLinus Torvalds  ********************************************************************/
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds /* This private helper function updates the tsnmap buffers and
2261da177e4SLinus Torvalds  * the Cumulative TSN Ack Point.
2271da177e4SLinus Torvalds  */
sctp_tsnmap_update(struct sctp_tsnmap * map)2281da177e4SLinus Torvalds static void sctp_tsnmap_update(struct sctp_tsnmap *map)
2291da177e4SLinus Torvalds {
2308e1ee18cSVlad Yasevich 	u16 len;
2318e1ee18cSVlad Yasevich 	unsigned long zero_bit;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 
2348e1ee18cSVlad Yasevich 	len = map->max_tsn_seen - map->cumulative_tsn_ack_point;
2358e1ee18cSVlad Yasevich 	zero_bit = find_first_zero_bit(map->tsn_map, len);
2368e1ee18cSVlad Yasevich 	if (!zero_bit)
2378e1ee18cSVlad Yasevich 		return;		/* The first 0-bit is bit 0.  nothing to do */
2381da177e4SLinus Torvalds 
2398e1ee18cSVlad Yasevich 	map->base_tsn += zero_bit;
2408e1ee18cSVlad Yasevich 	map->cumulative_tsn_ack_point += zero_bit;
2418e1ee18cSVlad Yasevich 
2428e1ee18cSVlad Yasevich 	bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len);
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds /* How many data chunks  are we missing from our peer?
2461da177e4SLinus Torvalds  */
sctp_tsnmap_pending(struct sctp_tsnmap * map)2471da177e4SLinus Torvalds __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
2481da177e4SLinus Torvalds {
2491da177e4SLinus Torvalds 	__u32 cum_tsn = map->cumulative_tsn_ack_point;
2501da177e4SLinus Torvalds 	__u32 max_tsn = map->max_tsn_seen;
2511da177e4SLinus Torvalds 	__u32 base_tsn = map->base_tsn;
2521da177e4SLinus Torvalds 	__u16 pending_data;
253fc184f08SAkinobu Mita 	u32 gap;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	pending_data = max_tsn - cum_tsn;
2561da177e4SLinus Torvalds 	gap = max_tsn - base_tsn;
2571da177e4SLinus Torvalds 
2588e1ee18cSVlad Yasevich 	if (gap == 0 || gap >= map->len)
2591da177e4SLinus Torvalds 		goto out;
2601da177e4SLinus Torvalds 
261fc184f08SAkinobu Mita 	pending_data -= bitmap_weight(map->tsn_map, gap + 1);
2621da177e4SLinus Torvalds out:
2631da177e4SLinus Torvalds 	return pending_data;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds /* This is a private helper for finding Gap Ack Blocks.  It searches a
2671da177e4SLinus Torvalds  * single array for the start and end of a Gap Ack Block.
2681da177e4SLinus Torvalds  *
2691da177e4SLinus Torvalds  * The flags "started" and "ended" tell is if we found the beginning
2701da177e4SLinus Torvalds  * or (respectively) the end of a Gap Ack Block.
2711da177e4SLinus Torvalds  */
sctp_tsnmap_find_gap_ack(unsigned long * map,__u16 off,__u16 len,__u16 * start,__u16 * end)2728e1ee18cSVlad Yasevich static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
2738e1ee18cSVlad Yasevich 				     __u16 len, __u16 *start, __u16 *end)
2741da177e4SLinus Torvalds {
2751da177e4SLinus Torvalds 	int i = off;
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	/* Look through the entire array, but break out
2781da177e4SLinus Torvalds 	 * early if we have found the end of the Gap Ack Block.
2791da177e4SLinus Torvalds 	 */
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	/* Also, stop looking past the maximum TSN seen. */
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	/* Look for the start. */
2848e1ee18cSVlad Yasevich 	i = find_next_bit(map, len, off);
2858e1ee18cSVlad Yasevich 	if (i < len)
2868e1ee18cSVlad Yasevich 		*start = i;
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds 	/* Look for the end.  */
2898e1ee18cSVlad Yasevich 	if (*start) {
2901da177e4SLinus Torvalds 		/* We have found the start, let's find the
2911da177e4SLinus Torvalds 		 * end.  If we find the end, break out.
2921da177e4SLinus Torvalds 		 */
2938e1ee18cSVlad Yasevich 		i = find_next_zero_bit(map, len, i);
2948e1ee18cSVlad Yasevich 		if (i < len)
2958e1ee18cSVlad Yasevich 			*end = i - 1;
2961da177e4SLinus Torvalds 	}
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds /* Renege that we have seen a TSN.  */
sctp_tsnmap_renege(struct sctp_tsnmap * map,__u32 tsn)3001da177e4SLinus Torvalds void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
3011da177e4SLinus Torvalds {
3028e1ee18cSVlad Yasevich 	u32 gap;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	if (TSN_lt(tsn, map->base_tsn))
3051da177e4SLinus Torvalds 		return;
3068e1ee18cSVlad Yasevich 	/* Assert: TSN is in range.  */
3078e1ee18cSVlad Yasevich 	if (!TSN_lt(tsn, map->base_tsn + map->len))
3081da177e4SLinus Torvalds 		return;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	gap = tsn - map->base_tsn;
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	/* Pretend we never saw the TSN.  */
3138e1ee18cSVlad Yasevich 	clear_bit(gap, map->tsn_map);
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /* How many gap ack blocks do we have recorded? */
sctp_tsnmap_num_gabs(struct sctp_tsnmap * map,struct sctp_gap_ack_block * gabs)31702015180SVlad Yasevich __u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,
31802015180SVlad Yasevich 			   struct sctp_gap_ack_block *gabs)
3191da177e4SLinus Torvalds {
3201da177e4SLinus Torvalds 	struct sctp_tsnmap_iter iter;
32102015180SVlad Yasevich 	int ngaps = 0;
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	/* Refresh the gap ack information. */
3241da177e4SLinus Torvalds 	if (sctp_tsnmap_has_gap(map)) {
32559ed5abaSShan Wei 		__u16 start = 0, end = 0;
3261da177e4SLinus Torvalds 		sctp_tsnmap_iter_init(map, &iter);
3271da177e4SLinus Torvalds 		while (sctp_tsnmap_next_gap_ack(map, &iter,
3289f81bcd9SAl Viro 						&start,
3299f81bcd9SAl Viro 						&end)) {
3301da177e4SLinus Torvalds 
33102015180SVlad Yasevich 			gabs[ngaps].start = htons(start);
33202015180SVlad Yasevich 			gabs[ngaps].end = htons(end);
33302015180SVlad Yasevich 			ngaps++;
33402015180SVlad Yasevich 			if (ngaps >= SCTP_MAX_GABS)
3351da177e4SLinus Torvalds 				break;
3361da177e4SLinus Torvalds 		}
3371da177e4SLinus Torvalds 	}
33802015180SVlad Yasevich 	return ngaps;
3391da177e4SLinus Torvalds }
3408e1ee18cSVlad Yasevich 
sctp_tsnmap_grow(struct sctp_tsnmap * map,u16 size)34170fc69bcSLee A. Roberts static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size)
3428e1ee18cSVlad Yasevich {
3438e1ee18cSVlad Yasevich 	unsigned long *new;
3448e1ee18cSVlad Yasevich 	unsigned long inc;
3458e1ee18cSVlad Yasevich 	u16  len;
3468e1ee18cSVlad Yasevich 
34770fc69bcSLee A. Roberts 	if (size > SCTP_TSN_MAP_SIZE)
3488e1ee18cSVlad Yasevich 		return 0;
3498e1ee18cSVlad Yasevich 
35070fc69bcSLee A. Roberts 	inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;
3518e1ee18cSVlad Yasevich 	len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE);
3528e1ee18cSVlad Yasevich 
3538e1ee18cSVlad Yasevich 	new = kzalloc(len>>3, GFP_ATOMIC);
3548e1ee18cSVlad Yasevich 	if (!new)
3558e1ee18cSVlad Yasevich 		return 0;
3568e1ee18cSVlad Yasevich 
35770fc69bcSLee A. Roberts 	bitmap_copy(new, map->tsn_map,
35870fc69bcSLee A. Roberts 		map->max_tsn_seen - map->cumulative_tsn_ack_point);
3598e1ee18cSVlad Yasevich 	kfree(map->tsn_map);
3608e1ee18cSVlad Yasevich 	map->tsn_map = new;
3618e1ee18cSVlad Yasevich 	map->len = len;
3628e1ee18cSVlad Yasevich 
3638e1ee18cSVlad Yasevich 	return 1;
3648e1ee18cSVlad Yasevich }
365