linux/net/sctp/tsnmap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* SCTP kernel implementation
   3 * (C) Copyright IBM Corp. 2001, 2004
   4 * Copyright (c) 1999-2000 Cisco, Inc.
   5 * Copyright (c) 1999-2001 Motorola, Inc.
   6 * Copyright (c) 2001 Intel Corp.
   7 *
   8 * This file is part of the SCTP kernel implementation
   9 *
  10 * These functions manipulate sctp tsn mapping array.
  11 *
  12 * Please send any bug reports or fixes you make to the
  13 * email address(es):
  14 *    lksctp developers <linux-sctp@vger.kernel.org>
  15 *
  16 * Written or modified by:
  17 *    La Monte H.P. Yarroll <piggy@acm.org>
  18 *    Jon Grimm             <jgrimm@us.ibm.com>
  19 *    Karl Knutson          <karl@athena.chicago.il.us>
  20 *    Sridhar Samudrala     <sri@us.ibm.com>
  21 */
  22
  23#include <linux/slab.h>
  24#include <linux/types.h>
  25#include <linux/bitmap.h>
  26#include <net/sctp/sctp.h>
  27#include <net/sctp/sm.h>
  28
  29static void sctp_tsnmap_update(struct sctp_tsnmap *map);
  30static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
  31                                     __u16 len, __u16 *start, __u16 *end);
  32static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size);
  33
  34/* Initialize a block of memory as a tsnmap.  */
  35struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
  36                                     __u32 initial_tsn, gfp_t gfp)
  37{
  38        if (!map->tsn_map) {
  39                map->tsn_map = kzalloc(len>>3, gfp);
  40                if (map->tsn_map == NULL)
  41                        return NULL;
  42
  43                map->len = len;
  44        } else {
  45                bitmap_zero(map->tsn_map, map->len);
  46        }
  47
  48        /* Keep track of TSNs represented by tsn_map.  */
  49        map->base_tsn = initial_tsn;
  50        map->cumulative_tsn_ack_point = initial_tsn - 1;
  51        map->max_tsn_seen = map->cumulative_tsn_ack_point;
  52        map->num_dup_tsns = 0;
  53
  54        return map;
  55}
  56
  57void sctp_tsnmap_free(struct sctp_tsnmap *map)
  58{
  59        map->len = 0;
  60        kfree(map->tsn_map);
  61}
  62
  63/* Test the tracking state of this TSN.
  64 * Returns:
  65 *   0 if the TSN has not yet been seen
  66 *  >0 if the TSN has been seen (duplicate)
  67 *  <0 if the TSN is invalid (too large to track)
  68 */
  69int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
  70{
  71        u32 gap;
  72
  73        /* Check to see if this is an old TSN */
  74        if (TSN_lte(tsn, map->cumulative_tsn_ack_point))
  75                return 1;
  76
  77        /* Verify that we can hold this TSN and that it will not
  78         * overflow our map
  79         */
  80        if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
  81                return -1;
  82
  83        /* Calculate the index into the mapping arrays.  */
  84        gap = tsn - map->base_tsn;
  85
  86        /* Check to see if TSN has already been recorded.  */
  87        if (gap < map->len && test_bit(gap, map->tsn_map))
  88                return 1;
  89        else
  90                return 0;
  91}
  92
  93
  94/* Mark this TSN as seen.  */
  95int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
  96                     struct sctp_transport *trans)
  97{
  98        u16 gap;
  99
 100        if (TSN_lt(tsn, map->base_tsn))
 101                return 0;
 102
 103        gap = tsn - map->base_tsn;
 104
 105        if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1))
 106                return -ENOMEM;
 107
 108        if (!sctp_tsnmap_has_gap(map) && gap == 0) {
 109                /* In this case the map has no gaps and the tsn we are
 110                 * recording is the next expected tsn.  We don't touch
 111                 * the map but simply bump the values.
 112                 */
 113                map->max_tsn_seen++;
 114                map->cumulative_tsn_ack_point++;
 115                if (trans)
 116                        trans->sack_generation =
 117                                trans->asoc->peer.sack_generation;
 118                map->base_tsn++;
 119        } else {
 120                /* Either we already have a gap, or about to record a gap, so
 121                 * have work to do.
 122                 *
 123                 * Bump the max.
 124                 */
 125                if (TSN_lt(map->max_tsn_seen, tsn))
 126                        map->max_tsn_seen = tsn;
 127
 128                /* Mark the TSN as received.  */
 129                set_bit(gap, map->tsn_map);
 130
 131                /* Go fixup any internal TSN mapping variables including
 132                 * cumulative_tsn_ack_point.
 133                 */
 134                sctp_tsnmap_update(map);
 135        }
 136
 137        return 0;
 138}
 139
 140
 141/* Initialize a Gap Ack Block iterator from memory being provided.  */
 142static void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
 143                                  struct sctp_tsnmap_iter *iter)
 144{
 145        /* Only start looking one past the Cumulative TSN Ack Point.  */
 146        iter->start = map->cumulative_tsn_ack_point + 1;
 147}
 148
 149/* Get the next Gap Ack Blocks. Returns 0 if there was not another block
 150 * to get.
 151 */
 152static int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
 153                                    struct sctp_tsnmap_iter *iter,
 154                                    __u16 *start, __u16 *end)
 155{
 156        int ended = 0;
 157        __u16 start_ = 0, end_ = 0, offset;
 158
 159        /* If there are no more gap acks possible, get out fast.  */
 160        if (TSN_lte(map->max_tsn_seen, iter->start))
 161                return 0;
 162
 163        offset = iter->start - map->base_tsn;
 164        sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len,
 165                                 &start_, &end_);
 166
 167        /* The Gap Ack Block happens to end at the end of the map. */
 168        if (start_ && !end_)
 169                end_ = map->len - 1;
 170
 171        /* If we found a Gap Ack Block, return the start and end and
 172         * bump the iterator forward.
 173         */
 174        if (end_) {
 175                /* Fix up the start and end based on the
 176                 * Cumulative TSN Ack which is always 1 behind base.
 177                 */
 178                *start = start_ + 1;
 179                *end = end_ + 1;
 180
 181                /* Move the iterator forward.  */
 182                iter->start = map->cumulative_tsn_ack_point + *end + 1;
 183                ended = 1;
 184        }
 185
 186        return ended;
 187}
 188
 189/* Mark this and any lower TSN as seen.  */
 190void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
 191{
 192        u32 gap;
 193
 194        if (TSN_lt(tsn, map->base_tsn))
 195                return;
 196        if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))
 197                return;
 198
 199        /* Bump the max.  */
 200        if (TSN_lt(map->max_tsn_seen, tsn))
 201                map->max_tsn_seen = tsn;
 202
 203        gap = tsn - map->base_tsn + 1;
 204
 205        map->base_tsn += gap;
 206        map->cumulative_tsn_ack_point += gap;
 207        if (gap >= map->len) {
 208                /* If our gap is larger then the map size, just
 209                 * zero out the map.
 210                 */
 211                bitmap_zero(map->tsn_map, map->len);
 212        } else {
 213                /* If the gap is smaller than the map size,
 214                 * shift the map by 'gap' bits and update further.
 215                 */
 216                bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len);
 217                sctp_tsnmap_update(map);
 218        }
 219}
 220
 221/********************************************************************
 222 * 2nd Level Abstractions
 223 ********************************************************************/
 224
 225/* This private helper function updates the tsnmap buffers and
 226 * the Cumulative TSN Ack Point.
 227 */
 228static void sctp_tsnmap_update(struct sctp_tsnmap *map)
 229{
 230        u16 len;
 231        unsigned long zero_bit;
 232
 233
 234        len = map->max_tsn_seen - map->cumulative_tsn_ack_point;
 235        zero_bit = find_first_zero_bit(map->tsn_map, len);
 236        if (!zero_bit)
 237                return;         /* The first 0-bit is bit 0.  nothing to do */
 238
 239        map->base_tsn += zero_bit;
 240        map->cumulative_tsn_ack_point += zero_bit;
 241
 242        bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len);
 243}
 244
 245/* How many data chunks  are we missing from our peer?
 246 */
 247__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
 248{
 249        __u32 cum_tsn = map->cumulative_tsn_ack_point;
 250        __u32 max_tsn = map->max_tsn_seen;
 251        __u32 base_tsn = map->base_tsn;
 252        __u16 pending_data;
 253        u32 gap;
 254
 255        pending_data = max_tsn - cum_tsn;
 256        gap = max_tsn - base_tsn;
 257
 258        if (gap == 0 || gap >= map->len)
 259                goto out;
 260
 261        pending_data -= bitmap_weight(map->tsn_map, gap + 1);
 262out:
 263        return pending_data;
 264}
 265
 266/* This is a private helper for finding Gap Ack Blocks.  It searches a
 267 * single array for the start and end of a Gap Ack Block.
 268 *
 269 * The flags "started" and "ended" tell is if we found the beginning
 270 * or (respectively) the end of a Gap Ack Block.
 271 */
 272static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
 273                                     __u16 len, __u16 *start, __u16 *end)
 274{
 275        int i = off;
 276
 277        /* Look through the entire array, but break out
 278         * early if we have found the end of the Gap Ack Block.
 279         */
 280
 281        /* Also, stop looking past the maximum TSN seen. */
 282
 283        /* Look for the start. */
 284        i = find_next_bit(map, len, off);
 285        if (i < len)
 286                *start = i;
 287
 288        /* Look for the end.  */
 289        if (*start) {
 290                /* We have found the start, let's find the
 291                 * end.  If we find the end, break out.
 292                 */
 293                i = find_next_zero_bit(map, len, i);
 294                if (i < len)
 295                        *end = i - 1;
 296        }
 297}
 298
 299/* Renege that we have seen a TSN.  */
 300void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
 301{
 302        u32 gap;
 303
 304        if (TSN_lt(tsn, map->base_tsn))
 305                return;
 306        /* Assert: TSN is in range.  */
 307        if (!TSN_lt(tsn, map->base_tsn + map->len))
 308                return;
 309
 310        gap = tsn - map->base_tsn;
 311
 312        /* Pretend we never saw the TSN.  */
 313        clear_bit(gap, map->tsn_map);
 314}
 315
 316/* How many gap ack blocks do we have recorded? */
 317__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,
 318                           struct sctp_gap_ack_block *gabs)
 319{
 320        struct sctp_tsnmap_iter iter;
 321        int ngaps = 0;
 322
 323        /* Refresh the gap ack information. */
 324        if (sctp_tsnmap_has_gap(map)) {
 325                __u16 start = 0, end = 0;
 326                sctp_tsnmap_iter_init(map, &iter);
 327                while (sctp_tsnmap_next_gap_ack(map, &iter,
 328                                                &start,
 329                                                &end)) {
 330
 331                        gabs[ngaps].start = htons(start);
 332                        gabs[ngaps].end = htons(end);
 333                        ngaps++;
 334                        if (ngaps >= SCTP_MAX_GABS)
 335                                break;
 336                }
 337        }
 338        return ngaps;
 339}
 340
 341static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size)
 342{
 343        unsigned long *new;
 344        unsigned long inc;
 345        u16  len;
 346
 347        if (size > SCTP_TSN_MAP_SIZE)
 348                return 0;
 349
 350        inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;
 351        len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE);
 352
 353        new = kzalloc(len>>3, GFP_ATOMIC);
 354        if (!new)
 355                return 0;
 356
 357        bitmap_copy(new, map->tsn_map,
 358                map->max_tsn_seen - map->cumulative_tsn_ack_point);
 359        kfree(map->tsn_map);
 360        map->tsn_map = new;
 361        map->len = len;
 362
 363        return 1;
 364}
 365