1 /* $NetBSD: iscsi_utils.c,v 1.8 2015/05/30 18:12:09 joerg 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@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 tsleep(&sess->ccb_pool, PWAIT, "get_ccb", 0); 237 } 238 } while (ccb == NULL); 239 240 ccb->flags = 0; 241 ccb->xs = NULL; 242 ccb->temp_data = NULL; 243 ccb->text_data = NULL; 244 ccb->status = ISCSI_STATUS_SUCCESS; 245 ccb->ITT = (ccb->ITT & 0xffffff) | (++sess->itt_id << 24); 246 ccb->disp = CCBDISP_NOWAIT; 247 ccb->connection = conn; 248 conn->usecount++; 249 250 return ccb; 251 } 252 253 /* 254 * free_ccb: 255 * Put a CCB back onto the free list. 256 * 257 * Parameter: The CCB. 258 */ 259 260 void 261 free_ccb(ccb_t *ccb) 262 { 263 session_t *sess = ccb->session; 264 pdu_t *pdu; 265 int s; 266 267 KASSERT((ccb->flags & CCBF_THROTTLING) == 0); 268 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 269 270 ccb->connection->usecount--; 271 ccb->connection = NULL; 272 273 ccb->disp = CCBDISP_UNUSED; 274 275 /* free temporary data */ 276 if (ccb->temp_data != NULL) { 277 free(ccb->temp_data, M_TEMP); 278 } 279 if (ccb->text_data != NULL) { 280 free(ccb->text_data, M_TEMP); 281 } 282 /* free PDU waiting for ACK */ 283 if ((pdu = ccb->pdu_waiting) != NULL) { 284 ccb->pdu_waiting = NULL; 285 free_pdu(pdu); 286 } 287 288 s = splbio(); 289 TAILQ_INSERT_TAIL(&sess->ccb_pool, ccb, chain); 290 splx(s); 291 292 wakeup(&sess->ccb_pool); 293 } 294 295 /* 296 * create_ccbs 297 * "Create" the pool of CCBs. This doesn't actually create the CCBs 298 * (they are allocated with the session structure), but it links them 299 * into the free-list. 300 * 301 * Parameter: The session owning the CCBs. 302 */ 303 304 void 305 create_ccbs(session_t *sess) 306 { 307 int i; 308 ccb_t *ccb; 309 int sid = sess->id << 8; 310 311 /* Note: CCBs are initialized to 0 with connection structure */ 312 313 for (i = 0, ccb = sess->ccb; i < CCBS_PER_SESSION; i++, ccb++) { 314 ccb->ITT = i | sid; 315 ccb->session = sess; 316 317 callout_init(&ccb->timeout, 0); 318 callout_setfunc(&ccb->timeout, ccb_timeout, ccb); 319 320 /*DEB (9, ("Create_ccbs: ccb %x itt %x\n", ccb, ccb->ITT)); */ 321 TAILQ_INSERT_HEAD(&sess->ccb_pool, ccb, chain); 322 } 323 } 324 325 /* 326 * suspend_ccb: 327 * Put CCB on wait queue 328 */ 329 void 330 suspend_ccb(ccb_t *ccb, bool yes) 331 { 332 connection_t *conn; 333 334 conn = ccb->connection; 335 if (yes) { 336 KASSERT((ccb->flags & CCBF_THROTTLING) == 0); 337 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 338 TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain); 339 ccb->flags |= CCBF_WAITQUEUE; 340 } else if (ccb->flags & CCBF_WAITQUEUE) { 341 KASSERT((ccb->flags & CCBF_THROTTLING) == 0); 342 TAILQ_REMOVE(&conn->ccbs_waiting, ccb, chain); 343 ccb->flags &= ~CCBF_WAITQUEUE; 344 } 345 } 346 347 /* 348 * throttle_ccb: 349 * Put CCB on throttling queue 350 */ 351 void 352 throttle_ccb(ccb_t *ccb, bool yes) 353 { 354 session_t *sess; 355 356 sess = ccb->session; 357 if (yes) { 358 KASSERT((ccb->flags & CCBF_THROTTLING) == 0); 359 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 360 TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain); 361 ccb->flags |= CCBF_THROTTLING; 362 } else if (ccb->flags & CCBF_THROTTLING) { 363 KASSERT((ccb->flags & CCBF_WAITQUEUE) == 0); 364 TAILQ_REMOVE(&sess->ccbs_throttled, ccb, chain); 365 ccb->flags &= ~CCBF_THROTTLING; 366 } 367 } 368 369 370 /* 371 * wake_ccb: 372 * Wake up (or dispose of) a CCB. Depending on the CCB's disposition, 373 * either wake up the requesting thread, signal SCSIPI that we're done, 374 * or just free the CCB for CCBDISP_FREE. 375 * 376 * Parameter: The CCB to handle and the new status of the CCB 377 */ 378 379 void 380 wake_ccb(ccb_t *ccb, uint32_t status) 381 { 382 ccb_disp_t disp; 383 connection_t *conn; 384 int s; 385 386 conn = ccb->connection; 387 388 #ifdef ISCSI_DEBUG 389 DEBC(conn, 9, ("CCB done, ccb = %p, disp = %d\n", 390 ccb, ccb->disp)); 391 #endif 392 393 callout_stop(&ccb->timeout); 394 395 s = splbio(); 396 disp = ccb->disp; 397 if (disp <= CCBDISP_NOWAIT || 398 (disp == CCBDISP_DEFER && conn->state <= ST_WINDING_DOWN)) { 399 splx(s); 400 return; 401 } 402 403 suspend_ccb(ccb, FALSE); 404 throttle_ccb(ccb, FALSE); 405 406 /* change the disposition so nobody tries this again */ 407 ccb->disp = CCBDISP_BUSY; 408 ccb->status = status; 409 splx(s); 410 411 switch (disp) { 412 case CCBDISP_FREE: 413 free_ccb(ccb); 414 break; 415 416 case CCBDISP_WAIT: 417 wakeup(ccb); 418 break; 419 420 case CCBDISP_SCSIPI: 421 iscsi_done(ccb); 422 free_ccb(ccb); 423 break; 424 425 case CCBDISP_DEFER: 426 break; 427 428 default: 429 DEBC(conn, 1, ("CCB done, ccb = %p, invalid disposition %d", ccb, disp)); 430 free_ccb(ccb); 431 break; 432 } 433 } 434 435 /***************************************************************************** 436 * PDU management functions 437 *****************************************************************************/ 438 439 /* 440 * get_pdu: 441 * Get a PDU for the SCSI operation. 442 * 443 * Parameter: 444 * conn The connection this PDU should be associated with 445 * waitok OK to wait for PDU if TRUE 446 * 447 * Returns: The PDU or NULL if none is available and waitok is FALSE. 448 */ 449 450 pdu_t * 451 get_pdu(connection_t *conn, bool waitok) 452 { 453 pdu_t *pdu; 454 int s; 455 456 do { 457 s = splbio(); 458 pdu = TAILQ_FIRST(&conn->pdu_pool); 459 if (pdu != NULL) 460 TAILQ_REMOVE(&conn->pdu_pool, pdu, chain); 461 splx(s); 462 463 DEB(100, ("get_pdu_c: pdu = %p, waitok = %d\n", pdu, waitok)); 464 if (pdu == NULL) { 465 if (!waitok || conn->terminating) 466 return NULL; 467 tsleep(&conn->pdu_pool, PWAIT, "get_pdu_c", 0); 468 } 469 } while (pdu == NULL); 470 471 memset(pdu, 0, sizeof(pdu_t)); 472 pdu->connection = conn; 473 pdu->disp = PDUDISP_FREE; 474 475 return pdu; 476 } 477 478 /* 479 * free_pdu: 480 * Put a PDU back onto the free list. 481 * 482 * Parameter: The PDU. 483 */ 484 485 void 486 free_pdu(pdu_t *pdu) 487 { 488 connection_t *conn = pdu->connection; 489 pdu_disp_t pdisp; 490 int s; 491 492 if (PDUDISP_UNUSED == (pdisp = pdu->disp)) 493 return; 494 pdu->disp = PDUDISP_UNUSED; 495 496 if (pdu->flags & PDUF_INQUEUE) { 497 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 498 pdu->flags &= ~PDUF_INQUEUE; 499 } 500 501 if (pdisp == PDUDISP_SIGNAL) 502 wakeup(pdu); 503 504 /* free temporary data in this PDU */ 505 if (pdu->temp_data) 506 free(pdu->temp_data, M_TEMP); 507 508 s = splbio(); 509 TAILQ_INSERT_TAIL(&conn->pdu_pool, pdu, chain); 510 splx(s); 511 512 wakeup(&conn->pdu_pool); 513 } 514 515 /* 516 * create_pdus 517 * "Create" the pool of PDUs. This doesn't actually create the PDUs 518 * (they are allocated with the connection structure), but it links them 519 * into the free-list. 520 * 521 * Parameter: The connection owning the PDUs. 522 */ 523 524 void 525 create_pdus(connection_t *conn) 526 { 527 int i; 528 pdu_t *pdu; 529 530 /* Note: PDUs are initialized to 0 with connection structure */ 531 532 for (i = 0, pdu = conn->pdu; i < PDUS_PER_CONNECTION; i++, pdu++) { 533 TAILQ_INSERT_HEAD(&conn->pdu_pool, pdu, chain); 534 } 535 } 536 537 538 /***************************************************************************** 539 * Serial Number management functions 540 *****************************************************************************/ 541 542 /* 543 * init_sernum: 544 * Initialize serial number buffer variables. 545 * 546 * Parameter: 547 * buff The serial number buffer. 548 */ 549 550 void 551 init_sernum(sernum_buffer_t *buff) 552 { 553 554 buff->bottom = 0; 555 buff->top = 0; 556 buff->next_sn = 0; 557 buff->ExpSN = 0; 558 } 559 560 561 /* 562 * add_sernum: 563 * Add a received serial number to the buffer. 564 * If the serial number is smaller than the expected one, it is ignored. 565 * If it is larger, all missing serial numbers are added as well. 566 * 567 * Parameter: 568 * buff The serial number buffer. 569 * num The received serial number 570 * 571 * Returns: 572 * 0 if the received block is a duplicate 573 * 1 if the number is the expected one 574 * >1 if the numer is > the expected value, in this case the 575 * return value is the number of unacknowledged blocks 576 * <0 if the buffer is full (i.e. an excessive number of blocks 577 * is unacknowledged) 578 */ 579 580 int 581 add_sernum(sernum_buffer_t *buff, uint32_t num) 582 { 583 int i, t, b; 584 uint32_t n; 585 int32_t diff; 586 587 /* 588 * next_sn is the next expected SN, so normally diff should be 1. 589 */ 590 n = buff->next_sn; 591 diff = (num - n) + 1; 592 593 if (diff <= 0) { 594 return 0; /* ignore if SN is smaller than expected (dup or retransmit) */ 595 } 596 597 buff->next_sn = num + 1; 598 t = buff->top; 599 b = buff->bottom; 600 601 for (i = 0; i < diff; i++) { 602 buff->sernum[t] = n++; 603 buff->ack[t] = false; 604 t = (t + 1) % SERNUM_BUFFER_LENGTH; 605 if (t == b) { 606 DEB(1, ("AddSernum: Buffer Full! num %d, diff %d\n", num, diff)); 607 return -1; 608 } 609 } 610 611 buff->top = t; 612 DEB(10, ("AddSernum bottom %d [%d], top %d, num %u, diff %d\n", 613 b, buff->sernum[b], buff->top, num, diff)); 614 615 return diff; 616 } 617 618 619 /* 620 * ack_sernum: 621 * Mark a received serial number as acknowledged. This does not necessarily 622 * change the associated ExpSN if there are lower serial numbers in the 623 * buffer. 624 * 625 * Parameter: 626 * buff The serial number buffer. 627 * num The serial number to acknowledge. 628 * 629 * Returns: The value of ExpSN. 630 */ 631 632 uint32_t 633 ack_sernum(sernum_buffer_t *buff, uint32_t num) 634 { 635 int b = buff->bottom; 636 int t = buff->top; 637 638 /* shortcut for most likely case */ 639 if (t == (b + 1) && num == buff->sernum[b]) { 640 /* buffer is now empty, reset top */ 641 buff->top = b; 642 } else if (b != t) { 643 for (; b != t; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 644 if (!sn_a_lt_b(buff->sernum[b], num)) 645 break; 646 } 647 if (num == buff->sernum[b]) { 648 if (b == buff->bottom) 649 buff->bottom = (b + 1) % SERNUM_BUFFER_LENGTH; 650 else 651 buff->ack[b] = true; 652 } 653 654 for (b = buff->bottom, num = buff->sernum[b] - 1; 655 b != t && buff->ack[b]; b = (b + 1) % SERNUM_BUFFER_LENGTH) { 656 num = buff->sernum[b]; 657 } 658 } 659 660 if (!sn_a_lt_b(num, buff->ExpSN)) 661 buff->ExpSN = num + 1; 662 663 DEB(10, ("AckSernum bottom %d, top %d, num %d ExpSN %d\n", 664 buff->bottom, buff->top, num, buff->ExpSN)); 665 666 return buff->ExpSN; 667 } 668