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