/* SCTP kernel implementation1* (C) Copyright IBM Corp. 2001, 20042* Copyright (c) 1999-2000 Cisco, Inc.3* Copyright (c) 1999-2001 Motorola, Inc.4* Copyright (c) 2001 Intel Corp.5*6* This file is part of the SCTP kernel implementation7*8* These functions manipulate sctp tsn mapping array.9*10* This SCTP implementation is free software;11* you can redistribute it and/or modify it under the terms of12* the GNU General Public License as published by13* the Free Software Foundation; either version 2, or (at your option)14* any later version.15*16* This SCTP implementation is distributed in the hope that it17* will be useful, but WITHOUT ANY WARRANTY; without even the implied18* ************************19* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.20* See the GNU General Public License for more details.21*22* You should have received a copy of the GNU General Public License23* along with GNU CC; see the file COPYING. If not, write to24* the Free Software Foundation, 59 Temple Place - Suite 330,25* Boston, MA 02111-1307, USA.26*27* Please send any bug reports or fixes you make to the28* email address(es):29* lksctp developers <[email protected]>30*31* Or submit a bug report through the following website:32* http://www.sf.net/projects/lksctp33*34* Written or modified by:35* La Monte H.P. Yarroll <[email protected]>36* Jon Grimm <[email protected]>37* Karl Knutson <[email protected]>38* Sridhar Samudrala <[email protected]>39*40* Any bugs reported given to us we will try to fix... any fixes shared will41* be incorporated into the next SCTP release.42*/4344#include <linux/slab.h>45#include <linux/types.h>46#include <linux/bitmap.h>47#include <net/sctp/sctp.h>48#include <net/sctp/sm.h>4950static void sctp_tsnmap_update(struct sctp_tsnmap *map);51static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,52__u16 len, __u16 *start, __u16 *end);53static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap);5455/* Initialize a block of memory as a tsnmap. */56struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,57__u32 initial_tsn, gfp_t gfp)58{59if (!map->tsn_map) {60map->tsn_map = kzalloc(len>>3, gfp);61if (map->tsn_map == NULL)62return NULL;6364map->len = len;65} else {66bitmap_zero(map->tsn_map, map->len);67}6869/* Keep track of TSNs represented by tsn_map. */70map->base_tsn = initial_tsn;71map->cumulative_tsn_ack_point = initial_tsn - 1;72map->max_tsn_seen = map->cumulative_tsn_ack_point;73map->num_dup_tsns = 0;7475return map;76}7778void sctp_tsnmap_free(struct sctp_tsnmap *map)79{80map->len = 0;81kfree(map->tsn_map);82}8384/* Test the tracking state of this TSN.85* Returns:86* 0 if the TSN has not yet been seen87* >0 if the TSN has been seen (duplicate)88* <0 if the TSN is invalid (too large to track)89*/90int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)91{92u32 gap;9394/* Check to see if this is an old TSN */95if (TSN_lte(tsn, map->cumulative_tsn_ack_point))96return 1;9798/* Verify that we can hold this TSN and that it will not99* overlfow our map100*/101if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))102return -1;103104/* Calculate the index into the mapping arrays. */105gap = tsn - map->base_tsn;106107/* Check to see if TSN has already been recorded. */108if (gap < map->len && test_bit(gap, map->tsn_map))109return 1;110else111return 0;112}113114115/* Mark this TSN as seen. */116int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)117{118u16 gap;119120if (TSN_lt(tsn, map->base_tsn))121return 0;122123gap = tsn - map->base_tsn;124125if (gap >= map->len && !sctp_tsnmap_grow(map, gap))126return -ENOMEM;127128if (!sctp_tsnmap_has_gap(map) && gap == 0) {129/* In this case the map has no gaps and the tsn we are130* recording is the next expected tsn. We don't touch131* the map but simply bump the values.132*/133map->max_tsn_seen++;134map->cumulative_tsn_ack_point++;135map->base_tsn++;136} else {137/* Either we already have a gap, or about to record a gap, so138* have work to do.139*140* Bump the max.141*/142if (TSN_lt(map->max_tsn_seen, tsn))143map->max_tsn_seen = tsn;144145/* Mark the TSN as received. */146set_bit(gap, map->tsn_map);147148/* Go fixup any internal TSN mapping variables including149* cumulative_tsn_ack_point.150*/151sctp_tsnmap_update(map);152}153154return 0;155}156157158/* Initialize a Gap Ack Block iterator from memory being provided. */159SCTP_STATIC void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,160struct sctp_tsnmap_iter *iter)161{162/* Only start looking one past the Cumulative TSN Ack Point. */163iter->start = map->cumulative_tsn_ack_point + 1;164}165166/* Get the next Gap Ack Blocks. Returns 0 if there was not another block167* to get.168*/169SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,170struct sctp_tsnmap_iter *iter,171__u16 *start, __u16 *end)172{173int ended = 0;174__u16 start_ = 0, end_ = 0, offset;175176/* If there are no more gap acks possible, get out fast. */177if (TSN_lte(map->max_tsn_seen, iter->start))178return 0;179180offset = iter->start - map->base_tsn;181sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len,182&start_, &end_);183184/* The Gap Ack Block happens to end at the end of the map. */185if (start_ && !end_)186end_ = map->len - 1;187188/* If we found a Gap Ack Block, return the start and end and189* bump the iterator forward.190*/191if (end_) {192/* Fix up the start and end based on the193* Cumulative TSN Ack which is always 1 behind base.194*/195*start = start_ + 1;196*end = end_ + 1;197198/* Move the iterator forward. */199iter->start = map->cumulative_tsn_ack_point + *end + 1;200ended = 1;201}202203return ended;204}205206/* Mark this and any lower TSN as seen. */207void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)208{209u32 gap;210211if (TSN_lt(tsn, map->base_tsn))212return;213if (!TSN_lt(tsn, map->base_tsn + SCTP_TSN_MAP_SIZE))214return;215216/* Bump the max. */217if (TSN_lt(map->max_tsn_seen, tsn))218map->max_tsn_seen = tsn;219220gap = tsn - map->base_tsn + 1;221222map->base_tsn += gap;223map->cumulative_tsn_ack_point += gap;224if (gap >= map->len) {225/* If our gap is larger then the map size, just226* zero out the map.227*/228bitmap_zero(map->tsn_map, map->len);229} else {230/* If the gap is smaller than the map size,231* shift the map by 'gap' bits and update further.232*/233bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len);234sctp_tsnmap_update(map);235}236}237238/********************************************************************239* 2nd Level Abstractions240********************************************************************/241242/* This private helper function updates the tsnmap buffers and243* the Cumulative TSN Ack Point.244*/245static void sctp_tsnmap_update(struct sctp_tsnmap *map)246{247u16 len;248unsigned long zero_bit;249250251len = map->max_tsn_seen - map->cumulative_tsn_ack_point;252zero_bit = find_first_zero_bit(map->tsn_map, len);253if (!zero_bit)254return; /* The first 0-bit is bit 0. nothing to do */255256map->base_tsn += zero_bit;257map->cumulative_tsn_ack_point += zero_bit;258259bitmap_shift_right(map->tsn_map, map->tsn_map, zero_bit, map->len);260}261262/* How many data chunks are we missing from our peer?263*/264__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)265{266__u32 cum_tsn = map->cumulative_tsn_ack_point;267__u32 max_tsn = map->max_tsn_seen;268__u32 base_tsn = map->base_tsn;269__u16 pending_data;270u32 gap, i;271272pending_data = max_tsn - cum_tsn;273gap = max_tsn - base_tsn;274275if (gap == 0 || gap >= map->len)276goto out;277278for (i = 0; i < gap+1; i++) {279if (test_bit(i, map->tsn_map))280pending_data--;281}282283out:284return pending_data;285}286287/* This is a private helper for finding Gap Ack Blocks. It searches a288* single array for the start and end of a Gap Ack Block.289*290* The flags "started" and "ended" tell is if we found the beginning291* or (respectively) the end of a Gap Ack Block.292*/293static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,294__u16 len, __u16 *start, __u16 *end)295{296int i = off;297298/* Look through the entire array, but break out299* early if we have found the end of the Gap Ack Block.300*/301302/* Also, stop looking past the maximum TSN seen. */303304/* Look for the start. */305i = find_next_bit(map, len, off);306if (i < len)307*start = i;308309/* Look for the end. */310if (*start) {311/* We have found the start, let's find the312* end. If we find the end, break out.313*/314i = find_next_zero_bit(map, len, i);315if (i < len)316*end = i - 1;317}318}319320/* Renege that we have seen a TSN. */321void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)322{323u32 gap;324325if (TSN_lt(tsn, map->base_tsn))326return;327/* Assert: TSN is in range. */328if (!TSN_lt(tsn, map->base_tsn + map->len))329return;330331gap = tsn - map->base_tsn;332333/* Pretend we never saw the TSN. */334clear_bit(gap, map->tsn_map);335}336337/* How many gap ack blocks do we have recorded? */338__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,339struct sctp_gap_ack_block *gabs)340{341struct sctp_tsnmap_iter iter;342int ngaps = 0;343344/* Refresh the gap ack information. */345if (sctp_tsnmap_has_gap(map)) {346__u16 start = 0, end = 0;347sctp_tsnmap_iter_init(map, &iter);348while (sctp_tsnmap_next_gap_ack(map, &iter,349&start,350&end)) {351352gabs[ngaps].start = htons(start);353gabs[ngaps].end = htons(end);354ngaps++;355if (ngaps >= SCTP_MAX_GABS)356break;357}358}359return ngaps;360}361362static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap)363{364unsigned long *new;365unsigned long inc;366u16 len;367368if (gap >= SCTP_TSN_MAP_SIZE)369return 0;370371inc = ALIGN((gap - map->len),BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;372len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE);373374new = kzalloc(len>>3, GFP_ATOMIC);375if (!new)376return 0;377378bitmap_copy(new, map->tsn_map, map->max_tsn_seen - map->base_tsn);379kfree(map->tsn_map);380map->tsn_map = new;381map->len = len;382383return 1;384}385386387