162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2001, 2004 462306a36Sopenharmony_ci * Copyright (c) 1999-2000 Cisco, Inc. 562306a36Sopenharmony_ci * Copyright (c) 1999-2001 Motorola, Inc. 662306a36Sopenharmony_ci * Copyright (c) 2001 Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * These functions manipulate sctp tsn mapping array. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 1362306a36Sopenharmony_ci * email address(es): 1462306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Written or modified by: 1762306a36Sopenharmony_ci * La Monte H.P. Yarroll <piggy@acm.org> 1862306a36Sopenharmony_ci * Jon Grimm <jgrimm@us.ibm.com> 1962306a36Sopenharmony_ci * Karl Knutson <karl@athena.chicago.il.us> 2062306a36Sopenharmony_ci * Sridhar Samudrala <sri@us.ibm.com> 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/types.h> 2562306a36Sopenharmony_ci#include <linux/bitmap.h> 2662306a36Sopenharmony_ci#include <net/sctp/sctp.h> 2762306a36Sopenharmony_ci#include <net/sctp/sm.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void sctp_tsnmap_update(struct sctp_tsnmap *map); 3062306a36Sopenharmony_cistatic void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off, 3162306a36Sopenharmony_ci __u16 len, __u16 *start, __u16 *end); 3262306a36Sopenharmony_cistatic int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Initialize a block of memory as a tsnmap. */ 3562306a36Sopenharmony_cistruct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len, 3662306a36Sopenharmony_ci __u32 initial_tsn, gfp_t gfp) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci if (!map->tsn_map) { 3962306a36Sopenharmony_ci map->tsn_map = kzalloc(len>>3, gfp); 4062306a36Sopenharmony_ci if (map->tsn_map == NULL) 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci map->len = len; 4462306a36Sopenharmony_ci } else { 4562306a36Sopenharmony_ci bitmap_zero(map->tsn_map, map->len); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Keep track of TSNs represented by tsn_map. */ 4962306a36Sopenharmony_ci map->base_tsn = initial_tsn; 5062306a36Sopenharmony_ci map->cumulative_tsn_ack_point = initial_tsn - 1; 5162306a36Sopenharmony_ci map->max_tsn_seen = map->cumulative_tsn_ack_point; 5262306a36Sopenharmony_ci map->num_dup_tsns = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return map; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_civoid sctp_tsnmap_free(struct sctp_tsnmap *map) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci map->len = 0; 6062306a36Sopenharmony_ci kfree(map->tsn_map); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Test the tracking state of this TSN. 6462306a36Sopenharmony_ci * Returns: 6562306a36Sopenharmony_ci * 0 if the TSN has not yet been seen 6662306a36Sopenharmony_ci * >0 if the TSN has been seen (duplicate) 6762306a36Sopenharmony_ci * <0 if the TSN is invalid (too large to track) 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ciint sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci u32 gap; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Check to see if this is an old TSN */ 7462306a36Sopenharmony_ci if (TSN_lte(tsn, map->cumulative_tsn_ack_point)) 7562306a36Sopenharmony_ci return 1; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Verify that we can hold this TSN and that it will not 7862306a36Sopenharmony_ci * overflow our map 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE)) 8162306a36Sopenharmony_ci return -1; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Calculate the index into the mapping arrays. */ 8462306a36Sopenharmony_ci gap = tsn - map->base_tsn; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Check to see if TSN has already been recorded. */ 8762306a36Sopenharmony_ci if (gap < map->len && test_bit(gap, map->tsn_map)) 8862306a36Sopenharmony_ci return 1; 8962306a36Sopenharmony_ci else 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* Mark this TSN as seen. */ 9562306a36Sopenharmony_ciint sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn, 9662306a36Sopenharmony_ci struct sctp_transport *trans) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci u16 gap; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci gap = tsn - map->base_tsn; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1)) 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!sctp_tsnmap_has_gap(map) && gap == 0) { 10962306a36Sopenharmony_ci /* In this case the map has no gaps and the tsn we are 11062306a36Sopenharmony_ci * recording is the next expected tsn. We don't touch 11162306a36Sopenharmony_ci * the map but simply bump the values. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci map->max_tsn_seen++; 11462306a36Sopenharmony_ci map->cumulative_tsn_ack_point++; 11562306a36Sopenharmony_ci if (trans) 11662306a36Sopenharmony_ci trans->sack_generation = 11762306a36Sopenharmony_ci trans->asoc->peer.sack_generation; 11862306a36Sopenharmony_ci map->base_tsn++; 11962306a36Sopenharmony_ci } else { 12062306a36Sopenharmony_ci /* Either we already have a gap, or about to record a gap, so 12162306a36Sopenharmony_ci * have work to do. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * Bump the max. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci if (TSN_lt(map->max_tsn_seen, tsn)) 12662306a36Sopenharmony_ci map->max_tsn_seen = tsn; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Mark the TSN as received. */ 12962306a36Sopenharmony_ci set_bit(gap, map->tsn_map); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Go fixup any internal TSN mapping variables including 13262306a36Sopenharmony_ci * cumulative_tsn_ack_point. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci sctp_tsnmap_update(map); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* Initialize a Gap Ack Block iterator from memory being provided. */ 14262306a36Sopenharmony_cistatic void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map, 14362306a36Sopenharmony_ci struct sctp_tsnmap_iter *iter) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci /* Only start looking one past the Cumulative TSN Ack Point. */ 14662306a36Sopenharmony_ci iter->start = map->cumulative_tsn_ack_point + 1; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Get the next Gap Ack Blocks. Returns 0 if there was not another block 15062306a36Sopenharmony_ci * to get. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map, 15362306a36Sopenharmony_ci struct sctp_tsnmap_iter *iter, 15462306a36Sopenharmony_ci __u16 *start, __u16 *end) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci int ended = 0; 15762306a36Sopenharmony_ci __u16 start_ = 0, end_ = 0, offset; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* If there are no more gap acks possible, get out fast. */ 16062306a36Sopenharmony_ci if (TSN_lte(map->max_tsn_seen, iter->start)) 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci offset = iter->start - map->base_tsn; 16462306a36Sopenharmony_ci sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 16562306a36Sopenharmony_ci &start_, &end_); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* The Gap Ack Block happens to end at the end of the map. */ 16862306a36Sopenharmony_ci if (start_ && !end_) 16962306a36Sopenharmony_ci end_ = map->len - 1; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* If we found a Gap Ack Block, return the start and end and 17262306a36Sopenharmony_ci * bump the iterator forward. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci if (end_) { 17562306a36Sopenharmony_ci /* Fix up the start and end based on the 17662306a36Sopenharmony_ci * Cumulative TSN Ack which is always 1 behind base. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci *start = start_ + 1; 17962306a36Sopenharmony_ci *end = end_ + 1; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Move the iterator forward. */ 18262306a36Sopenharmony_ci iter->start = map->cumulative_tsn_ack_point + *end + 1; 18362306a36Sopenharmony_ci ended = 1; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return ended; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* Mark this and any lower TSN as seen. */ 19062306a36Sopenharmony_civoid sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci u32 gap; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE)) 19762306a36Sopenharmony_ci return; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Bump the max. */ 20062306a36Sopenharmony_ci if (TSN_lt(map->max_tsn_seen, tsn)) 20162306a36Sopenharmony_ci map->max_tsn_seen = tsn; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci gap = tsn - map->base_tsn + 1; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci map->base_tsn += gap; 20662306a36Sopenharmony_ci map->cumulative_tsn_ack_point += gap; 20762306a36Sopenharmony_ci if (gap >= map->len) { 20862306a36Sopenharmony_ci /* If our gap is larger then the map size, just 20962306a36Sopenharmony_ci * zero out the map. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci bitmap_zero(map->tsn_map, map->len); 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci /* If the gap is smaller than the map size, 21462306a36Sopenharmony_ci * shift the map by 'gap' bits and update further. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len); 21762306a36Sopenharmony_ci sctp_tsnmap_update(map); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/******************************************************************** 22262306a36Sopenharmony_ci * 2nd Level Abstractions 22362306a36Sopenharmony_ci ********************************************************************/ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* This private helper function updates the tsnmap buffers and 22662306a36Sopenharmony_ci * the Cumulative TSN Ack Point. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistatic void sctp_tsnmap_update(struct sctp_tsnmap *map) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci u16 len; 23162306a36Sopenharmony_ci unsigned long zero_bit; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci len = map->max_tsn_seen - map->cumulative_tsn_ack_point; 23562306a36Sopenharmony_ci zero_bit = find_first_zero_bit(map->tsn_map, len); 23662306a36Sopenharmony_ci if (!zero_bit) 23762306a36Sopenharmony_ci return; /* The first 0-bit is bit 0. nothing to do */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci map->base_tsn += zero_bit; 24062306a36Sopenharmony_ci map->cumulative_tsn_ack_point += zero_bit; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* How many data chunks are we missing from our peer? 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci __u32 cum_tsn = map->cumulative_tsn_ack_point; 25062306a36Sopenharmony_ci __u32 max_tsn = map->max_tsn_seen; 25162306a36Sopenharmony_ci __u32 base_tsn = map->base_tsn; 25262306a36Sopenharmony_ci __u16 pending_data; 25362306a36Sopenharmony_ci u32 gap; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci pending_data = max_tsn - cum_tsn; 25662306a36Sopenharmony_ci gap = max_tsn - base_tsn; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (gap == 0 || gap >= map->len) 25962306a36Sopenharmony_ci goto out; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci pending_data -= bitmap_weight(map->tsn_map, gap + 1); 26262306a36Sopenharmony_ciout: 26362306a36Sopenharmony_ci return pending_data; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* This is a private helper for finding Gap Ack Blocks. It searches a 26762306a36Sopenharmony_ci * single array for the start and end of a Gap Ack Block. 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * The flags "started" and "ended" tell is if we found the beginning 27062306a36Sopenharmony_ci * or (respectively) the end of a Gap Ack Block. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistatic void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off, 27362306a36Sopenharmony_ci __u16 len, __u16 *start, __u16 *end) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int i = off; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Look through the entire array, but break out 27862306a36Sopenharmony_ci * early if we have found the end of the Gap Ack Block. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Also, stop looking past the maximum TSN seen. */ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Look for the start. */ 28462306a36Sopenharmony_ci i = find_next_bit(map, len, off); 28562306a36Sopenharmony_ci if (i < len) 28662306a36Sopenharmony_ci *start = i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Look for the end. */ 28962306a36Sopenharmony_ci if (*start) { 29062306a36Sopenharmony_ci /* We have found the start, let's find the 29162306a36Sopenharmony_ci * end. If we find the end, break out. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci i = find_next_zero_bit(map, len, i); 29462306a36Sopenharmony_ci if (i < len) 29562306a36Sopenharmony_ci *end = i - 1; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* Renege that we have seen a TSN. */ 30062306a36Sopenharmony_civoid sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci u32 gap; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (TSN_lt(tsn, map->base_tsn)) 30562306a36Sopenharmony_ci return; 30662306a36Sopenharmony_ci /* Assert: TSN is in range. */ 30762306a36Sopenharmony_ci if (!TSN_lt(tsn, map->base_tsn + map->len)) 30862306a36Sopenharmony_ci return; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci gap = tsn - map->base_tsn; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Pretend we never saw the TSN. */ 31362306a36Sopenharmony_ci clear_bit(gap, map->tsn_map); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* How many gap ack blocks do we have recorded? */ 31762306a36Sopenharmony_ci__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map, 31862306a36Sopenharmony_ci struct sctp_gap_ack_block *gabs) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct sctp_tsnmap_iter iter; 32162306a36Sopenharmony_ci int ngaps = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Refresh the gap ack information. */ 32462306a36Sopenharmony_ci if (sctp_tsnmap_has_gap(map)) { 32562306a36Sopenharmony_ci __u16 start = 0, end = 0; 32662306a36Sopenharmony_ci sctp_tsnmap_iter_init(map, &iter); 32762306a36Sopenharmony_ci while (sctp_tsnmap_next_gap_ack(map, &iter, 32862306a36Sopenharmony_ci &start, 32962306a36Sopenharmony_ci &end)) { 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci gabs[ngaps].start = htons(start); 33262306a36Sopenharmony_ci gabs[ngaps].end = htons(end); 33362306a36Sopenharmony_ci ngaps++; 33462306a36Sopenharmony_ci if (ngaps >= SCTP_MAX_GABS) 33562306a36Sopenharmony_ci break; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci return ngaps; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci unsigned long *new; 34462306a36Sopenharmony_ci unsigned long inc; 34562306a36Sopenharmony_ci u16 len; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (size > SCTP_TSN_MAP_SIZE) 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT; 35162306a36Sopenharmony_ci len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci new = kzalloc(len>>3, GFP_ATOMIC); 35462306a36Sopenharmony_ci if (!new) 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci bitmap_copy(new, map->tsn_map, 35862306a36Sopenharmony_ci map->max_tsn_seen - map->cumulative_tsn_ack_point); 35962306a36Sopenharmony_ci kfree(map->tsn_map); 36062306a36Sopenharmony_ci map->tsn_map = new; 36162306a36Sopenharmony_ci map->len = len; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 1; 36462306a36Sopenharmony_ci} 365