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