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