Home | History | Annotate | Line # | Download | only in iscsi
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