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