iscsi_utils.c revision 1.1.2.2 1 /* $NetBSD: iscsi_utils.c,v 1.1.2.2 2013/01/23 00:06:07 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "iscsi_globals.h"
32
33 #include <sys/systm.h>
34 #include <sys/buf.h>
35 #include <sys/socketvar.h>
36 #include <sys/bswap.h>
37
38
39 #ifdef ISCSI_DEBUG
40
41 /* debug helper routine */
42 void
43 dump(void *buff, int len)
44 {
45 uint8_t *bp = (uint8_t *) buff;
46 int i;
47
48 while (len > 0) {
49 for (i = min(16, len); i > 0; i--)
50 printf("%02x ", *bp++);
51 printf("\n");
52 len -= 16;
53 }
54 }
55
56 #endif
57
58 /*****************************************************************************
59 * Digest functions
60 *****************************************************************************/
61
62 /*****************************************************************
63 *
64 * CRC LOOKUP TABLE
65 * ================
66 * The following CRC lookup table was generated automagically
67 * by the Rocksoft^tm Model CRC Algorithm Table Generation
68 * Program V1.0 using the following model parameters:
69 *
70 * Width : 4 bytes.
71 * Poly : 0x1EDC6F41L
72 * Reverse : TRUE.
73 *
74 * For more information on the Rocksoft^tm Model CRC Algorithm,
75 * see the document titled "A Painless Guide to CRC Error
76 * Detection Algorithms" by Ross Williams
77 * (ross (at) guest.adelaide.edu.au.). This document is likely to be
78 * in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".
79 *
80 *****************************************************************/
81
82 STATIC uint32_t crc_table[256] = {
83 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
84 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
85 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
86 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
87 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
88 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
89 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
90 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
91 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
92 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
93 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
94 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
95 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
96 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
97 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
98 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
99 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
100 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
101 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
102 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
103 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
104 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
105 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
106 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
107 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
108 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
109 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
110 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
111 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
112 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
113 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
114 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
115 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
116 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
117 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
118 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
119 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
120 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
121 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
122 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
123 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
124 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
125 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
126 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
127 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
128 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
129 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
130 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
131 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
132 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
133 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
134 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
135 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
136 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
137 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
138 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
139 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
140 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
141 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
142 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
143 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
144 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
145 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
146 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
147 };
148
149
150 /*
151 * gen_digest:
152 * Generate an iSCSI CRC32C digest over the given data.
153 *
154 * Parameters:
155 * buff The data
156 * len The length of the data in bytes
157 *
158 * Returns: The digest in network byte order
159 */
160
161 uint32_t
162 gen_digest(void *buff, int len)
163 {
164 uint8_t *bp = (uint8_t *) buff;
165 uint32_t crc = 0xffffffff;
166
167 while (len--) {
168 crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
169 }
170 return htonl(bswap32(crc ^ 0xffffffff));
171 }
172
173
174 /*
175 * gen_digest_2:
176 * Generate an iSCSI CRC32C digest over the given data, which is split over
177 * two buffers.
178 *
179 * Parameters:
180 * buf1, buf2 The data
181 * len1, len2 The length of the data in bytes
182 *
183 * Returns: The digest in network byte order
184 */
185
186 uint32_t
187 gen_digest_2(void *buf1, int len1, void *buf2, int len2)
188 {
189 uint8_t *bp = (uint8_t *) buf1;
190 uint32_t crc = 0xffffffff;
191
192 while (len1--) {
193 crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
194 }
195 bp = (uint8_t *) buf2;
196 while (len2--) {
197 crc = ((crc >> 8) & 0x00ffffff) ^ crc_table[(crc ^ *bp++) & 0xff];
198 }
199 return htonl(bswap32(crc ^ 0xffffffff));
200 }
201
202 /*****************************************************************************
203 * CCB management functions
204 *****************************************************************************/
205
206 /*
207 * get_ccb:
208 * Get a CCB for the SCSI operation, waiting if none is available.
209 *
210 * Parameter:
211 * sess The session containing this CCB
212 * waitok Whether waiting for a CCB is OK
213 *
214 * Returns: The CCB.
215 */
216
217 ccb_t *
218 get_ccb(connection_t *conn, bool waitok)
219 {
220 ccb_t *ccb;
221 session_t *sess = conn->session;
222 int s;
223
224 do {
225 s = splbio();
226 ccb = TAILQ_FIRST(&sess->ccb_pool);
227 if (ccb != NULL)
228 TAILQ_REMOVE(&sess->ccb_pool, ccb, chain);
229 splx(s);
230
231 DEB(100, ("get_ccb: ccb = %p, waitok = %d\n", ccb, waitok));
232 if (ccb == NULL) {
233 if (!waitok || conn->terminating) {
234 return NULL;
235 }
236 PDEBOUT(("Waiting for CCB!\n"));
237 tsleep(&sess->ccb_pool, PWAIT, "get_ccb", 0);
238 }
239 } while (ccb == NULL);
240
241 ccb->flags = 0;
242 ccb->xs = NULL;
243 ccb->temp_data = NULL;
244 ccb->text_data = NULL;
245 ccb->status = ISCSI_STATUS_SUCCESS;
246 ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24);
247 ccb->disp = CCBDISP_NOWAIT;
248 ccb->connection = conn;
249 conn->usecount++;
250
251 return ccb;
252 }
253
254 /*
255 * free_ccb:
256 * Put a CCB back onto the free list.
257 *
258 * Parameter: The CCB.
259 */
260
261 void
262 free_ccb(ccb_t *ccb)
263 {
264 session_t *sess = ccb->session;
265 pdu_t *pdu;
266 int s;
267
268 KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
269 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
270
271 ccb->connection->usecount--;
272 ccb->connection = NULL;
273
274 ccb->disp = CCBDISP_UNUSED;
275
276 /* free temporary data */
277 if (ccb->temp_data != NULL) {
278 free(ccb->temp_data, M_TEMP);
279 }
280 if (ccb->text_data != NULL) {
281 free(ccb->text_data, M_TEMP);
282 }
283 /* free PDU waiting for ACK */
284 if ((pdu = ccb->pdu_waiting) != NULL) {
285 ccb->pdu_waiting = NULL;
286 free_pdu(pdu);
287 }
288
289 s = splbio();
290 TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain);
291 splx(s);
292
293 wakeup(&sess->ccb_pool);
294 }
295
296 /*
297 * create_ccbs
298 * "Create" the pool of CCBs. This doesn't actually create the CCBs
299 * (they are allocated with the session structure), but it links them
300 * into the free-list.
301 *
302 * Parameter: The session owning the CCBs.
303 */
304
305 void
306 create_ccbs(session_t *sess)
307 {
308 int i;
309 ccb_t *ccb;
310 int sid = sess->id << 8;
311
312 /* Note: CCBs are initialized to 0 with connection structure */
313
314 for (i = 0, ccb = sess->ccb; i < CCBS_PER_SESSION; i++, ccb++) {
315 ccb->ITT = i | sid;
316 ccb->session = sess;
317
318 callout_init(&ccb->timeout, 0);
319 #if (__NetBSD_Version__ >= 106000000)
320 callout_setfunc(&ccb->timeout, ccb_timeout, ccb);
321 #endif
322
323 /*DEB (9, ("Create_ccbs: ccb %x itt %x\n", ccb, ccb->ITT)); */
324 TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain);
325 }
326 }
327
328 /*
329 * suspend_ccb:
330 * Put CCB on wait queue
331 */
332 void
333 suspend_ccb(ccb_t *ccb, bool yes)
334 {
335 connection_t *conn;
336
337 conn = ccb->connection;
338 if (yes) {
339 KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
340 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
341 TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain);
342 ccb->flags |= CCBF_WAITQUEUE;
343 } else if (ccb->flags & CCBF_WAITQUEUE) {
344 KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
345 TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain);
346 ccb->flags &= ~CCBF_WAITQUEUE;
347 }
348 }
349
350 /*
351 * throttle_ccb:
352 * Put CCB on throttling queue
353 */
354 void
355 throttle_ccb(ccb_t *ccb, bool yes)
356 {
357 session_t *sess;
358
359 sess = ccb->session;
360 if (yes) {
361 KASSERT((ccb->flags & CCBF_THROTTLING) == 0);
362 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
363 TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain);
364 ccb->flags |= CCBF_THROTTLING;
365 } else if (ccb->flags & CCBF_THROTTLING) {
366 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0);
367 TAILQ_REMOVE(&sess->ccbs_throttled, ccb, chain);
368 ccb->flags &= ~CCBF_THROTTLING;
369 }
370 }
371
372
373 /*
374 * wake_ccb:
375 * Wake up (or dispose of) a CCB. Depending on the CCB's disposition,
376 * either wake up the requesting thread, signal SCSIPI that we're done,
377 * or just free the CCB for CCBDISP_FREE.
378 *
379 * Parameter: The CCB to handle and the new status of the CCB
380 */
381
382 void
383 wake_ccb(ccb_t *ccb, uint32_t status)
384 {
385 ccb_disp_t disp;
386 connection_t *conn;
387 int s;
388
389 conn = ccb->connection;
390
391 #ifdef ISCSI_DEBUG
392 DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n",
393 ccb, ccb->disp));
394 #endif
395
396 callout_stop(&ccb->timeout);
397
398 s = splbio();
399 disp = ccb->disp;
400 if (disp <= CCBDISP_NOWAIT ||
401 (disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) {
402 splx(s);
403 return;
404 }
405
406 suspend_ccb(ccb, FALSE);
407 throttle_ccb(ccb, FALSE);
408
409 /* change the disposition so nobody tries this again */
410 ccb->disp = CCBDISP_BUSY;
411 ccb->status = status;
412 splx(s);
413
414 PERF_END(ccb);
415
416 switch (disp) {
417 case CCBDISP_FREE:
418 free_ccb(ccb);
419 break;
420
421 case CCBDISP_WAIT:
422 wakeup(ccb);
423 break;
424
425 case CCBDISP_SCSIPI:
426 iscsi_done(ccb);
427 free_ccb(ccb);
428 break;
429
430 case CCBDISP_DEFER:
431 break;
432
433 default:
434 DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp));
435 free_ccb(ccb);
436 break;
437 }
438 }
439
440 /*****************************************************************************
441 * PDU management functions
442 *****************************************************************************/
443
444 /*
445 * get_pdu:
446 * Get a PDU for the SCSI operation.
447 *
448 * Parameter:
449 * conn The connection this PDU should be associated with
450 * waitok OK to wait for PDU if TRUE
451 *
452 * Returns: The PDU or NULL if none is available and waitok is FALSE.
453 */
454
455 pdu_t *
456 get_pdu(connection_t *conn, bool waitok)
457 {
458 pdu_t *pdu;
459 int s;
460
461 do {
462 s = splbio();
463 pdu = TAILQ_FIRST(&conn->pdu_pool);
464 if (pdu != NULL)
465 TAILQ_REMOVE(&conn->pdu_pool, pdu, chain);
466 splx(s);
467
468 DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok));
469 if (pdu == NULL) {
470 if (!waitok || conn->terminating)
471 return NULL;
472 PDEBOUT(("Waiting for PDU!\n"));
473 tsleep(&conn->pdu_pool, PWAIT, "get_pdu_c", 0);
474 }
475 } while (pdu == NULL);
476
477 memset(pdu, 0, sizeof(pdu_t));
478 pdu->connection = conn;
479 pdu->disp = PDUDISP_FREE;
480
481 return pdu;
482 }
483
484 /*
485 * free_pdu:
486 * Put a PDU back onto the free list.
487 *
488 * Parameter: The PDU.
489 */
490
491 void
492 free_pdu(pdu_t *pdu)
493 {
494 connection_t *conn = pdu->connection;
495 pdu_disp_t pdisp;
496 int s;
497
498 if (PDUDISP_UNUSED == (pdisp = pdu->disp))
499 return;
500 pdu->disp = PDUDISP_UNUSED;
501
502 if (pdu->flags & PDUF_INQUEUE) {
503 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain);
504 pdu->flags &= ~PDUF_INQUEUE;
505 }
506
507 if (pdisp == PDUDISP_SIGNAL)
508 wakeup(pdu);
509
510 /* free temporary data in this PDU */
511 if (pdu->temp_data)
512 free(pdu->temp_data, M_TEMP);
513
514 s = splbio();
515 TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain);
516 splx(s);
517
518 wakeup(&conn->pdu_pool);
519 }
520
521 /*
522 * create_pdus
523 * "Create" the pool of PDUs. This doesn't actually create the PDUs
524 * (they are allocated with the connection structure), but it links them
525 * into the free-list.
526 *
527 * Parameter: The connection owning the PDUs.
528 */
529
530 void
531 create_pdus(connection_t *conn)
532 {
533 int i;
534 pdu_t *pdu;
535
536 /* Note: PDUs are initialized to 0 with connection structure */
537
538 for (i = 0, pdu = conn->pdu; i < PDUS_PER_CONNECTION; i++, pdu++) {
539 TAILQ_INSERT_HEAD(&conn->pdu_pool, pdu, chain);
540 }
541 }
542
543
544 /*****************************************************************************
545 * Serial Number management functions
546 *****************************************************************************/
547
548 /*
549 * init_sernum:
550 * Initialize serial number buffer variables.
551 *
552 * Parameter:
553 * buff The serial number buffer.
554 */
555
556 void
557 init_sernum(sernum_buffer_t *buff)
558 {
559
560 buff->bottom = 0;
561 buff->top = 0;
562 buff->next_sn = 0;
563 buff->ExpSN = 0;
564 }
565
566
567 /*
568 * add_sernum:
569 * Add a received serial number to the buffer.
570 * If the serial number is smaller than the expected one, it is ignored.
571 * If it is larger, all missing serial numbers are added as well.
572 *
573 * Parameter:
574 * buff The serial number buffer.
575 * num The received serial number
576 *
577 * Returns:
578 * 0 if the received block is a duplicate
579 * 1 if the number is the expected one
580 * >1 if the numer is > the expected value, in this case the
581 * return value is the number of unacknowledged blocks
582 * <0 if the buffer is full (i.e. an excessive number of blocks
583 * is unacknowledged)
584 */
585
586 int
587 add_sernum(sernum_buffer_t *buff, uint32_t num)
588 {
589 int i, t, b;
590 uint32_t n;
591 int32_t diff;
592
593 /*
594 * next_sn is the next expected SN, so normally diff should be 1.
595 */
596 n = buff->next_sn;
597 diff = (num - n) + 1;
598
599 if (diff <= 0) {
600 PDEB(1, ("Rx Duplicate Block: SN %u < Next SN %u\n", num, n));
601 return 0; /* ignore if SN is smaller than expected (dup or retransmit) */
602 }
603
604 buff->next_sn = num + 1;
605 t = buff->top;
606 b = buff->bottom;
607
608 for (i = 0; i < diff; i++) {
609 buff->sernum[t] = n++;
610 buff->ack[t] = 0;
611 t = (t + 1) % SERNUM_BUFFER_LENGTH;
612 if (t == b) {
613 DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff));
614 return -1;
615 }
616 }
617
618 buff->top = t;
619 DEB(10, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n",
620 b, buff->sernum[b], buff->top, num, diff));
621
622 return diff;
623 }
624
625
626 /*
627 * ack_sernum:
628 * Mark a received serial number as acknowledged. This does not necessarily
629 * change the associated ExpSN if there are lower serial numbers in the
630 * buffer.
631 *
632 * Parameter:
633 * buff The serial number buffer.
634 * num The serial number to acknowledge.
635 *
636 * Returns: The value of ExpSN.
637 */
638
639 uint32_t
640 ack_sernum(sernum_buffer_t *buff, uint32_t num)
641 {
642 int b = buff->bottom;
643 int t = buff->top;
644
645 /* shortcut for most likely case */
646 if (t == (b + 1) && num == buff->sernum[b]) {
647 /* buffer is now empty, reset top */
648 buff->top = b;
649 } else if (b != t) {
650 for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
651 if (!sn_a_lt_b(buff->sernum[b], num))
652 break;
653 }
654 if (num == buff->sernum[b]) {
655 if (b == buff->bottom)
656 buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH;
657 else
658 buff->ack[b] = 1;
659 }
660
661 for (b = buff->bottom, num = buff->sernum[b] - 1;
662 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) {
663 num = buff->sernum[b];
664 }
665 }
666
667 if (!sn_a_lt_b(num, buff->ExpSN))
668 buff->ExpSN = num + 1;
669
670 DEB(10, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n",
671 buff->bottom, buff->top, num, buff->ExpSN));
672
673 return buff->ExpSN;
674 }
675