18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 48c2ecf20Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * These functions manipulate sctp tsn mapping array. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 138c2ecf20Sopenharmony_ci * email address(es): 148c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Written or modified by: 178c2ecf20Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 188c2ecf20Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 198c2ecf20Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 208c2ecf20Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/types.h> 258c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 268c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 278c2ecf20Sopenharmony_ci#include <net/sctp/sm.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic void sctp_tsnmap_update(struct sctp_tsnmap *map); 308c2ecf20Sopenharmony_cistatic void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off, 318c2ecf20Sopenharmony_ci __u16 len, __u16 *start, __u16 *end); 328c2ecf20Sopenharmony_cistatic int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Initialize a block of memory as a tsnmap. */ 358c2ecf20Sopenharmony_cistruct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len, 368c2ecf20Sopenharmony_ci __u32 initial_tsn, gfp_t gfp) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (!map->tsn_map) { 398c2ecf20Sopenharmony_ci map->tsn_map = kzalloc(len>>3, gfp); 408c2ecf20Sopenharmony_ci if (map->tsn_map == NULL) 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci map->len = len; 448c2ecf20Sopenharmony_ci } else { 458c2ecf20Sopenharmony_ci bitmap_zero(map->tsn_map, map->len); 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Keep track of TSNs represented by tsn_map. */ 498c2ecf20Sopenharmony_ci map->base_tsn = initial_tsn; 508c2ecf20Sopenharmony_ci map->cumulative_tsn_ack_point = initial_tsn - 1; 518c2ecf20Sopenharmony_ci map->max_tsn_seen = map->cumulative_tsn_ack_point; 528c2ecf20Sopenharmony_ci map->num_dup_tsns = 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return map; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_civoid sctp_tsnmap_free(struct sctp_tsnmap *map) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci map->len = 0; 608c2ecf20Sopenharmony_ci kfree(map->tsn_map); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Test the tracking state of this TSN. 648c2ecf20Sopenharmony_ci * Returns: 658c2ecf20Sopenharmony_ci * 0 if the TSN has not yet been seen 668c2ecf20Sopenharmony_ci * >0 if the TSN has been seen (duplicate) 678c2ecf20Sopenharmony_ci * <0 if the TSN is invalid (too large to track) 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ciint sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci u32 gap; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Check to see if this is an old TSN */ 748c2ecf20Sopenharmony_ci if (TSN_lte(tsn, map->cumulative_tsn_ack_point)) 758c2ecf20Sopenharmony_ci return 1; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Verify that we can hold this TSN and that it will not 788c2ecf20Sopenharmony_ci * overlfow our map 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE)) 818c2ecf20Sopenharmony_ci return -1; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Calculate the index into the mapping arrays. */ 848c2ecf20Sopenharmony_ci gap = tsn - map->base_tsn; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Check to see if TSN has already been recorded. */ 878c2ecf20Sopenharmony_ci if (gap < map->len && test_bit(gap, map->tsn_map)) 888c2ecf20Sopenharmony_ci return 1; 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Mark this TSN as seen. */ 958c2ecf20Sopenharmony_ciint sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn, 968c2ecf20Sopenharmony_ci struct sctp_transport *trans) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u16 gap; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci gap = tsn - map->base_tsn; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1)) 1068c2ecf20Sopenharmony_ci return -ENOMEM; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!sctp_tsnmap_has_gap(map) && gap == 0) { 1098c2ecf20Sopenharmony_ci /* In this case the map has no gaps and the tsn we are 1108c2ecf20Sopenharmony_ci * recording is the next expected tsn. We don't touch 1118c2ecf20Sopenharmony_ci * the map but simply bump the values. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci map->max_tsn_seen++; 1148c2ecf20Sopenharmony_ci map->cumulative_tsn_ack_point++; 1158c2ecf20Sopenharmony_ci if (trans) 1168c2ecf20Sopenharmony_ci trans->sack_generation = 1178c2ecf20Sopenharmony_ci trans->asoc->peer.sack_generation; 1188c2ecf20Sopenharmony_ci map->base_tsn++; 1198c2ecf20Sopenharmony_ci } else { 1208c2ecf20Sopenharmony_ci /* Either we already have a gap, or about to record a gap, so 1218c2ecf20Sopenharmony_ci * have work to do. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * Bump the max. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci if (TSN_lt(map->max_tsn_seen, tsn)) 1268c2ecf20Sopenharmony_ci map->max_tsn_seen = tsn; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* Mark the TSN as received. */ 1298c2ecf20Sopenharmony_ci set_bit(gap, map->tsn_map); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Go fixup any internal TSN mapping variables including 1328c2ecf20Sopenharmony_ci * cumulative_tsn_ack_point. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci sctp_tsnmap_update(map); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* Initialize a Gap Ack Block iterator from memory being provided. */ 1428c2ecf20Sopenharmony_cistatic void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map, 1438c2ecf20Sopenharmony_ci struct sctp_tsnmap_iter *iter) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci /* Only start looking one past the Cumulative TSN Ack Point. */ 1468c2ecf20Sopenharmony_ci iter->start = map->cumulative_tsn_ack_point + 1; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* Get the next Gap Ack Blocks. Returns 0 if there was not another block 1508c2ecf20Sopenharmony_ci * to get. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_cistatic int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, 1538c2ecf20Sopenharmony_ci struct sctp_tsnmap_iter *iter, 1548c2ecf20Sopenharmony_ci __u16 *start, __u16 *end) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci int ended = 0; 1578c2ecf20Sopenharmony_ci __u16 start_ = 0, end_ = 0, offset; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* If there are no more gap acks possible, get out fast. */ 1608c2ecf20Sopenharmony_ci if (TSN_lte(map->max_tsn_seen, iter->start)) 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci offset = iter->start - map->base_tsn; 1648c2ecf20Sopenharmony_ci sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 1658c2ecf20Sopenharmony_ci &start_, &end_); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* The Gap Ack Block happens to end at the end of the map. */ 1688c2ecf20Sopenharmony_ci if (start_ && !end_) 1698c2ecf20Sopenharmony_ci end_ = map->len - 1; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* If we found a Gap Ack Block, return the start and end and 1728c2ecf20Sopenharmony_ci * bump the iterator forward. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci if (end_) { 1758c2ecf20Sopenharmony_ci /* Fix up the start and end based on the 1768c2ecf20Sopenharmony_ci * Cumulative TSN Ack which is always 1 behind base. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci *start = start_ + 1; 1798c2ecf20Sopenharmony_ci *end = end_ + 1; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Move the iterator forward. */ 1828c2ecf20Sopenharmony_ci iter->start = map->cumulative_tsn_ack_point + *end + 1; 1838c2ecf20Sopenharmony_ci ended = 1; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return ended; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* Mark this and any lower TSN as seen. */ 1908c2ecf20Sopenharmony_civoid sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci u32 gap; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 1958c2ecf20Sopenharmony_ci return; 1968c2ecf20Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE)) 1978c2ecf20Sopenharmony_ci return; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Bump the max. */ 2008c2ecf20Sopenharmony_ci if (TSN_lt(map->max_tsn_seen, tsn)) 2018c2ecf20Sopenharmony_ci map->max_tsn_seen = tsn; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci gap = tsn - map->base_tsn + 1; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci map->base_tsn += gap; 2068c2ecf20Sopenharmony_ci map->cumulative_tsn_ack_point += gap; 2078c2ecf20Sopenharmony_ci if (gap >= map->len) { 2088c2ecf20Sopenharmony_ci /* If our gap is larger then the map size, just 2098c2ecf20Sopenharmony_ci * zero out the map. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci bitmap_zero(map->tsn_map, map->len); 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci /* If the gap is smaller than the map size, 2148c2ecf20Sopenharmony_ci * shift the map by 'gap' bits and update further. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len); 2178c2ecf20Sopenharmony_ci sctp_tsnmap_update(map); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/******************************************************************** 2228c2ecf20Sopenharmony_ci * 2nd Level Abstractions 2238c2ecf20Sopenharmony_ci ********************************************************************/ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* This private helper function updates the tsnmap buffers and 2268c2ecf20Sopenharmony_ci * the Cumulative TSN Ack Point. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic void sctp_tsnmap_update(struct sctp_tsnmap *map) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci u16 len; 2318c2ecf20Sopenharmony_ci unsigned long zero_bit; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci len = map->max_tsn_seen - map->cumulative_tsn_ack_point; 2358c2ecf20Sopenharmony_ci zero_bit = find_first_zero_bit(map->tsn_map, len); 2368c2ecf20Sopenharmony_ci if (!zero_bit) 2378c2ecf20Sopenharmony_ci return; /* The first 0-bit is bit 0. nothing to do */ 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci map->base_tsn += zero_bit; 2408c2ecf20Sopenharmony_ci map->cumulative_tsn_ack_point += zero_bit; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/* How many data chunks are we missing from our peer? 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci __u32 cum_tsn = map->cumulative_tsn_ack_point; 2508c2ecf20Sopenharmony_ci __u32 max_tsn = map->max_tsn_seen; 2518c2ecf20Sopenharmony_ci __u32 base_tsn = map->base_tsn; 2528c2ecf20Sopenharmony_ci __u16 pending_data; 2538c2ecf20Sopenharmony_ci u32 gap; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci pending_data = max_tsn - cum_tsn; 2568c2ecf20Sopenharmony_ci gap = max_tsn - base_tsn; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (gap == 0 || gap >= map->len) 2598c2ecf20Sopenharmony_ci goto out; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci pending_data -= bitmap_weight(map->tsn_map, gap + 1); 2628c2ecf20Sopenharmony_ciout: 2638c2ecf20Sopenharmony_ci return pending_data; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* This is a private helper for finding Gap Ack Blocks. It searches a 2678c2ecf20Sopenharmony_ci * single array for the start and end of a Gap Ack Block. 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * The flags "started" and "ended" tell is if we found the beginning 2708c2ecf20Sopenharmony_ci * or (respectively) the end of a Gap Ack Block. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off, 2738c2ecf20Sopenharmony_ci __u16 len, __u16 *start, __u16 *end) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int i = off; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Look through the entire array, but break out 2788c2ecf20Sopenharmony_ci * early if we have found the end of the Gap Ack Block. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Also, stop looking past the maximum TSN seen. */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Look for the start. */ 2848c2ecf20Sopenharmony_ci i = find_next_bit(map, len, off); 2858c2ecf20Sopenharmony_ci if (i < len) 2868c2ecf20Sopenharmony_ci *start = i; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Look for the end. */ 2898c2ecf20Sopenharmony_ci if (*start) { 2908c2ecf20Sopenharmony_ci /* We have found the start, let's find the 2918c2ecf20Sopenharmony_ci * end. If we find the end, break out. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci i = find_next_zero_bit(map, len, i); 2948c2ecf20Sopenharmony_ci if (i < len) 2958c2ecf20Sopenharmony_ci *end = i - 1; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* Renege that we have seen a TSN. */ 3008c2ecf20Sopenharmony_civoid sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci u32 gap; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci /* Assert: TSN is in range. */ 3078c2ecf20Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + map->len)) 3088c2ecf20Sopenharmony_ci return; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci gap = tsn - map->base_tsn; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* Pretend we never saw the TSN. */ 3138c2ecf20Sopenharmony_ci clear_bit(gap, map->tsn_map); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* How many gap ack blocks do we have recorded? */ 3178c2ecf20Sopenharmony_ci__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map, 3188c2ecf20Sopenharmony_ci struct sctp_gap_ack_block *gabs) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct sctp_tsnmap_iter iter; 3218c2ecf20Sopenharmony_ci int ngaps = 0; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Refresh the gap ack information. */ 3248c2ecf20Sopenharmony_ci if (sctp_tsnmap_has_gap(map)) { 3258c2ecf20Sopenharmony_ci __u16 start = 0, end = 0; 3268c2ecf20Sopenharmony_ci sctp_tsnmap_iter_init(map, &iter); 3278c2ecf20Sopenharmony_ci while (sctp_tsnmap_next_gap_ack(map, &iter, 3288c2ecf20Sopenharmony_ci &start, 3298c2ecf20Sopenharmony_ci &end)) { 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci gabs[ngaps].start = htons(start); 3328c2ecf20Sopenharmony_ci gabs[ngaps].end = htons(end); 3338c2ecf20Sopenharmony_ci ngaps++; 3348c2ecf20Sopenharmony_ci if (ngaps >= SCTP_MAX_GABS) 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci return ngaps; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci unsigned long *new; 3448c2ecf20Sopenharmony_ci unsigned long inc; 3458c2ecf20Sopenharmony_ci u16 len; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (size > SCTP_TSN_MAP_SIZE) 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT; 3518c2ecf20Sopenharmony_ci len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci new = kzalloc(len>>3, GFP_ATOMIC); 3548c2ecf20Sopenharmony_ci if (!new) 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci bitmap_copy(new, map->tsn_map, 3588c2ecf20Sopenharmony_ci map->max_tsn_seen - map->cumulative_tsn_ack_point); 3598c2ecf20Sopenharmony_ci kfree(map->tsn_map); 3608c2ecf20Sopenharmony_ci map->tsn_map = new; 3618c2ecf20Sopenharmony_ci map->len = len; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 1; 3648c2ecf20Sopenharmony_ci} 365