ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / sctp / tsnmap.c
1 /* SCTP kernel reference Implementation
2  * (C) Copyright IBM Corp. 2001, 2004
3  * Copyright (c) 1999-2000 Cisco, Inc.
4  * Copyright (c) 1999-2001 Motorola, Inc.
5  * Copyright (c) 2001 Intel Corp.
6  *
7  * This file is part of the SCTP kernel reference Implementation
8  *
9  * These functions manipulate sctp tsn mapping array.
10  *
11  * The SCTP reference implementation is free software;
12  * you can redistribute it and/or modify it under the terms of
13  * the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * The SCTP reference implementation is distributed in the hope that it
18  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19  *                 ************************
20  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21  * See the GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with GNU CC; see the file COPYING.  If not, write to
25  * the Free Software Foundation, 59 Temple Place - Suite 330,
26  * Boston, MA 02111-1307, USA.
27  *
28  * Please send any bug reports or fixes you make to the
29  * email address(es):
30  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
31  *
32  * Or submit a bug report through the following website:
33  *    http://www.sf.net/projects/lksctp
34  *
35  * Written or modified by:
36  *    La Monte H.P. Yarroll <piggy@acm.org>
37  *    Jon Grimm             <jgrimm@us.ibm.com>
38  *    Karl Knutson          <karl@athena.chicago.il.us>
39  *    Sridhar Samudrala     <sri@us.ibm.com>
40  *
41  * Any bugs reported given to us we will try to fix... any fixes shared will
42  * be incorporated into the next SCTP release.
43  */
44
45 #include <linux/types.h>
46 #include <net/sctp/sctp.h>
47 #include <net/sctp/sm.h>
48
49 static void sctp_tsnmap_update(struct sctp_tsnmap *map);
50 static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
51                                      __u16 len, __u16 base,
52                                      int *started, __u16 *start,
53                                      int *ended, __u16 *end);
54
55 /* Create a new sctp_tsnmap.
56  * Allocate room to store at least 'len' contiguous TSNs.
57  */
58 struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
59 {
60         struct sctp_tsnmap *retval;
61
62         retval = kmalloc(sizeof(struct sctp_tsnmap) +
63                          sctp_tsnmap_storage_size(len), gfp);
64         if (!retval)
65                 goto fail;
66
67         if (!sctp_tsnmap_init(retval, len, initial_tsn))
68                 goto fail_map;
69         retval->malloced = 1;
70         return retval;
71
72 fail_map:
73         kfree(retval);
74 fail:
75         return NULL;
76 }
77
78 /* Initialize a block of memory as a tsnmap.  */
79 struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
80                                      __u32 initial_tsn)
81 {
82         map->tsn_map = map->raw_map;
83         map->overflow_map = map->tsn_map + len;
84         map->len = len;
85
86         /* Clear out a TSN ack status.  */
87         memset(map->tsn_map, 0x00, map->len + map->len);
88
89         /* Keep track of TSNs represented by tsn_map.  */
90         map->base_tsn = initial_tsn;
91         map->overflow_tsn = initial_tsn + map->len;
92         map->cumulative_tsn_ack_point = initial_tsn - 1;
93         map->max_tsn_seen = map->cumulative_tsn_ack_point;
94         map->malloced = 0;
95         map->num_dup_tsns = 0;
96
97         return map;
98 }
99
100 /* Test the tracking state of this TSN.
101  * Returns:
102  *   0 if the TSN has not yet been seen
103  *  >0 if the TSN has been seen (duplicate)
104  *  <0 if the TSN is invalid (too large to track)
105  */
106 int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
107 {
108         __s32 gap;
109         int dup;
110
111         /* Calculate the index into the mapping arrays.  */
112         gap = tsn - map->base_tsn;
113
114         /* Verify that we can hold this TSN.  */
115         if (gap >= (/* base */ map->len + /* overflow */ map->len)) {
116                 dup = -1;
117                 goto out;
118         }
119
120         /* Honk if we've already seen this TSN.
121          * We have three cases:
122          *      1. The TSN is ancient or belongs to a previous tsn_map.
123          *      2. The TSN is already marked in the tsn_map.
124          *      3. The TSN is already marked in the tsn_map_overflow.
125          */
126         if (gap < 0 ||
127             (gap < map->len && map->tsn_map[gap]) ||
128             (gap >= map->len && map->overflow_map[gap - map->len]))
129                 dup = 1;
130         else
131                 dup = 0;
132
133 out:
134         return dup;
135 }
136
137
138 /* Mark this TSN as seen.  */
139 void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
140 {
141         __s32 gap;
142
143         /* Vacuously mark any TSN which precedes the map base or
144          * exceeds the end of the map.
145          */
146         if (TSN_lt(tsn, map->base_tsn))
147                 return;
148         if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
149                 return;
150
151         /* Bump the max.  */
152         if (TSN_lt(map->max_tsn_seen, tsn))
153                 map->max_tsn_seen = tsn;
154
155         /* Assert: TSN is in range.  */
156         gap = tsn - map->base_tsn;
157
158         /* Mark the TSN as received.  */
159         if (gap < map->len)
160                 map->tsn_map[gap]++;
161         else
162                 map->overflow_map[gap - map->len]++;
163
164         /* Go fixup any internal TSN mapping variables including
165          * cumulative_tsn_ack_point.
166          */
167         sctp_tsnmap_update(map);
168 }
169
170
171 /* Dispose of a tsnmap.  */
172 void sctp_tsnmap_free(struct sctp_tsnmap *map)
173 {
174         if (map->malloced)
175                 kfree(map);
176 }
177
178 /* Initialize a Gap Ack Block iterator from memory being provided.  */
179 void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
180                            struct sctp_tsnmap_iter *iter)
181 {
182         /* Only start looking one past the Cumulative TSN Ack Point.  */
183         iter->start = map->cumulative_tsn_ack_point + 1;
184 }
185
186 /* Get the next Gap Ack Blocks. Returns 0 if there was not another block
187  * to get.
188  */
189 int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
190         struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
191 {
192         int started, ended;
193         __u16 _start, _end, offset;
194
195         /* We haven't found a gap yet.  */
196         started = ended = 0;
197
198         /* If there are no more gap acks possible, get out fast.  */
199         if (TSN_lte(map->max_tsn_seen, iter->start))
200                 return 0;
201
202         /* Search the first mapping array.  */
203         if (iter->start - map->base_tsn < map->len) {
204
205                 offset = iter->start - map->base_tsn;
206                 sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0,
207                                          &started, &_start, &ended, &_end);
208         }
209
210         /* Do we need to check the overflow map? */
211         if (!ended) {
212                 /* Fix up where we'd like to start searching in the
213                  * overflow map.
214                  */
215                 if (iter->start - map->base_tsn < map->len)
216                         offset = 0;
217                 else
218                         offset = iter->start - map->base_tsn - map->len;
219
220                 /* Search the overflow map.  */
221                 sctp_tsnmap_find_gap_ack(map->overflow_map,
222                                          offset,
223                                          map->len,
224                                          map->len,
225                                          &started, &_start,
226                                          &ended, &_end);
227         }
228
229         /* The Gap Ack Block happens to end at the end of the
230          * overflow map.
231          */
232         if (started && !ended) {
233                 ended++;
234                 _end = map->len + map->len - 1;
235         }
236
237         /* If we found a Gap Ack Block, return the start and end and
238          * bump the iterator forward.
239          */
240         if (ended) {
241                 /* Fix up the start and end based on the
242                  * Cumulative TSN Ack offset into the map.
243                  */
244                 int gap = map->cumulative_tsn_ack_point -
245                         map->base_tsn;
246
247                 *start = _start - gap;
248                 *end = _end - gap;
249
250                 /* Move the iterator forward.  */
251                 iter->start = map->cumulative_tsn_ack_point + *end + 1;
252         }
253
254         return ended;
255 }
256
257 /* Mark this and any lower TSN as seen.  */
258 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
259 {
260         __s32 gap;
261
262         /* Vacuously mark any TSN which precedes the map base or
263          * exceeds the end of the map.
264          */
265         if (TSN_lt(tsn, map->base_tsn))
266                 return;
267         if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
268                 return;
269
270         /* Bump the max.  */
271         if (TSN_lt(map->max_tsn_seen, tsn))
272                 map->max_tsn_seen = tsn;
273
274         /* Assert: TSN is in range.  */
275         gap = tsn - map->base_tsn + 1;
276
277         /* Mark the TSNs as received.  */
278         if (gap <= map->len)
279                 memset(map->tsn_map, 0x01, gap);
280         else {
281                 memset(map->tsn_map, 0x01, map->len);
282                 memset(map->overflow_map, 0x01, (gap - map->len));
283         }
284
285         /* Go fixup any internal TSN mapping variables including
286          * cumulative_tsn_ack_point.
287          */
288         sctp_tsnmap_update(map);
289 }
290
291 /********************************************************************
292  * 2nd Level Abstractions
293  ********************************************************************/
294
295 /* This private helper function updates the tsnmap buffers and
296  * the Cumulative TSN Ack Point.
297  */
298 static void sctp_tsnmap_update(struct sctp_tsnmap *map)
299 {
300         __u32 ctsn;
301
302         ctsn = map->cumulative_tsn_ack_point;
303         do {
304                 ctsn++;
305                 if (ctsn == map->overflow_tsn) {
306                         /* Now tsn_map must have been all '1's,
307                          * so we swap the map and check the overflow table
308                          */
309                         __u8 *tmp = map->tsn_map;
310                         memset(tmp, 0, map->len);
311                         map->tsn_map = map->overflow_map;
312                         map->overflow_map = tmp;
313
314                         /* Update the tsn_map boundaries.  */
315                         map->base_tsn += map->len;
316                         map->overflow_tsn += map->len;
317                 }
318         } while (map->tsn_map[ctsn - map->base_tsn]);
319
320         map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
321 }
322
323 /* How many data chunks  are we missing from our peer?
324  */
325 __u16 sctp_tsnmap_pending(struct sctp_tsnmap *map)
326 {
327         __u32 cum_tsn = map->cumulative_tsn_ack_point;
328         __u32 max_tsn = map->max_tsn_seen;
329         __u32 base_tsn = map->base_tsn;
330         __u16 pending_data;
331         __s32 gap, start, end, i;
332
333         pending_data = max_tsn - cum_tsn;
334         gap = max_tsn - base_tsn;
335
336         if (gap <= 0 || gap >= (map->len + map->len))
337                 goto out;
338
339         start = ((cum_tsn >= base_tsn) ? (cum_tsn - base_tsn + 1) : 0);
340         end = ((gap > map->len ) ? map->len : gap + 1);
341
342         for (i = start; i < end; i++) {
343                 if (map->tsn_map[i])
344                         pending_data--;
345         }
346
347         if (gap >= map->len) {
348                 start = 0;
349                 end = gap - map->len + 1;
350                 for (i = start; i < end; i++) {
351                         if (map->overflow_map[i])
352                                 pending_data--;
353                 }
354         }
355
356 out:
357         return pending_data;
358 }
359
360 /* This is a private helper for finding Gap Ack Blocks.  It searches a
361  * single array for the start and end of a Gap Ack Block.
362  *
363  * The flags "started" and "ended" tell is if we found the beginning
364  * or (respectively) the end of a Gap Ack Block.
365  */
366 static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
367                                      __u16 len, __u16 base,
368                                      int *started, __u16 *start,
369                                      int *ended, __u16 *end)
370 {
371         int i = off;
372
373         /* Look through the entire array, but break out
374          * early if we have found the end of the Gap Ack Block.
375          */
376
377         /* Also, stop looking past the maximum TSN seen. */
378
379         /* Look for the start. */
380         if (!(*started)) {
381                 for (; i < len; i++) {
382                         if (map[i]) {
383                                 (*started)++;
384                                 *start = base + i;
385                                 break;
386                         }
387                 }
388         }
389
390         /* Look for the end.  */
391         if (*started) {
392                 /* We have found the start, let's find the
393                  * end.  If we find the end, break out.
394                  */
395                 for (; i < len; i++) {
396                         if (!map[i]) {
397                                 (*ended)++;
398                                 *end = base + i - 1;
399                                 break;
400                         }
401                 }
402         }
403 }
404
405 /* Renege that we have seen a TSN.  */
406 void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
407 {
408         __s32 gap;
409
410         if (TSN_lt(tsn, map->base_tsn))
411                 return;
412         if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
413                 return;
414
415         /* Assert: TSN is in range.  */
416         gap = tsn - map->base_tsn;
417
418         /* Pretend we never saw the TSN.  */
419         if (gap < map->len)
420                 map->tsn_map[gap] = 0;
421         else
422                 map->overflow_map[gap - map->len] = 0;
423 }
424
425 /* How many gap ack blocks do we have recorded? */
426 __u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map)
427 {
428         struct sctp_tsnmap_iter iter;
429         int gabs = 0;
430
431         /* Refresh the gap ack information. */
432         if (sctp_tsnmap_has_gap(map)) {
433                 sctp_tsnmap_iter_init(map, &iter);
434                 while (sctp_tsnmap_next_gap_ack(map, &iter,
435                                                 &map->gabs[gabs].start,
436                                                 &map->gabs[gabs].end)) {
437
438                         map->gabs[gabs].start = htons(map->gabs[gabs].start);
439                         map->gabs[gabs].end = htons(map->gabs[gabs].end);
440                         gabs++;
441                         if (gabs >= SCTP_MAX_GABS)
442                                 break;
443                 }
444         }
445         return gabs;
446 }