Home | History | Annotate | Line # | Download | only in iscsi
iscsi_utils.c revision 1.1
      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 (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 
    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