Home | History | Annotate | Line # | Download | only in lib
      1 /*
      2  * IMPORTANT:  READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      3  * By downloading, copying, installing or using the software you agree
      4  * to this license.  If you do not agree to this license, do not
      5  * download, install, copy or use the software.
      6  *
      7  * Intel License Agreement
      8  *
      9  * Copyright (c) 2000, Intel Corporation
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  *
     16  * -Redistributions of source code must retain the above copyright
     17  *  notice, this list of conditions and the following disclaimer.
     18  *
     19  * -Redistributions in binary form must reproduce the above copyright
     20  *  notice, this list of conditions and the following disclaimer in the
     21  *  documentation and/or other materials provided with the
     22  *  distribution.
     23  *
     24  * -The name of Intel Corporation may not be used to endorse or
     25  *  promote products derived from this software without specific prior
     26  *  written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     31  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL INTEL
     32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
     35  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     36  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     37  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     38  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  */
     41 #include "config.h"
     42 
     43 #include <sys/types.h>
     44 #include <sys/param.h>
     45 
     46 #include <assert.h>
     47 #include <stdlib.h>
     48 
     49 #ifdef HAVE_NETINET_TCP_H
     50 #include <netinet/tcp.h>
     51 #endif
     52 
     53 #ifdef HAVE_SYS_UIO_H
     54 #include <sys/uio.h>
     55 #endif
     56 
     57 #ifdef HAVE_SYS_SOCKET_H
     58 #include <sys/socket.h>
     59 #endif
     60 
     61 #ifdef HAVE_NETINET_IN_H
     62 #include <netinet/in.h>
     63 #endif
     64 
     65 #ifdef HAVE_STRING_H
     66 #include <string.h>
     67 #endif
     68 
     69 #ifdef HAVE_SIGNAL_H
     70 #include <signal.h>
     71 #endif
     72 
     73 #ifdef HAVE_SYSLOG_H
     74 #include <syslog.h>
     75 #endif
     76 
     77 #ifdef HAVE_ERRNO_H
     78 #include <errno.h>
     79 #endif
     80 
     81 #ifdef HAVE_NETDB_H
     82 #include <netdb.h>
     83 #endif
     84 
     85 #ifdef HAVE_ARPA_INET_H
     86 #include <arpa/inet.h>
     87 #endif
     88 
     89 #ifdef HAVE_INTTYPES_H
     90 #include <inttypes.h>
     91 #endif
     92 
     93 
     94 #include "iscsiprotocol.h"
     95 #include "conffile.h"
     96 #include "storage.h"
     97 #include "target.h"
     98 #include "device.h"
     99 #include "iscsi-md5.h"
    100 #include "parameters.h"
    101 #include "iscsi.h"
    102 
    103 enum {
    104 	TARGET_SHUT_DOWN     = 0,
    105 	TARGET_INITIALIZING  = 1,
    106 	TARGET_INITIALIZED   = 2,
    107 	TARGET_SHUTTING_DOWN = 3
    108 };
    109 
    110 /***********
    111  * Private *
    112  ***********/
    113 
    114 static target_session_t	*g_session;
    115 static iscsi_queue_t	g_session_q;
    116 static iscsi_mutex_t	g_session_q_mutex;
    117 
    118 /*********************
    119  * Private Functions *
    120  *********************/
    121 
    122 static char *
    123 get_iqn(target_session_t *sess, uint32_t t, char *buf, size_t size)
    124 {
    125 	targv_t	*targv;
    126 
    127 	targv = sess->target->lunv;
    128 	if (targv->v[t].iqn != NULL) {
    129 		(void) strlcpy(buf, targv->v[t].iqn, size);
    130 		return buf;
    131 	}
    132 	(void) snprintf(buf, size, "%s:%s",
    133 			iscsi_target_getvar(sess->target, "iqn"),
    134 			targv->v[t].target);
    135 	return buf;
    136 }
    137 
    138 static int
    139 reject_t(target_session_t * sess, uint8_t *header, uint8_t reason)
    140 {
    141 	iscsi_reject_t  reject;
    142 	uint8_t   rsp_header[ISCSI_HEADER_LEN];
    143 
    144 	iscsi_err(__FILE__, __LINE__, "reject %x\n", reason);
    145 	reject.reason = reason;
    146 	reject.length = ISCSI_HEADER_LEN;
    147 	reject.StatSN = ++(sess->StatSN);
    148 	reject.ExpCmdSN = sess->ExpCmdSN;
    149 	reject.MaxCmdSN = sess->MaxCmdSN;
    150 	reject.DataSN = 0;	/* SNACK not yet implemented */
    151 
    152 	if (iscsi_reject_encap(rsp_header, &reject) != 0) {
    153 		iscsi_err(__FILE__, __LINE__,
    154 				"iscsi_reject_encap() failed\n");
    155 		return -1;
    156 	}
    157 	if (iscsi_sock_send_header_and_data(sess->sock, rsp_header,
    158 			ISCSI_HEADER_LEN, header, ISCSI_HEADER_LEN, 0, sess->sess_params.header_digest, sess->sess_params.data_digest) !=
    159 			2 * ISCSI_HEADER_LEN) {
    160 		iscsi_err(__FILE__, __LINE__,
    161 			"iscsi_sock_send_header_and_data() failed\n");
    162 		return -1;
    163 	}
    164 	return 0;
    165 }
    166 
    167 static int
    168 scsi_command_t(target_session_t *sess, uint8_t *header)
    169 {
    170 	iscsi_scsi_cmd_args_t	scsi_cmd;
    171 	iscsi_read_data_t	data;
    172 	iscsi_scsi_rsp_t	scsi_rsp;
    173 	target_cmd_t		cmd;
    174 	uint32_t		DataSN = 0;
    175 	uint8_t			rsp_header[ISCSI_HEADER_LEN];
    176 	struct iovec		*sg_new = NULL;
    177 	int			result;
    178 
    179 	(void) memset(&scsi_cmd, 0x0, sizeof(scsi_cmd));
    180 	scsi_cmd.ahs = NULL;
    181 	scsi_cmd.send_buffer = NULL;
    182 	if (iscsi_scsi_cmd_decap(header, &scsi_cmd) != 0) {
    183 		iscsi_err(__FILE__, __LINE__,
    184 				"iscsi_scsi_cmd_decap() failed\n");
    185 		result = -1;
    186 		goto out;
    187 	}
    188 	iscsi_trace(TRACE_ISCSI_DEBUG,
    189 		"session %d: SCSI Command (CmdSN %u, op %#x)\n",
    190 		sess->id, scsi_cmd.CmdSN, scsi_cmd.cdb[0]);
    191 
    192 	/* For Non-immediate commands, the CmdSN should be between ExpCmdSN  */
    193 	/* and MaxCmdSN, inclusive of both.  Otherwise, ignore the command */
    194 	if (!scsi_cmd.immediate &&
    195 	    (scsi_cmd.CmdSN < sess->ExpCmdSN ||
    196 	     scsi_cmd.CmdSN > sess->MaxCmdSN)) {
    197 		iscsi_err(__FILE__, __LINE__,
    198 			"CmdSN(%d) of SCSI Command not valid, "
    199 			"ExpCmdSN(%d) MaxCmdSN(%d). Ignoring the command\n",
    200 			scsi_cmd.CmdSN, sess->ExpCmdSN, sess->MaxCmdSN);
    201 		result = 0;
    202 		goto out;
    203 	}
    204 	/* Arg check.   */
    205 	scsi_cmd.attr = 0;	/* Temp fix FIXME */
    206 	/*
    207 	 * RETURN_NOT_EQUAL("ATTR (FIX ME)", scsi_cmd.attr, 0, NO_CLEANUP,
    208 	 * -1);
    209 	 */
    210 
    211 	/* Check Numbering */
    212 
    213 	if (scsi_cmd.CmdSN != sess->ExpCmdSN) {
    214 		iscsi_warn(__FILE__, __LINE__,
    215 			"Expected CmdSN %d, got %d. "
    216 			"(ignoring and resetting expectations)\n",
    217 			sess->ExpCmdSN, scsi_cmd.CmdSN);
    218 		sess->ExpCmdSN = scsi_cmd.CmdSN;
    219 	}
    220 	/* Check Transfer Lengths */
    221 	if (sess->sess_params.first_burst_length
    222 	    && (scsi_cmd.length > sess->sess_params.first_burst_length)) {
    223 		iscsi_err(__FILE__, __LINE__,
    224 			"scsi_cmd.length (%u) > FirstBurstLength (%u)\n",
    225 			scsi_cmd.length, sess->sess_params.first_burst_length);
    226 		scsi_cmd.status = 0x02;
    227 		scsi_cmd.length = 0;
    228 		goto response;
    229 	}
    230 	if (sess->sess_params.max_dataseg_len &&
    231 	    scsi_cmd.length > sess->sess_params.max_dataseg_len) {
    232 		iscsi_err(__FILE__, __LINE__,
    233 			"scsi_cmd.length (%u) > MaxRecvDataSegmentLength "
    234 			"(%u)\n",
    235 			scsi_cmd.length, sess->sess_params.max_dataseg_len);
    236 		result = -1;
    237 		goto out;
    238 	}
    239 
    240 #if 0
    241 	/* commented out in original Intel reference code */
    242 	if (scsi_cmd.final && scsi_cmd.output) {
    243 		RETURN_NOT_EQUAL("Length", scsi_cmd.length,
    244 			scsi_cmd.trans_len, NO_CLEANUP, -1);
    245 	}
    246 #endif
    247 
    248 	/* Read AHS.  Need to optimize/clean this.   */
    249 	/* We should not be calling malloc(). */
    250 	/* We need to check for properly formated AHS segments. */
    251 
    252 	if (scsi_cmd.ahs_len) {
    253 		uint32_t        ahs_len;
    254 		uint8_t  *ahs_ptr;
    255 		uint8_t   ahs_type;
    256 
    257 		iscsi_trace(TRACE_ISCSI_DEBUG,
    258 				"reading %u bytes AHS\n", scsi_cmd.ahs_len);
    259 		scsi_cmd.ahs = iscsi_malloc_atomic((unsigned)scsi_cmd.ahs_len);
    260 		if (scsi_cmd.ahs == NULL) {
    261 			iscsi_err(__FILE__, __LINE__,
    262 				"iscsi_malloc_atomic() failed\n");
    263 			result = -1;
    264 			goto out;
    265 		}
    266 		if (iscsi_sock_msg(sess->sock, 0, (unsigned)scsi_cmd.ahs_len,
    267 				scsi_cmd.ahs, 0, sess->sess_params.header_digest) != scsi_cmd.ahs_len) {
    268 			iscsi_err(__FILE__, __LINE__,
    269 				"iscsi_sock_msg() failed\n");
    270 			result = -1;
    271 			goto out;
    272 		}
    273 		iscsi_trace(TRACE_ISCSI_DEBUG,
    274 				"read %u bytes AHS\n", scsi_cmd.ahs_len);
    275 		for (ahs_ptr = scsi_cmd.ahs;
    276 		     ahs_ptr < (scsi_cmd.ahs + scsi_cmd.ahs_len - 1) ;
    277 		     ahs_ptr += ahs_len) {
    278 			ahs_len = ISCSI_NTOHS(*((uint16_t *) (void *)ahs_ptr));
    279 			if (ahs_len == 0) {
    280 				iscsi_err(__FILE__, __LINE__,
    281 				 		"Zero ahs_len\n");
    282 				result = -1;
    283 				goto out;
    284 			}
    285 			switch (ahs_type = *(ahs_ptr + 2)) {
    286 			case ISCSI_AHS_EXTENDED_CDB:
    287 				iscsi_trace(TRACE_ISCSI_DEBUG,
    288 					"Got ExtendedCDB AHS - %u bytes extra "
    289 					"CDB)\n", ahs_len - 1);
    290 				scsi_cmd.ext_cdb = ahs_ptr + 4;
    291 				break;
    292 			case ISCSI_AHS_BIDI_READ:
    293 				scsi_cmd.bidi_trans_len =
    294 					ISCSI_NTOHL(*((uint32_t *)(void *)
    295 							(ahs_ptr + 4)));
    296 				*((uint32_t *)(void *)(ahs_ptr + 4)) =
    297 						scsi_cmd.bidi_trans_len;
    298 				iscsi_trace(TRACE_ISCSI_DEBUG,
    299 					"Got Bidirectional Read AHS "
    300 					"(expected read length %u)\n",
    301 					scsi_cmd.bidi_trans_len);
    302 				break;
    303 			default:
    304 				iscsi_err(__FILE__, __LINE__,
    305 					"unknown AHS type %x\n", ahs_type);
    306 				result = -1;
    307 				goto out;
    308 			}
    309 		}
    310 		iscsi_trace(TRACE_ISCSI_DEBUG,
    311 			"done parsing %u bytes AHS\n", scsi_cmd.ahs_len);
    312 	} else {
    313 		iscsi_trace(TRACE_ISCSI_DEBUG, "no AHS to read\n");
    314 		scsi_cmd.ahs = NULL;
    315 	}
    316 
    317 	sess->ExpCmdSN++;
    318 	sess->MaxCmdSN++;
    319 
    320 	/* Execute cdb.  device_command() will set scsi_cmd.input if
    321 	* there is input data and set the length of the input to
    322 	* either scsi_cmd.trans_len or scsi_cmd.bidi_trans_len,
    323 	* depending on whether scsi_cmd.output was set.  */
    324 	scsi_cmd.send_data = sess->buff;
    325 	scsi_cmd.input = 0;
    326 	cmd.scsi_cmd = &scsi_cmd;
    327 	cmd.callback = NULL;
    328 	if (device_command(sess, &cmd) != 0) {
    329 		iscsi_err(__FILE__, __LINE__,
    330 				"device_command() failed\n");
    331 		result = -1;
    332 		goto out;
    333 	}
    334 	/* Send any input data */
    335 
    336 	scsi_cmd.bytes_sent = 0;
    337 	if (!scsi_cmd.status && scsi_cmd.input) {
    338 		struct iovec    sg_singleton;
    339 		struct iovec   *sg, *sg_orig;
    340 		int             sg_len_orig, sg_len;
    341 		uint32_t        offset, trans_len;
    342 		int             fragment_flag = 0;
    343 		int             offset_inc;
    344 
    345 		if (scsi_cmd.output) {
    346 			iscsi_trace(TRACE_ISCSI_DEBUG,
    347 				"sending %u bytes bi-directional input data\n",
    348 				scsi_cmd.bidi_trans_len);
    349 			trans_len = scsi_cmd.bidi_trans_len;
    350 		} else {
    351 			trans_len = scsi_cmd.trans_len;
    352 		}
    353 		iscsi_trace(TRACE_ISCSI_DEBUG,
    354 			"sending %u bytes input data as separate PDUs\n",
    355 			trans_len);
    356 
    357 		if (scsi_cmd.send_sg_len) {
    358 			sg_orig = (struct iovec *)(void *)scsi_cmd.send_data;
    359 			sg_len_orig = scsi_cmd.send_sg_len;
    360 		} else {
    361 			sg_len_orig = 1;
    362 			sg_singleton.iov_base = scsi_cmd.send_data;
    363 			sg_singleton.iov_len = trans_len;
    364 			sg_orig = &sg_singleton;
    365 		}
    366 		sg = sg_orig;
    367 		sg_len = sg_len_orig;
    368 
    369 		offset_inc = (sess->sess_params.max_dataseg_len) ?
    370 			sess->sess_params.max_dataseg_len : trans_len;
    371 
    372 		for (offset = 0; offset < trans_len; offset += offset_inc) {
    373 			(void) memset(&data, 0x0, sizeof(data));
    374 			data.length = (sess->sess_params.max_dataseg_len) ?
    375 				MIN(trans_len - offset,
    376 					sess->sess_params.max_dataseg_len) :
    377 				trans_len - offset;
    378 			if (data.length != trans_len) {
    379 				if (!fragment_flag) {
    380 					sg_new = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len_orig);
    381 					if (sg_new == NULL) {
    382 						iscsi_err(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n");
    383 						result = -1;
    384 						goto out;
    385 					}
    386 					fragment_flag++;
    387 				}
    388 				sg = sg_new;
    389 				sg_len = sg_len_orig;
    390 				(void) memcpy(sg, sg_orig, sizeof(struct iovec) * sg_len_orig);
    391 				if (modify_iov(&sg, &sg_len, offset, data.length) != 0) {
    392 					iscsi_err(__FILE__, __LINE__, "modify_iov() failed\n");
    393 					result = -1;
    394 					goto out;
    395 				}
    396 			}
    397 			iscsi_trace(TRACE_ISCSI_DEBUG, "sending read data PDU (offset %u, len %u)\n", offset, data.length);
    398 			if (offset + data.length == trans_len) {
    399 				data.final = 1;
    400 
    401 				if (sess->UsePhaseCollapsedRead) {
    402 					data.status = 1;
    403 					data.status = scsi_cmd.status;
    404 					data.StatSN = ++(sess->StatSN);
    405 					iscsi_trace(TRACE_ISCSI_DEBUG, "status %#x collapsed into last data PDU\n", data.status);
    406 				} else {
    407 					iscsi_trace(TRACE_ISCSI_DEBUG, "NOT collapsing status with last data PDU\n");
    408 				}
    409 			} else if (offset + data.length > trans_len) {
    410 				iscsi_err(__FILE__, __LINE__, "offset+data.length > trans_len??\n");
    411 				result = -1;
    412 				goto out;
    413 			}
    414 			data.task_tag = scsi_cmd.tag;
    415 			data.ExpCmdSN = sess->ExpCmdSN;
    416 			data.MaxCmdSN = sess->MaxCmdSN;
    417 			data.DataSN = DataSN++;
    418 			data.offset = offset;
    419 			if (iscsi_read_data_encap(rsp_header, &data) != 0) {
    420 				iscsi_err(__FILE__, __LINE__, "iscsi_read_data_encap() failed\n");
    421 				result = -1;
    422 				goto out;
    423 			}
    424 			if ((uint32_t)iscsi_sock_send_header_and_data(
    425 				sess->sock, rsp_header, ISCSI_HEADER_LEN,
    426 				sg, data.length, sg_len,
    427 				sess->sess_params.header_digest,
    428 				sess->sess_params.data_digest) != ISCSI_HEADER_LEN + data.length) {
    429 				iscsi_err(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n");
    430 				result = -1;
    431 				goto out;
    432 			}
    433 			scsi_cmd.bytes_sent += data.length;
    434 			iscsi_trace(TRACE_ISCSI_DEBUG, "sent read data PDU ok (offset %u, len %u)\n", data.offset, data.length);
    435 		}
    436 		iscsi_trace(TRACE_ISCSI_DEBUG, "successfully sent %u bytes read data\n", trans_len);
    437 	}
    438 	/*
    439          * Send a response PDU if
    440          *
    441          * 1) we're not using phase collapsed input (and status was good)
    442          * 2) we are using phase collapsed input, but there was no input data (e.g., TEST UNIT READY)
    443          * 3) command had non-zero status and possible sense data
    444          */
    445 response:
    446 	if (!sess->UsePhaseCollapsedRead || !scsi_cmd.length || scsi_cmd.status) {
    447 		iscsi_trace(TRACE_ISCSI_DEBUG, "sending SCSI response PDU\n");
    448 		(void) memset(&scsi_rsp, 0x0, sizeof(scsi_rsp));
    449 		scsi_rsp.length = scsi_cmd.status ? scsi_cmd.length : 0;
    450 		scsi_rsp.tag = scsi_cmd.tag;
    451 		/* If r2t send, then the StatSN is already incremented */
    452 		if (sess->StatSN < scsi_cmd.ExpStatSN) {
    453 			++sess->StatSN;
    454 		}
    455 		scsi_rsp.StatSN = sess->StatSN;
    456 		scsi_rsp.ExpCmdSN = sess->ExpCmdSN;
    457 		scsi_rsp.MaxCmdSN = sess->MaxCmdSN;
    458 		scsi_rsp.ExpDataSN = (!scsi_cmd.status && scsi_cmd.input) ? DataSN : 0;
    459 		scsi_rsp.response = 0x00;	/* iSCSI response */
    460 		scsi_rsp.status = scsi_cmd.status;	/* SCSI status */
    461 		if (iscsi_scsi_rsp_encap(rsp_header, &scsi_rsp) != 0) {
    462 			iscsi_err(__FILE__, __LINE__, "iscsi_scsi_rsp_encap() failed\n");
    463 			result = -1;
    464 			goto out;
    465 		}
    466 		if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock,
    467 			rsp_header, ISCSI_HEADER_LEN, scsi_cmd.send_data,
    468 			scsi_rsp.length, 0,
    469 			sess->sess_params.header_digest,
    470 			sess->sess_params.data_digest) != ISCSI_HEADER_LEN + scsi_rsp.length) {
    471 			iscsi_err(__FILE__, __LINE__,
    472 				"iscsi_sock_send_header_and_data() failed\n");
    473 			result = -1;
    474 			goto out;
    475 		}
    476 		/* Make sure all data was transferred */
    477 
    478 		if (scsi_cmd.output) {
    479 			if (scsi_cmd.bytes_recv != scsi_cmd.trans_len) {
    480 				iscsi_err(__FILE__, __LINE__,
    481 					"scsi_cmd.bytes_recv");
    482 				result = -1;
    483 				goto out;
    484 			}
    485 			if (scsi_cmd.input) {
    486 				if (scsi_cmd.bytes_sent !=
    487 						scsi_cmd.bidi_trans_len) {
    488 					iscsi_err(__FILE__, __LINE__,
    489 						"scsi_cmd.bytes_sent");
    490 					result = -1;
    491 					goto out;
    492 				}
    493 			}
    494 		} else {
    495 			if (scsi_cmd.input) {
    496 				if (scsi_cmd.bytes_sent != scsi_cmd.trans_len) {
    497 					iscsi_err(__FILE__, __LINE__,
    498 						"scsi_cmd.bytes_sent");
    499 					result = -1;
    500 					goto out;
    501 				}
    502 			}
    503 		}
    504 	}
    505 
    506 	/* Device callback after command has completed */
    507 	if (cmd.callback) {
    508 		iscsi_trace(TRACE_ISCSI_DEBUG, "issuing device callback\n");
    509 		if ((*cmd.callback)(cmd.callback_arg) != 0) {
    510 			iscsi_err(__FILE__, __LINE__,
    511 				"device callback failed\n");
    512 			result = -1;
    513 			goto out;
    514 		}
    515 	}
    516 	result = 0;
    517 out:
    518 	if (scsi_cmd.ahs != NULL) {					\
    519 		iscsi_free_atomic(scsi_cmd.ahs);			\
    520 	}								\
    521 	if (sg_new != NULL) {
    522 		iscsi_free_atomic(sg_new);
    523 	}
    524 	free(scsi_cmd.send_buffer);
    525 	return result;
    526 }
    527 
    528 static int
    529 task_command_t(target_session_t * sess, uint8_t *header)
    530 {
    531 	iscsi_task_cmd_t cmd;
    532 	iscsi_task_rsp_t rsp;
    533 	uint8_t   rsp_header[ISCSI_HEADER_LEN];
    534 
    535 	/* Get & check args */
    536 
    537 	if (iscsi_task_cmd_decap(header, &cmd) != 0) {
    538 		iscsi_err(__FILE__, __LINE__,
    539 				"iscsi_task_cmd_decap() failed\n");
    540 		return -1;
    541 	}
    542 	if (cmd.CmdSN != sess->ExpCmdSN) {
    543 		iscsi_warn(__FILE__, __LINE__,
    544 			"Expected CmdSN %d, got %d. "
    545 			"(ignoring and resetting expectations)\n",
    546 			 cmd.CmdSN, sess->ExpCmdSN);
    547 		sess->ExpCmdSN = cmd.CmdSN;
    548 	}
    549 	sess->MaxCmdSN++;
    550 
    551 	(void) memset(&rsp, 0x0, sizeof(rsp));
    552 	rsp.response = ISCSI_TASK_RSP_FUNCTION_COMPLETE;
    553 
    554 	switch (cmd.function) {
    555 	case ISCSI_TASK_CMD_ABORT_TASK:
    556 		printf("ISCSI_TASK_CMD_ABORT_TASK\n");
    557 		break;
    558 	case ISCSI_TASK_CMD_ABORT_TASK_SET:
    559 		printf("ISCSI_TASK_CMD_ABORT_TASK_SET\n");
    560 		break;
    561 	case ISCSI_TASK_CMD_CLEAR_ACA:
    562 		printf("ISCSI_TASK_CMD_CLEAR_ACA\n");
    563 		break;
    564 	case ISCSI_TASK_CMD_CLEAR_TASK_SET:
    565 		printf("ISCSI_TASK_CMD_CLEAR_TASK_SET\n");
    566 		break;
    567 	case ISCSI_TASK_CMD_LOGICAL_UNIT_RESET:
    568 		printf("ISCSI_TASK_CMD_LOGICAL_UNIT_RESET\n");
    569 		break;
    570 	case ISCSI_TASK_CMD_TARGET_WARM_RESET:
    571 		printf("ISCSI_TASK_CMD_TARGET_WARM_RESET\n");
    572 		break;
    573 	case ISCSI_TASK_CMD_TARGET_COLD_RESET:
    574 		printf("ISCSI_TASK_CMD_TARGET_COLD_RESET\n");
    575 		break;
    576 	case ISCSI_TASK_CMD_TARGET_REASSIGN:
    577 		printf("ISCSI_TASK_CMD_TARGET_REASSIGN\n");
    578 		break;
    579 	default:
    580 		iscsi_err(__FILE__, __LINE__, "Unknown task function %d\n", cmd.function);
    581 		rsp.response = ISCSI_TASK_RSP_REJECTED;
    582 	}
    583 
    584 	rsp.tag = cmd.tag;
    585 	rsp.StatSN = ++(sess->StatSN);
    586 	rsp.ExpCmdSN = sess->ExpCmdSN;
    587 	rsp.MaxCmdSN = sess->MaxCmdSN;
    588 
    589 	if (iscsi_task_rsp_encap(rsp_header, &rsp) != 0) {
    590 		iscsi_err(__FILE__, __LINE__, "iscsi_task_cmd_decap() failed\n");
    591 		return -1;
    592 	}
    593 	if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0, sess->sess_params.header_digest) != ISCSI_HEADER_LEN) {
    594 		iscsi_err(__FILE__, __LINE__, "iscsi_sock_msg() failed\n");
    595 		return -1;
    596 
    597 	}
    598 	return 0;
    599 }
    600 
    601 static int
    602 nop_out_t(target_session_t * sess, uint8_t *header)
    603 {
    604 	iscsi_nop_out_args_t nop_out;
    605 	char           *ping_data = NULL;
    606 
    607 	if (iscsi_nop_out_decap(header, &nop_out) != 0) {
    608 		iscsi_err(__FILE__, __LINE__, "iscsi_nop_out_decap() failed\n");
    609 		return -1;
    610 	}
    611 	if (nop_out.CmdSN != sess->ExpCmdSN) {
    612 		iscsi_warn(__FILE__, __LINE__, "Expected CmdSN %d, got %d. (ignoring and resetting expectations)\n",
    613 			      nop_out.CmdSN, sess->ExpCmdSN);
    614 		sess->ExpCmdSN = nop_out.CmdSN;
    615 	}
    616 	/* TODO Clarify whether we need to update the CmdSN */
    617 	/* sess->ExpCmdSN++;  */
    618 	/* sess->MaxCmdSN++;  */
    619 
    620 	if (nop_out.length) {
    621 		iscsi_trace(TRACE_ISCSI_DEBUG, "reading %u bytes ping data\n", nop_out.length);
    622 		if ((ping_data = iscsi_malloc(nop_out.length)) == NULL) {
    623 			iscsi_err(__FILE__, __LINE__, "iscsi_malloc() failed\n");
    624 			return -1;
    625 		}
    626 		if ((uint32_t)iscsi_sock_msg(sess->sock, 0, nop_out.length, ping_data, 0, sess->sess_params.header_digest) != nop_out.length) {
    627 			iscsi_err(__FILE__, __LINE__, "iscsi_sock_msg() failed\n");
    628 			if (ping_data) {
    629 				iscsi_free(ping_data);
    630 			}
    631 			return -1;
    632 		}
    633 		iscsi_trace(TRACE_ISCSI_DEBUG, "successfully read %u bytes ping data:\n", nop_out.length);
    634 		iscsi_print_buffer(ping_data, nop_out.length);
    635 	}
    636 	if (nop_out.tag != 0xffffffff) {
    637 		iscsi_nop_in_args_t  nop_in;
    638 		uint8_t   rsp_header[ISCSI_HEADER_LEN];
    639 
    640 		iscsi_trace(TRACE_ISCSI_DEBUG, "sending %u bytes ping response\n", nop_out.length);
    641 		(void) memset(&nop_in, 0x0, sizeof(nop_in));
    642 		nop_in.length = nop_out.length;
    643 		nop_in.lun = nop_out.lun;
    644 		nop_in.tag = nop_out.tag;
    645 		nop_in.transfer_tag = 0xffffffff;
    646 		nop_in.StatSN = ++(sess->StatSN);
    647 		nop_in.ExpCmdSN = sess->ExpCmdSN;
    648 		nop_in.MaxCmdSN = sess->MaxCmdSN;
    649 
    650 		if (iscsi_nop_in_encap(rsp_header, &nop_in) != 0) {
    651 			iscsi_err(__FILE__, __LINE__, "iscsi_nop_in_encap() failed\n");
    652 			if (ping_data) {
    653 				iscsi_free(ping_data);
    654 			}
    655 			return -1;
    656 		}
    657 		if ((uint32_t)iscsi_sock_send_header_and_data(
    658 			sess->sock, rsp_header, ISCSI_HEADER_LEN,
    659 			ping_data, nop_in.length, 0,
    660 			sess->sess_params.header_digest,
    661 			sess->sess_params.data_digest) != ISCSI_HEADER_LEN + nop_in.length) {
    662 			iscsi_err(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n");
    663 			if (ping_data) {
    664 				iscsi_free(ping_data);
    665 			}
    666 			return -1;
    667 		}
    668 		iscsi_trace(TRACE_ISCSI_DEBUG, "successfully sent %u bytes ping response\n", nop_out.length);
    669 	}
    670 	if (ping_data) {
    671 		iscsi_free(ping_data);
    672 	}
    673 	return 0;
    674 }
    675 
    676 /*
    677  * text_command_t
    678  */
    679 
    680 static int
    681 text_command_t(target_session_t * sess, uint8_t *header)
    682 {
    683 	iscsi_text_cmd_args_t	 text_cmd;
    684 	iscsi_text_rsp_args_t	 text_rsp;
    685 	unsigned		 len_in;
    686 	uint32_t		 i;
    687 	uint8_t   		 rsp_header[ISCSI_HEADER_LEN];
    688 	targv_t			*targv;
    689 	char           		*text_in = NULL;
    690 	char           		*text_out = NULL;
    691 	char			 buf[BUFSIZ];
    692 	int			 len_out = 0;
    693 
    694 #define TC_CLEANUP do {							\
    695 	if (text_in != NULL) {						\
    696 		iscsi_free_atomic(text_in);				\
    697 	}								\
    698 	if (text_out != NULL) {						\
    699 		iscsi_free_atomic(text_out);				\
    700 	}								\
    701 } while (/* CONSTCOND */ 0)
    702 #define TC_ERROR {							\
    703 	TC_CLEANUP;							\
    704 	return -1;							\
    705 }
    706 	/* Get text args */
    707 
    708 	if (iscsi_text_cmd_decap(header, &text_cmd) != 0) {
    709 		iscsi_err(__FILE__, __LINE__, "iscsi_text_cmd_decap() failed\n");
    710 		return -1;
    711 	}
    712 	/* Check args & update numbering */
    713 #if 0
    714 	RETURN_NOT_EQUAL("Continue", text_cmd.cont, 0, NO_CLEANUP, -1);
    715 	RETURN_NOT_EQUAL("CmdSN", text_cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1);
    716 #else
    717 	if (text_cmd.cont != 0) {
    718 		iscsi_err(__FILE__, __LINE__, "Continue");
    719 		NO_CLEANUP;
    720 		return -1;
    721 	}
    722 	if (text_cmd.CmdSN != sess->ExpCmdSN) {
    723 		iscsi_err(__FILE__, __LINE__, "CmdSN");
    724 		NO_CLEANUP;
    725 		return -1;
    726 	}
    727 #endif
    728 
    729 	sess->ExpCmdSN++;
    730 	sess->MaxCmdSN++;
    731 
    732 	if ((text_out = iscsi_malloc_atomic(2048)) == NULL) {
    733 		iscsi_err(__FILE__, __LINE__,
    734 				"iscsi_malloc_atomic() failed\n");
    735 		return -1;
    736 	}
    737 
    738 	/* Read text parameters */
    739 	if ((len_in = text_cmd.length) != 0) {
    740 		iscsi_parameter_t *ptr;
    741 
    742 		if ((text_in = iscsi_malloc_atomic(len_in + 1)) == NULL) {
    743 			iscsi_err(__FILE__, __LINE__,
    744 				"iscsi_malloc_atomic() failed\n");
    745 			TC_CLEANUP;
    746 			return -1;
    747 		}
    748 		iscsi_trace(TRACE_ISCSI_DEBUG,
    749 			"reading %u bytes text parameters\n", len_in);
    750 		if ((unsigned)iscsi_sock_msg(sess->sock, 0, len_in, text_in,
    751 				0, sess->sess_params.header_digest) != len_in) {
    752 			iscsi_err(__FILE__, __LINE__,
    753 				"iscsi_sock_msg() failed\n");
    754 			TC_CLEANUP;
    755 			return -1;
    756 		}
    757 		text_in[len_in] = 0x0;
    758 		PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred,
    759 			text_in, (int) len_in, text_out,
    760 			(int *)(void *)&len_out, 2048, 0, TC_ERROR);
    761 
    762 		/*
    763 		 * Handle exceptional cases not covered by parameters.c
    764 		 * (e.g., SendTargets)
    765 		 */
    766 		if ((ptr = param_get(sess->params, "SendTargets")) == NULL) {
    767 			iscsi_err(__FILE__, __LINE__,
    768 					"param_get() failed\n");
    769 			TC_CLEANUP;
    770 			return -1;
    771 		}
    772 		if (ptr->rx_offer) {
    773 			if (strcmp(ptr->offer_rx, "All") == 0 &&
    774 			    !param_equiv(sess->params, "SessionType",
    775 			    	"Discovery")) {
    776 				iscsi_trace(TRACE_ISCSI_DEBUG,
    777 					"Rejecting SendTargets=All in a "
    778 					"non Discovery session\n");
    779 				PARAM_TEXT_ADD(sess->params, "SendTargets",
    780 					"Reject", text_out, &len_out, 2048,
    781 					0, TC_ERROR);
    782 			} else {
    783 				targv = sess->target->lunv;
    784 				for (i = 0 ; i < targv->c ; i++) {
    785 					if (sess->address_family == 6 ||
    786 					    (sess->address_family == 4 &&
    787 					    	allow_netmask(targv->v[i].mask,
    788 						sess->initiator))) {
    789 						(void) get_iqn(sess, i, buf,
    790 							sizeof(buf));
    791 						PARAM_TEXT_ADD(sess->params,
    792 							"TargetName", buf,
    793 							text_out, &len_out,
    794 							2048, 0, TC_ERROR);
    795 						PARAM_TEXT_ADD(sess->params,
    796 							"TargetAddress",
    797 			iscsi_target_getvar(sess->target, "target address"),
    798 							text_out, &len_out,
    799 							2048, 0, TC_ERROR);
    800 					} else {
    801 #ifdef HAVE_SYSLOG_H
    802 						syslog(LOG_INFO,
    803 							"WARNING: attempt to "
    804 							"discover targets from "
    805 							"%s (not allowed by %s)"
    806 							" has been rejected",
    807 							sess->initiator,
    808 							targv->v[0].mask);
    809 #endif
    810 					}
    811 				}
    812 			}
    813 			ptr->rx_offer = 0;
    814 		}
    815 		/* Parse outgoing offer */
    816 
    817 		if (len_out) {
    818 			PARAM_TEXT_PARSE(sess->params,
    819 				&sess->sess_params.cred, text_out, len_out,
    820 				NULL, NULL, 2048, 1, TC_ERROR);
    821 		}
    822 	}
    823 	if (sess->IsFullFeature) {
    824 		set_session_parameters(sess->params, &sess->sess_params);
    825 	}
    826 	/* Send response */
    827 
    828 	text_rsp.final = text_cmd.final;
    829 	text_rsp.cont = 0;
    830 	text_rsp.length = len_out;
    831 	text_rsp.lun = text_cmd.lun;
    832 	text_rsp.tag = text_cmd.tag;
    833 	text_rsp.transfer_tag = (text_rsp.final) ? 0xffffffff : 0x1234;
    834 	text_rsp.StatSN = ++(sess->StatSN);
    835 	text_rsp.ExpCmdSN = sess->ExpCmdSN;
    836 	text_rsp.MaxCmdSN = sess->MaxCmdSN;
    837 	if (iscsi_text_rsp_encap(rsp_header, &text_rsp) != 0) {
    838 		iscsi_err(__FILE__, __LINE__,
    839 			"iscsi_text_rsp_encap() failed\n");
    840 		TC_CLEANUP;
    841 		return -1;
    842 	}
    843 	if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0, sess->sess_params.header_digest) !=
    844 			ISCSI_HEADER_LEN) {
    845 		iscsi_err(__FILE__, __LINE__,
    846 			"iscsi_sock_msg() failed\n");
    847 		TC_CLEANUP;
    848 		return -1;
    849 	}
    850 	if (len_out && iscsi_sock_msg(sess->sock, 1, (unsigned) len_out,
    851 			text_out, 0, sess->sess_params.header_digest) != len_out) {
    852 		iscsi_err(__FILE__, __LINE__,
    853 			"iscsi_sock_msg() failed\n");
    854 		TC_CLEANUP;
    855 		return -1;
    856 	}
    857 	TC_CLEANUP;
    858 	return 0;
    859 }
    860 
    861 /* given a target's iqn, find the relevant target that we're exporting */
    862 int
    863 find_target_iqn(target_session_t *sess)
    864 {
    865 	uint32_t	 i;
    866 	targv_t		*targv;
    867 	char		 buf[BUFSIZ];
    868 
    869 	targv = sess->target->lunv;
    870 	for (i = 0 ; i < targv->c ; i++) {
    871 		if (param_equiv(sess->params, "TargetName",
    872 				get_iqn(sess, i, buf, sizeof(buf)))) {
    873 			return sess->d = i;
    874 		}
    875 	}
    876 	return -1;
    877 }
    878 
    879 /* given a tsih, find the relevant target that we're exporting */
    880 int
    881 find_target_tsih(iscsi_target_t *target, int tsih)
    882 {
    883 	uint32_t	 i;
    884 	targv_t		*targv;
    885 
    886 	targv = target->lunv;
    887 	for (i = 0 ; i < targv->c ; i++) {
    888 		if (targv->v[i].tsih == tsih) {
    889 			return i;
    890 		}
    891 	}
    892 	return -1;
    893 }
    894 
    895 /*
    896  * login_command_t() handles login requests and replies.
    897  */
    898 
    899 static int
    900 login_command_t(target_session_t * sess, uint8_t *header)
    901 {
    902 	iscsi_login_cmd_args_t cmd;
    903 	iscsi_login_rsp_args_t rsp;
    904 	uint8_t		rsp_header[ISCSI_HEADER_LEN];
    905 	targv_t		*targv;
    906 	char           *text_in = NULL;
    907 	char           *text_out = NULL;
    908 	char		logbuf[BUFSIZ];
    909 	int             len_in = 0;
    910 	int             len_out = 0;
    911 	int             status = 0;
    912 	int		i;
    913 
    914 	/* Initialize response */
    915 
    916 #define LC_CLEANUP do {							\
    917 	if (text_in != NULL) {						\
    918 		iscsi_free_atomic(text_in);				\
    919 	}								\
    920 	if (text_out != NULL) {						\
    921 		iscsi_free_atomic(text_out);				\
    922 	}								\
    923 } while (/* CONSTCOND */ 0)
    924 #define LC_ERROR {							\
    925 	TC_CLEANUP;							\
    926 	return -1;							\
    927 }
    928 
    929 	(void) memset(&rsp, 0x0, sizeof(rsp));
    930 	rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
    931 
    932 	/* Get login args & check preconditions */
    933 
    934 	if (iscsi_login_cmd_decap(header, &cmd) != 0) {
    935 		iscsi_err(__FILE__, __LINE__,
    936 			"iscsi_login_cmd_decap() failed\n");
    937 		goto response;
    938 	}
    939 	if (sess->IsLoggedIn) {
    940 		iscsi_err(__FILE__, __LINE__,
    941 			"duplicate login attempt on sess %d\n", sess->id);
    942 		goto response;
    943 	}
    944 	if ((cmd.cont != 0) && (cmd.transit != 0)) {
    945 		iscsi_err(__FILE__, __LINE__,
    946 			"Bad cmd.continue.  Expected 0.\n");
    947 		goto response;
    948 	} else if ((cmd.version_max < ISCSI_VERSION) ||
    949 		   (cmd.version_min > ISCSI_VERSION)) {
    950 		iscsi_err(__FILE__, __LINE__,
    951 			"Target iscsi version (%u) not supported by initiator "
    952 			"[Max Ver (%u) and Min Ver (%u)]\n",
    953 			ISCSI_VERSION, cmd.version_max, cmd.version_min);
    954 		rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
    955 		rsp.status_detail = ISCSI_LOGIN_DETAIL_VERSION_NOT_SUPPORTED;
    956 		rsp.version_max = ISCSI_VERSION;
    957 		rsp.version_active = ISCSI_VERSION;
    958 		goto response;
    959 	} else if (cmd.tsih != 0) {
    960 		iscsi_err(__FILE__, __LINE__,
    961 			"Bad cmd.tsih (%u). Expected 0.\n", cmd.tsih);
    962 		goto response;
    963 	}
    964 
    965 	/* Parse text parameters and build response */
    966 	if ((text_out = iscsi_malloc_atomic(2048)) == NULL) {
    967 		iscsi_err(__FILE__, __LINE__,
    968 			"iscsi_malloc_atomic() failed\n");
    969 		return -1;
    970 	}
    971 	if ((len_in = cmd.length) != 0) {
    972 		iscsi_trace(TRACE_ISCSI_DEBUG,
    973 			"reading %d bytes text data\n", len_in);
    974 		text_in = iscsi_malloc_atomic((unsigned)(len_in + 1));
    975 		if (text_in == NULL) {
    976 			iscsi_err(__FILE__, __LINE__,
    977 				"iscsi_malloc() failed\n");
    978 			LC_CLEANUP;
    979 			return -1;
    980 		}
    981 		if (iscsi_sock_msg(sess->sock, 0, (unsigned) len_in, text_in,
    982 				0, sess->sess_params.header_digest) != len_in) {
    983 			iscsi_err(__FILE__, __LINE__,
    984 				"iscsi_sock_msg() failed\n");
    985 			LC_CLEANUP;
    986 			return -1;
    987 		}
    988 		text_in[len_in] = 0x0;
    989 		iscsi_trace(TRACE_ISCSI_DEBUG,
    990 			"successfully read %d bytes text data\n", len_in);
    991 
    992 		/*
    993 		 * Parse incoming parameters (text_out will contain the
    994 		 * response we need
    995 		 */
    996 
    997 		/* to send back to the initiator */
    998 
    999 
   1000 		status = param_text_parse(sess->params,
   1001 				&sess->sess_params.cred, text_in, len_in,
   1002 				text_out, &len_out, 2048, 0);
   1003 		if (status != 0) {
   1004 			switch (status) {
   1005 			case ISCSI_PARAM_STATUS_FAILED:
   1006 				rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS;
   1007 				break;
   1008 			case ISCSI_PARAM_STATUS_AUTH_FAILED:
   1009 				rsp.status_detail =
   1010 					ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE;
   1011 				break;
   1012 			default:
   1013 				/*
   1014 				 * We will need to set the detail
   1015 				 * field based on more detailed error
   1016 				 * cases.  Will need to fix this if
   1017 				 * compliciance test break
   1018 		                 * (status_detail field).
   1019 		                 */
   1020 				break;
   1021 			}
   1022 			goto response;
   1023 		}
   1024 		/* Parse the outgoing offer */
   1025 		if (!sess->LoginStarted) {
   1026 			PARAM_TEXT_ADD(sess->params, "TargetPortalGroupTag",
   1027 				"1", text_out, &len_out, 2048, 0, LC_ERROR);
   1028 		}
   1029 		if (len_out) {
   1030 			PARAM_TEXT_PARSE(sess->params,
   1031 				&sess->sess_params.cred, text_out, len_out,
   1032 				NULL, NULL, 2048, 1, LC_ERROR;
   1033 			);
   1034 		}
   1035 	}
   1036 	if (!sess->LoginStarted) {
   1037 		sess->LoginStarted = 1;
   1038 	}
   1039 	/*
   1040 	 * For now, we accept what ever the initiators' current and next
   1041 	 * states are. And le are always
   1042 	 */
   1043 	/* ready to transitition to that state. */
   1044 
   1045 	rsp.csg = cmd.csg;
   1046 	rsp.nsg = cmd.nsg;
   1047 	rsp.transit = cmd.transit;
   1048 
   1049 	if (cmd.csg == ISCSI_LOGIN_STAGE_SECURITY) {
   1050 		if (param_equiv(sess->params, "AuthResult", "No")) {
   1051 			rsp.transit = 0;
   1052 		} else if (param_equiv(sess->params, "AuthResult", "Fail")) {
   1053 			rsp.status_class = rsp.status_detail =
   1054 				ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE;
   1055 			goto response;
   1056 		}
   1057 	}
   1058 	if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) {
   1059 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1060 			"transitioning to ISCSI_LOGIN_STAGE_FULL_FEATURE\n");
   1061 
   1062 		/* Check post conditions */
   1063 		if (param_equiv(sess->params, "InitiatorName", "")) {
   1064 			iscsi_err(__FILE__, __LINE__,
   1065 				"InitiatorName not specified\n");
   1066 			goto response;
   1067 		}
   1068 		if (param_equiv(sess->params, "SessionType", "Normal")) {
   1069 			if (param_equiv(sess->params, "TargetName", "")) {
   1070 				iscsi_err(__FILE__, __LINE__,
   1071 					"TargetName not specified\n");
   1072 				goto response;
   1073 			}
   1074 			if ((i = find_target_iqn(sess)) < 0) {
   1075 				iscsi_err(__FILE__, __LINE__,
   1076 					"Bad TargetName \"%s\"\n",
   1077 					param_val(sess->params, "TargetName"));
   1078 				goto response;
   1079 			}
   1080 			if (cmd.tsih != 0 &&
   1081 			    find_target_tsih(sess->target, cmd.tsih) != i) {
   1082 				targv = sess->target->lunv;
   1083 				iscsi_err(__FILE__, __LINE__,
   1084 					"target tsih expected %d, cmd.tsih %d, "
   1085 					"i %d\n", targv->v[i].tsih, cmd.tsih,
   1086 					i);
   1087 			}
   1088 			sess->d = i;
   1089 		} else if ((i = find_target_tsih(sess->target, cmd.tsih)) < 0) {
   1090 			iscsi_err(__FILE__, __LINE__,
   1091 				"Abnormal SessionType cmd.tsih %d not found\n",
   1092 				cmd.tsih);
   1093 			i = sess->d;
   1094 		}
   1095 		if (param_equiv(sess->params, "SessionType", "")) {
   1096 			iscsi_err(__FILE__, __LINE__,
   1097 				"SessionType not specified\n");
   1098 			goto response;
   1099 		}
   1100 		sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN;
   1101 		sess->cid = cmd.cid;
   1102 		sess->isid = cmd.isid;
   1103 
   1104 		targv = sess->target->lunv;
   1105 		targv->v[i].tsih = sess->tsih = ++sess->target->last_tsih;
   1106 		sess->IsFullFeature = 1;
   1107 
   1108 		sess->IsLoggedIn = 1;
   1109 		if (!param_equiv(sess->params, "SessionType", "Discovery")) {
   1110 			(void) strlcpy(param_val(sess->params,
   1111 					"MaxConnections"), "1", 2);
   1112 		}
   1113 		set_session_parameters(sess->params, &sess->sess_params);
   1114 	} else {
   1115 		if ((i = find_target_tsih(sess->target, cmd.tsih)) < 0) {
   1116 			iscsi_err(__FILE__, __LINE__,
   1117 				"cmd.tsih %d not found\n", cmd.tsih);
   1118 		}
   1119 	}
   1120 
   1121 	/* No errors */
   1122 	rsp.status_class = rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS;
   1123 	rsp.length = len_out;
   1124 
   1125 	/* Send login response */
   1126 response:
   1127 	sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN;
   1128 	rsp.isid = cmd.isid;
   1129 	rsp.StatSN = cmd.ExpStatSN;	/* debug  */
   1130 	rsp.tag = cmd.tag;
   1131 	rsp.cont = cmd.cont;
   1132 	rsp.ExpCmdSN = sess->ExpCmdSN;
   1133 	rsp.MaxCmdSN = sess->MaxCmdSN;
   1134 	if (!rsp.status_class) {
   1135 		if (rsp.transit &&
   1136 		    (rsp.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE)) {
   1137 			rsp.version_max = ISCSI_VERSION;
   1138 			rsp.version_active = ISCSI_VERSION;
   1139 			rsp.StatSN = ++(sess->StatSN);
   1140 			rsp.tsih = sess->tsih;
   1141 		}
   1142 	}
   1143 	if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) {
   1144 		iscsi_err(__FILE__, __LINE__,
   1145 			"iscsi_login_rsp_encap() failed\n");
   1146 		LC_CLEANUP;
   1147 		return -1;
   1148 	}
   1149 	iscsi_trace(TRACE_ISCSI_DEBUG, "sending login response\n");
   1150 	if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header,
   1151 			ISCSI_HEADER_LEN, text_out, rsp.length, 0,
   1152 			sess->sess_params.header_digest,
   1153 			sess->sess_params.data_digest) != ISCSI_HEADER_LEN + rsp.length) {
   1154 		iscsi_err(__FILE__, __LINE__,
   1155 			"iscsi_sock_send_header_and_data() failed\n");
   1156 		LC_CLEANUP;
   1157 		return -1;
   1158 	}
   1159 	iscsi_trace(TRACE_ISCSI_DEBUG,
   1160 		"sent login response ok\n");
   1161 	if (rsp.status_class != 0) {
   1162 		LC_CLEANUP;
   1163 		return -1;
   1164 	}
   1165 	if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) {
   1166 
   1167 		/* log information to stdout */
   1168 		(void) snprintf(logbuf, sizeof(logbuf),
   1169 			"> iSCSI %s login  successful from %s on %s disk %d, "
   1170 			"ISID %" PRIu64 ", TSIH %u",
   1171 			param_val(sess->params, "SessionType"),
   1172 			param_val(sess->params, "InitiatorName"),
   1173 			sess->initiator,
   1174 			sess->d,
   1175 			sess->isid,
   1176 			sess->tsih);
   1177 		printf("%s\n", logbuf);
   1178 #ifdef HAVE_SYSLOG_H
   1179 		/* log information to syslog */
   1180 		syslog(LOG_INFO, "%s", logbuf);
   1181 #endif
   1182 
   1183 		/* Buffer for data xfers to/from the scsi device */
   1184 		if (!param_equiv(sess->params, "MaxRecvDataSegmentLength",
   1185 					"0")) {
   1186 			sess->buff = iscsi_malloc((unsigned)(
   1187 					param_atoi(sess->params,
   1188 					"MaxRecvDataSegmentLength")));
   1189 			if (sess->buff == NULL) {
   1190 				iscsi_err(__FILE__, __LINE__,
   1191 					"iscsi_malloc() failed\n");
   1192 				LC_CLEANUP;
   1193 				return -1;
   1194 			}
   1195 		} else {
   1196 			iscsi_err(__FILE__, __LINE__,
   1197 				"0 MaxRecvDataSegmentLength not supported\n");
   1198 			LC_CLEANUP;
   1199 			return -1;
   1200 		}
   1201 	}
   1202 	LC_CLEANUP;
   1203 	return 0;
   1204 }
   1205 
   1206 static int
   1207 logout_command_t(target_session_t * sess, uint8_t *header)
   1208 {
   1209 	iscsi_logout_cmd_args_t	cmd;
   1210 	iscsi_logout_rsp_args_t	rsp;
   1211 	targv_t			*targv;
   1212 	uint8_t			rsp_header[ISCSI_HEADER_LEN];
   1213 	char			logbuf[BUFSIZ];
   1214 	int			i;
   1215 
   1216 	(void) memset(&rsp, 0x0, sizeof(rsp));
   1217 	if (iscsi_logout_cmd_decap(header, &cmd) != 0) {
   1218 		iscsi_err(__FILE__, __LINE__,
   1219 			"iscsi_logout_cmd_decap() failed\n");
   1220 		return -1;
   1221 	}
   1222 	sess->StatSN = cmd.ExpStatSN;
   1223 	if ((cmd.reason == ISCSI_LOGOUT_CLOSE_RECOVERY) &&
   1224 	    (param_equiv(sess->params, "ErrorRecoveryLevel", "0"))) {
   1225 		rsp.response = ISCSI_LOGOUT_STATUS_NO_RECOVERY;
   1226 	}
   1227 #if 0
   1228 	RETURN_NOT_EQUAL("CmdSN", cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1);
   1229 	RETURN_NOT_EQUAL("ExpStatSN", cmd.ExpStatSN, sess->StatSN, NO_CLEANUP, -1);
   1230 #else
   1231 	if (cmd.CmdSN != sess->ExpCmdSN) {
   1232 		iscsi_err(__FILE__, __LINE__, "CmdSN");
   1233 		NO_CLEANUP;
   1234 		return -1;
   1235 	}
   1236 	if (cmd.ExpStatSN != sess->StatSN) {
   1237 		iscsi_err(__FILE__, __LINE__, "ExpStatSN");
   1238 		NO_CLEANUP;
   1239 		return -1;
   1240 	}
   1241 #endif
   1242 
   1243 	rsp.tag = cmd.tag;
   1244 	rsp.StatSN = sess->StatSN;
   1245 	rsp.ExpCmdSN = ++sess->ExpCmdSN;
   1246 	rsp.MaxCmdSN = sess->MaxCmdSN;
   1247 	if (iscsi_logout_rsp_encap(rsp_header, &rsp) != 0) {
   1248 		iscsi_err(__FILE__, __LINE__,
   1249 				"iscsi_logout_rsp_encap() failed\n");
   1250 		return -1;
   1251 	}
   1252 	if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0, sess->sess_params.header_digest) !=
   1253 			ISCSI_HEADER_LEN) {
   1254 		iscsi_err(__FILE__, __LINE__,
   1255 			"iscsi_sock_msg() failed\n");
   1256 		return -1;
   1257 	}
   1258 	iscsi_trace(TRACE_ISCSI_DEBUG, "sent logout response OK\n");
   1259 
   1260 	/* log information to stdout */
   1261 	(void) snprintf(logbuf, sizeof(logbuf),
   1262 		"< iSCSI %s logout successful from %s on %s "
   1263 		"disk %d, ISID %" PRIu64 ", TSIH %u",
   1264 		param_val(sess->params, "SessionType"),
   1265 		param_val(sess->params, "InitiatorName"),
   1266 		sess->initiator,
   1267 		sess->d,
   1268 		sess->isid,
   1269 		sess->tsih);
   1270 	printf("%s\n", logbuf);
   1271 #ifdef HAVE_SYSLOG
   1272 	/* log information to syslog */
   1273 	syslog(LOG_INFO, "%s", logbuf);
   1274 #endif
   1275 
   1276 	sess->IsLoggedIn = 0;
   1277 
   1278 	if (sess->sess_params.cred.user) {
   1279 		free(sess->sess_params.cred.user);
   1280 		sess->sess_params.cred.user = NULL;
   1281 	}
   1282 
   1283 	if ((i = find_target_tsih(sess->target, sess->tsih)) < 0) {
   1284 		iscsi_err(__FILE__, __LINE__,
   1285 			"logout sess->tsih %d not found\n", sess->tsih);
   1286 	} else {
   1287 		targv = sess->target->lunv;
   1288 		targv->v[i].tsih = 0;
   1289 	}
   1290 	sess->tsih = 0;
   1291 
   1292 	return 0;
   1293 }
   1294 
   1295 static int
   1296 verify_cmd_t(target_session_t * sess, uint8_t *header)
   1297 {
   1298 	int             op = ISCSI_OPCODE(header);
   1299 
   1300 	if ((!sess->LoginStarted) && (op != ISCSI_LOGIN_CMD)) {
   1301 		/* Terminate the connection */
   1302 		iscsi_err(__FILE__, __LINE__,
   1303 			"session %d: iSCSI op %#x attempted "
   1304 			"before LOGIN PHASE\n",
   1305 			    sess->id, op);
   1306 		return -1;
   1307 	}
   1308 	if (!sess->IsFullFeature &&
   1309 	    ((op != ISCSI_LOGIN_CMD) && (op != ISCSI_LOGOUT_CMD))) {
   1310 		iscsi_login_rsp_args_t rsp;
   1311 		uint8_t   rsp_header[ISCSI_HEADER_LEN];
   1312 		iscsi_err(__FILE__, __LINE__,
   1313 			"session %d: iSCSI op %#x before FULL FEATURE\n",
   1314 			sess->id, op);
   1315 		/* Create Login Reject response */
   1316 		(void) memset(&rsp, 0x0, sizeof(rsp));
   1317 		rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR;
   1318 		rsp.status_detail = ISCSI_LOGIN_DETAIL_NOT_LOGGED_IN;
   1319 		rsp.version_max = ISCSI_VERSION;
   1320 		rsp.version_active = ISCSI_VERSION;
   1321 
   1322 		if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) {
   1323 			iscsi_err(__FILE__, __LINE__,
   1324 				"iscsi_login_rsp_encap() failed\n");
   1325 			return -1;
   1326 		}
   1327 		iscsi_trace(TRACE_ISCSI_DEBUG, "sending login response\n");
   1328 		if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock,
   1329 				rsp_header, ISCSI_HEADER_LEN, NULL, 0, 0,
   1330 				sess->sess_params.header_digest,
   1331 				sess->sess_params.data_digest) !=
   1332 				ISCSI_HEADER_LEN + rsp.length) {
   1333 			iscsi_err(__FILE__, __LINE__,
   1334 				"iscsi_sock_send_header_and_data() failed\n");
   1335 			return -1;
   1336 		}
   1337 		iscsi_trace(TRACE_ISCSI_DEBUG, "sent login response ok\n");
   1338 		return -1;
   1339 	}
   1340 	return 0;
   1341 }
   1342 
   1343 /*
   1344  * this function looks at the opcode in the received header for the session,
   1345  * and does a switch on the opcode to call the required function.
   1346  */
   1347 static int
   1348 execute_t(target_session_t *sess, uint8_t *header)
   1349 {
   1350 	int             op = ISCSI_OPCODE(header);
   1351 
   1352 	if (verify_cmd_t(sess, header) != 0) {
   1353 		return -1;
   1354 	}
   1355 	switch (op) {
   1356 	case ISCSI_TASK_CMD:
   1357 		iscsi_trace(TRACE_ISCSI_CMD,
   1358 				"session %d: Task Command\n", sess->id);
   1359 		if (task_command_t(sess, header) != 0) {
   1360 			iscsi_err(__FILE__, __LINE__,
   1361 				"task_command_t() failed\n");
   1362 			return -1;
   1363 		}
   1364 		break;
   1365 
   1366 	case ISCSI_NOP_OUT:
   1367 		iscsi_trace(TRACE_ISCSI_CMD, "session %d: NOP-Out\n", sess->id);
   1368 		if (nop_out_t(sess, header) != 0) {
   1369 			iscsi_err(__FILE__, __LINE__,
   1370 				"nop_out_t() failed\n");
   1371 			return -1;
   1372 		}
   1373 		break;
   1374 
   1375 	case ISCSI_LOGIN_CMD:
   1376 		iscsi_trace(TRACE_ISCSI_CMD,
   1377 				"session %d: Login Command\n", sess->id);
   1378 		if (login_command_t(sess, header) != 0) {
   1379 			iscsi_err(__FILE__, __LINE__,
   1380 				"login_command_t() failed\n");
   1381 			return -1;
   1382 		}
   1383 		break;
   1384 
   1385 	case ISCSI_TEXT_CMD:
   1386 		iscsi_trace(TRACE_ISCSI_CMD,
   1387 				"session %d: Text Command\n", sess->id);
   1388 		if (text_command_t(sess, header) != 0) {
   1389 			iscsi_err(__FILE__, __LINE__,
   1390 				"text_command_t() failed\n");
   1391 			return -1;
   1392 		}
   1393 		break;
   1394 
   1395 	case ISCSI_LOGOUT_CMD:
   1396 		iscsi_trace(TRACE_ISCSI_CMD,
   1397 			"session %d: Logout Command\n", sess->id);
   1398 		if (logout_command_t(sess, header) != 0) {
   1399 			iscsi_err(__FILE__, __LINE__,
   1400 				"logout_command_t() failed\n");
   1401 			return -1;
   1402 		}
   1403 		break;
   1404 
   1405 	case ISCSI_SCSI_CMD:
   1406 		iscsi_trace(TRACE_ISCSI_CMD,
   1407 			"session %d: SCSI Command\n", sess->id);
   1408 		if (scsi_command_t(sess, header) != 0) {
   1409 			iscsi_err(__FILE__, __LINE__,
   1410 				"scsi_command_t() failed\n");
   1411 			return -1;
   1412 		}
   1413 		break;
   1414 
   1415 	default:
   1416 		iscsi_err(__FILE__, __LINE__, "Unknown Opcode %#x\n",
   1417 			ISCSI_OPCODE(header));
   1418 		if (reject_t(sess, header, 0x04) != 0) {
   1419 			iscsi_err(__FILE__, __LINE__,
   1420 				"reject_t() failed\n");
   1421 			return -1;
   1422 		}
   1423 		break;
   1424 	}
   1425 	return 0;
   1426 }
   1427 
   1428 /*
   1429  * Currently one thread per session, used for both Rx and Tx.
   1430  */
   1431 static int
   1432 worker_proc_t(void *arg)
   1433 {
   1434 	target_session_t *sess = (target_session_t *) arg;
   1435 	uint8_t   header[ISCSI_HEADER_LEN];
   1436 	iscsi_parameter_t **l = &sess->params;
   1437 
   1438 	ISCSI_THREAD_START("worker_thread");
   1439 	sess->worker.pid = getpid();
   1440 	sess->worker.state |= ISCSI_WORKER_STATE_STARTED;
   1441 	iscsi_trace(TRACE_ISCSI_DEBUG, "session %d: started\n", sess->id);
   1442 
   1443 	/*
   1444          * ISCSI_PARAM_TYPE_LIST format:        <type> <key> <dflt> <valid list values>
   1445          * ISCSI_PARAM_TYPE_BINARY format:      <type> <key> <dflt> <valid binary values>
   1446          * ISCSI_PARAM_TYPE_NUMERICAL format:   <type> <key> <dflt> <max>
   1447          * ISCSI_PARAM_TYPE_DECLARATIVE format: <type> <key> <dflt> ""
   1448          */
   1449 
   1450 	sess->params = NULL;
   1451 	l = &sess->params;
   1452 
   1453 	/* CHAP Parameters */
   1454 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthMethod", "CHAP", "CHAP,None", return -1);
   1455 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "CHAP_A", "None", "5", return -1);
   1456 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_N", "", "", return -1);
   1457 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_R", "", "", return -1);
   1458 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_I", "", "", return -1);
   1459 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_C", "", "", return -1);
   1460 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetPortalGroupTag", "1", "1", return -1);
   1461 	/* CHAP Parameters */
   1462 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "HeaderDigest", "None", "None", return -1);
   1463 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "DataDigest", "None", "None", return -1);
   1464 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxConnections", "1", "1", return -1);
   1465 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SendTargets", "", "", return -1);
   1466 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetName", "", "", return -1);
   1467 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorName", "", "", return -1);
   1468 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAlias", "", "", return -1);
   1469 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorAlias", "", "", return -1);
   1470 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAddress", "", "", return -1);
   1471 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "InitialR2T", "Yes", "Yes,No", return -1);
   1472 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "OFMarker", "No", "Yes,No", return -1);
   1473 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "IFMarker", "No", "Yes,No", return -1);
   1474 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "OFMarkInt", "1", "65536", return -1);
   1475 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "IFMarkInt", "1", "65536", return -1);
   1476 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "ImmediateData", "Yes", "Yes,No", return -1);
   1477 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxRecvDataSegmentLength", "8192", "16777215", return -1);
   1478 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxBurstLength", "262144", "16777215", return -1);
   1479 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "FirstBurstLength", "65536", "16777215", return -1);
   1480 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Wait", "2", "2", return -1);
   1481 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Retain", "20", "20", return -1);
   1482 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxOutstandingR2T", "1", "1", return -1);
   1483 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataPDUInOrder", "Yes", "Yes,No", return -1);
   1484 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataSequenceInOrder", "Yes", "Yes,No", return -1);
   1485 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "ErrorRecoveryLevel", "0", "0", return -1);
   1486 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SessionType", "Normal", "Normal,Discovery", return -1);
   1487 	/*
   1488 	 * Auth Result is not in specs, we use this key to pass
   1489 	 * authentication result
   1490 	 */
   1491 	PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthResult", "No", "Yes,No,Fail", return -1);
   1492 
   1493 	/* Set remaining session parameters  */
   1494 
   1495 	sess->UsePhaseCollapsedRead = ISCSI_USE_PHASE_COLLAPSED_READ_DFLT;
   1496 
   1497 	/* Loop for commands */
   1498 
   1499 	while (sess->target->state != TARGET_SHUT_DOWN) {
   1500 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1501 			"session %d: reading header\n", sess->id);
   1502 		if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0, sess->sess_params.header_digest)
   1503 				!= ISCSI_HEADER_LEN) {
   1504 			iscsi_trace(TRACE_ISCSI_DEBUG,
   1505 				"session %d: iscsi_sock_msg() failed\n",
   1506 				sess->id);
   1507 			break;
   1508 		}
   1509 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1510 			"session %d: iscsi op %#x\n", sess->id,
   1511 			ISCSI_OPCODE(header));
   1512 		if (execute_t(sess, header) != 0) {
   1513 			iscsi_err(__FILE__, __LINE__,
   1514 				"execute_t() failed\n");
   1515 			break;
   1516 		}
   1517 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1518 			"session %d: iscsi op %#x complete\n", sess->id,
   1519 			ISCSI_OPCODE(header));
   1520 		if (ISCSI_OPCODE(header) == ISCSI_LOGOUT_CMD) {
   1521 			iscsi_trace(TRACE_ISCSI_DEBUG,
   1522 				"session %d: logout received, ending session\n",
   1523 				sess->id);
   1524 			break;
   1525 		}
   1526 	}
   1527 
   1528 	/* Clean up */
   1529 
   1530 	iscsi_free(sess->buff);
   1531 	if (param_list_destroy(sess->params) != 0) {
   1532 		iscsi_err(__FILE__, __LINE__,
   1533 			"param_list_destroy() failed\n");
   1534 		return -1;
   1535 	}
   1536 	/* Terminate connection */
   1537 
   1538 	if (iscsi_sock_close(sess->sock) != 0) {
   1539 		iscsi_err(__FILE__, __LINE__,
   1540 			"iscsi_sock_close() failed\n");
   1541 	}
   1542 	/* Make session available */
   1543 
   1544 	ISCSI_LOCK(&g_session_q_mutex, return -1);
   1545 	(void) memset(sess, 0x0, sizeof(*sess));
   1546 	sess->d = -1;
   1547 	if (iscsi_queue_insert(&g_session_q, sess) != 0) {
   1548 		iscsi_err(__FILE__, __LINE__,
   1549 				"iscsi_queue_insert() failed\n");
   1550 		return -1;
   1551 	}
   1552 	ISCSI_UNLOCK(&g_session_q_mutex, return -1);
   1553 	iscsi_trace(TRACE_ISCSI_DEBUG, "session %d: ended\n", sess->id);
   1554 
   1555 	return 0;
   1556 }
   1557 
   1558 static int
   1559 read_data_pdu(target_session_t * sess,
   1560 	      iscsi_write_data_t * data,
   1561 	      iscsi_scsi_cmd_args_t * args)
   1562 {
   1563 	uint8_t   header[ISCSI_HEADER_LEN];
   1564 	int             ret_val = -1;
   1565 
   1566 	if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0, sess->sess_params.header_digest) !=
   1567 			ISCSI_HEADER_LEN) {
   1568 		iscsi_err(__FILE__, __LINE__,
   1569 			"iscsi_sock_msg() failed\n");
   1570 		return -1;
   1571 	}
   1572 	if ((ret_val = iscsi_write_data_decap(header, data)) != 0) {
   1573 		iscsi_err(__FILE__, __LINE__,
   1574 			"iscsi_write_data_decap() failed\n");
   1575 		return ret_val;
   1576 	}
   1577 	/* Check args */
   1578 	if (sess->sess_params.max_dataseg_len) {
   1579 		if (data->length > sess->sess_params.max_dataseg_len) {
   1580 			args->status = 0x02;
   1581 			return -1;
   1582 		}
   1583 	}
   1584 	if ((args->bytes_recv + data->length) > args->trans_len) {
   1585 		args->status = 0x02;
   1586 		return -1;
   1587 	}
   1588 	if (data->tag != args->tag) {
   1589 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1590 			"Data ITT (%d) does not match with command ITT (%d)\n",
   1591 			data->tag, args->tag);
   1592 		if (data->final) {
   1593 			args->status = 0x02;
   1594 			return -1;
   1595 		} else {
   1596 			/* Send a reject PDU */
   1597 			iscsi_trace(TRACE_ISCSI_DEBUG, "Sending Reject PDU\n");
   1598 			if (reject_t(sess, header, 0x09) != 0) {
   1599 				/* Invalid PDU Field */
   1600 				iscsi_trace(TRACE_ISCSI_DEBUG,
   1601 					"Sending Reject PDU failed\n");
   1602 				return 1;
   1603 			}
   1604 		}
   1605 	}
   1606 	return 0;
   1607 }
   1608 
   1609 int
   1610 target_transfer_data(target_session_t * sess, iscsi_scsi_cmd_args_t * args,
   1611 		struct iovec * sg, int sg_len)
   1612 {
   1613 	iscsi_write_data_t data;
   1614 	struct iovec   *iov, *iov_ptr = NULL;
   1615 	int             iov_len;
   1616 
   1617 #define TTD_CLEANUP do {						\
   1618 	if (iov_ptr != NULL) {						\
   1619 		iscsi_free_atomic(iov_ptr);				\
   1620 	}								\
   1621 } while (/* CONSTCOND */ 0)
   1622 
   1623 	args->bytes_recv = 0;
   1624 	if ((!sess->sess_params.immediate_data) && args->length) {
   1625 		iscsi_trace(TRACE_ISCSI_DEBUG,
   1626 			"Cannot accept any Immediate data\n");
   1627 		args->status = 0x02;
   1628 		return -1;
   1629 	}
   1630 
   1631 	/* Make a copy of the iovec */
   1632 	iov_ptr = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len);
   1633 	if (iov_ptr == NULL) {
   1634 		iscsi_err(__FILE__, __LINE__,
   1635 				"iscsi_malloc_atomic() failed\n");
   1636 		return -1;
   1637 	}
   1638 	iov = iov_ptr;
   1639 	(void) memcpy(iov, sg, sizeof(struct iovec) * sg_len);
   1640 	iov_len = sg_len;
   1641 
   1642 	/*
   1643          * Read any immediate data.
   1644          */
   1645 
   1646 	if (sess->sess_params.immediate_data && args->length) {
   1647 		if (sess->sess_params.max_dataseg_len &&
   1648 		    args->length > sess->sess_params.max_dataseg_len) {
   1649 			iscsi_err(__FILE__, __LINE__,
   1650 				"args->length (%u) too long\n",
   1651 				args->length);
   1652 				TTD_CLEANUP;
   1653 				return -1;
   1654 		}
   1655 
   1656 		/* Modify iov to include just immediate data */
   1657 		if (modify_iov(&iov, &iov_len, 0, args->length) != 0) {
   1658 			iscsi_err(__FILE__, __LINE__,
   1659 				"modify_iov() failed\n");
   1660 			TTD_CLEANUP;
   1661 			return -1;
   1662 		}
   1663 		iscsi_trace(TRACE_SCSI_DATA,
   1664 			"reading %u bytes immediate write data\n",
   1665 			args->length);
   1666 		if ((uint32_t)iscsi_sock_msg(sess->sock, 0, args->length, iov,
   1667 				iov_len, sess->sess_params.header_digest) != args->length) {
   1668 			iscsi_err(__FILE__, __LINE__,
   1669 				"iscsi_sock_msg() failed\n");
   1670 			TTD_CLEANUP;
   1671 			return -1;
   1672 		}
   1673 		iscsi_trace(TRACE_SCSI_DATA,
   1674 			"successfully read %u bytes immediate write data\n",
   1675 			args->length);
   1676 		args->bytes_recv += args->length;
   1677 	}
   1678 
   1679 	/*
   1680          * Read iSCSI data PDUs
   1681          */
   1682 	if (args->bytes_recv < args->trans_len) {
   1683 		int             r2t_flag = 0;
   1684 		int             read_status = 0;
   1685 		iscsi_r2t_t     r2t;
   1686 		int             desired_xfer_len;
   1687 
   1688 		desired_xfer_len = MIN(sess->sess_params.first_burst_length,
   1689 				      args->trans_len) - args->bytes_recv;
   1690 		(void) memset(&r2t, 0x0, sizeof(r2t));
   1691 		do {
   1692 
   1693 			/*
   1694 			 * Send R2T if we're either operating in solicted
   1695 			 * mode or we're operating in unsolicted
   1696 			 */
   1697 			/* mode and have reached the first burst */
   1698 			if (!r2t_flag &&
   1699 			     (sess->sess_params.initial_r2t ||
   1700 			        (sess->sess_params.first_burst_length &&
   1701 				(args->bytes_recv >=
   1702 				sess->sess_params.first_burst_length)))) {
   1703 				uint8_t   header[ISCSI_HEADER_LEN];
   1704 
   1705 				desired_xfer_len = MIN(args->trans_len -
   1706 							args->bytes_recv,
   1707 					sess->sess_params.max_burst_length);
   1708 				iscsi_trace(TRACE_ISCSI_DEBUG,
   1709 					"sending R2T for %u bytes data\n",
   1710 					desired_xfer_len);
   1711 				r2t.tag = args->tag;
   1712 
   1713 				r2t.transfer_tag = 0x1234;
   1714 
   1715 				r2t.ExpCmdSN = sess->ExpCmdSN;
   1716 				r2t.MaxCmdSN = sess->MaxCmdSN;
   1717 				r2t.StatSN = ++(sess->StatSN);
   1718 				r2t.length = desired_xfer_len;
   1719 				r2t.offset = args->bytes_recv;
   1720 				if (iscsi_r2t_encap(header, &r2t) != 0) {
   1721 					iscsi_err(__FILE__, __LINE__,
   1722 						"r2t_encap() failed\n");
   1723 					TTD_CLEANUP;
   1724 					return -1;
   1725 				}
   1726 				iscsi_trace(TRACE_ISCSI_DEBUG,
   1727 					"sending R2T tag %u transfer tag "
   1728 					"%u len %u offset %u\n",
   1729 					r2t.tag, r2t.transfer_tag, r2t.length,
   1730 					r2t.offset);
   1731 				if (iscsi_sock_msg(sess->sock, 1,
   1732 					ISCSI_HEADER_LEN, header, 0, sess->sess_params.header_digest) !=
   1733 					ISCSI_HEADER_LEN) {
   1734 					iscsi_err(__FILE__, __LINE__,
   1735 						"iscsi_sock_msg() failed\n");
   1736 					TTD_CLEANUP;
   1737 					return -1;
   1738 				}
   1739 				r2t_flag = 1;
   1740 				r2t.R2TSN += 1;
   1741 			}
   1742 
   1743 			/* Read iSCSI data PDU */
   1744 			iscsi_trace(TRACE_ISCSI_DEBUG, "reading data pdu\n");
   1745 			read_status = read_data_pdu(sess, &data, args);
   1746 			if (read_status != 0) {
   1747 				if (read_status == 1) {
   1748 					iscsi_trace(TRACE_ISCSI_DEBUG,
   1749 						"Unknown PDU received and "
   1750 						"ignored. Expecting "
   1751 						"Data PDU\n");
   1752 					continue;
   1753 				} else {
   1754 					iscsi_err(__FILE__, __LINE__,
   1755 						"read_data_pdu() failed\n");
   1756 					args->status = 0x02;
   1757 					TTD_CLEANUP;
   1758 					return -1;
   1759 				}
   1760 			}
   1761 			if (data.ExpStatSN != sess->StatSN) {
   1762 				iscsi_warn(__FILE__, __LINE__,
   1763 					"Bad \"ExpStatSN\": Got %u "
   1764 					"expected %u.\n",
   1765 					data.ExpStatSN, sess->StatSN);
   1766 			}
   1767 			iscsi_trace(TRACE_ISCSI_DEBUG,
   1768 				"read data pdu OK (offset %u, length %u)\n",
   1769 				data.offset, data.length);
   1770 
   1771 			/* Modify iov with offset and length. */
   1772 			iov = iov_ptr;
   1773 			(void) memcpy(iov, sg, sizeof(struct iovec) * sg_len);
   1774 			iov_len = sg_len;
   1775 			if (modify_iov(&iov, &iov_len, data.offset,
   1776 					data.length) != 0) {
   1777 				iscsi_err(__FILE__, __LINE__,
   1778 					"modify_iov() failed\n");
   1779 				TTD_CLEANUP;
   1780 				return -1;
   1781 			}
   1782 
   1783 			/* Scatter into destination buffers */
   1784 			if ((uint32_t)iscsi_sock_msg(sess->sock, 0,
   1785 				data.length, iov, iov_len, sess->sess_params.header_digest) != data.length) {
   1786 				iscsi_err(__FILE__, __LINE__,
   1787 					"iscsi_sock_msg() failed\n");
   1788 				TTD_CLEANUP;
   1789 				return -1;
   1790 			}
   1791 			iscsi_trace(TRACE_ISCSI_DEBUG,
   1792 				"successfully scattered %u bytes\n",
   1793 				data.length);
   1794 			args->bytes_recv += data.length;
   1795 			desired_xfer_len -= data.length;
   1796 			if ((!r2t_flag) &&
   1797 			    (args->bytes_recv >
   1798 			    	sess->sess_params.first_burst_length)) {
   1799 				iscsi_err(__FILE__, __LINE__,
   1800 					"Received unsolicited data (%u) "
   1801 					"more than first_burst_length (%u)\n",
   1802 					args->bytes_recv,
   1803 					sess->sess_params.first_burst_length);
   1804 				args->status = 0x02;
   1805 				TTD_CLEANUP;
   1806 				return -1;
   1807 			}
   1808 			if ((desired_xfer_len != 0) && data.final) {
   1809 				iscsi_err(__FILE__, __LINE__,
   1810 					"Expecting more data (%d) "
   1811 					"from initiator for this sequence\n",
   1812 					desired_xfer_len);
   1813 				args->status = 0x02;
   1814 				TTD_CLEANUP;
   1815 				return -1;
   1816 			}
   1817 			if ((desired_xfer_len == 0) && !data.final) {
   1818 				iscsi_err(__FILE__, __LINE__,
   1819 					"Final bit not set on the last "
   1820 					"data PDU of this sequence\n");
   1821 				args->status = 0x02;
   1822 				TTD_CLEANUP;
   1823 				return -1;
   1824 			}
   1825 			if ((desired_xfer_len == 0) &&
   1826 			    (args->bytes_recv < args->trans_len)) {
   1827 				r2t_flag = 0;
   1828 			}
   1829 		} while (args->bytes_recv < args->trans_len);
   1830 #if 0
   1831 		RETURN_NOT_EQUAL("Final bit", data.final, 1, TTD_CLEANUP, -1);
   1832 #else
   1833 		if (data.final != 1) {
   1834 			iscsi_err(__FILE__, __LINE__, "Final bit\n");
   1835 			TTD_CLEANUP;
   1836 			return -1;
   1837 		}
   1838 #endif
   1839 	} else {
   1840 #if 0
   1841 		RETURN_NOT_EQUAL("Final bit", args->final, 1, TTD_CLEANUP, -1);
   1842 #else
   1843 		if (args->final != 1) {
   1844 			iscsi_err(__FILE__, __LINE__, "Final bit\n");
   1845 			TTD_CLEANUP;
   1846 			return -1;
   1847 		}
   1848 #endif
   1849 	}
   1850 	iscsi_trace(TRACE_ISCSI_DEBUG,
   1851 		"successfully transferred %u bytes write data\n",
   1852 		args->trans_len);
   1853 	TTD_CLEANUP;
   1854 	return 0;
   1855 }
   1856 
   1857 /* check there's enough space in the arrays */
   1858 static void
   1859 size_arrays(iscsi_target_t *tgt, unsigned needed)
   1860 {
   1861 	if (tgt->size == 0) {
   1862 		/* only get here first time around */
   1863 		tgt->size = needed;
   1864 		tgt->name = calloc(sizeof(char *), needed);
   1865 		tgt->value = calloc(sizeof(char *), needed);
   1866 	} else if (tgt->c == tgt->size) {
   1867 		/* only uses 'needed' when filled array */
   1868 		tgt->size += needed;
   1869 		tgt->name = realloc(tgt->name, sizeof(char *) * needed);
   1870 		tgt->value = realloc(tgt->value, sizeof(char *) * needed);
   1871 	}
   1872 }
   1873 
   1874 /* find the name in the array */
   1875 static int
   1876 findvar(iscsi_target_t *tgt, const char *name)
   1877 {
   1878 	unsigned	i;
   1879 
   1880 	for (i = 0 ; i < tgt->c && strcmp(tgt->name[i], name) != 0; i++) {
   1881 	}
   1882 	return (i == tgt->c) ? -1 : (int)i;
   1883 }
   1884 
   1885 /********************
   1886  * Public Functions *
   1887  ********************/
   1888 
   1889 int
   1890 iscsi_target_set_defaults(iscsi_target_t *tgt)
   1891 {
   1892 	char	buf[32];
   1893 
   1894 	/* set defaults */
   1895 	(void) memset(tgt, 0x0, sizeof(*tgt));
   1896 	iscsi_target_setvar(tgt, "iqn", DEFAULT_TARGET_NAME);
   1897 	(void) snprintf(buf, sizeof(buf), "%d", ISCSI_PORT);
   1898 	iscsi_target_setvar(tgt, "target port", buf);
   1899 	iscsi_target_setvar(tgt, "address family", "unspec");
   1900 	(void) snprintf(buf, sizeof(buf), "%d", DEFAULT_TARGET_MAX_SESSIONS);
   1901 	iscsi_target_setvar(tgt, "max sessions", buf);
   1902 	iscsi_target_setvar(tgt, "configfile", _PATH_ISCSI_TARGETS);
   1903 	iscsi_target_setvar(tgt, "blocklen", "512");
   1904 	return 1;
   1905 }
   1906 
   1907 /* re-read the configuration file */
   1908 int
   1909 iscsi_target_reconfigure(iscsi_target_t *tgt)
   1910 {
   1911 	targv_t	*oldluns;
   1912 	devv_t	*olddevices;
   1913 	extv_t	*oldextents;
   1914 	targv_t	*luns;
   1915 	devv_t	*devices;
   1916 	extv_t	*extents;
   1917 	char	*config;
   1918 
   1919 	NEW(targv_t, luns, "iscsi_target_reconf 1", return -1);
   1920 	NEW(devv_t, devices, "iscsi_target_reconf 2", return -1);
   1921 	NEW(extv_t, extents, "iscsi_target_reconf 3", return -1);
   1922 	config = iscsi_target_getvar(tgt, "configfile");
   1923 	if (!read_conf_file(config, tgt->lunv, tgt->devv, tgt->extentv)) {
   1924 		(void) fprintf(stderr, "Error: can't open `%s'\n", config);
   1925 		return 0;
   1926 	}
   1927 	/* it worked - let's reassign things */
   1928 	/* XXX - agc - lock */
   1929 	oldluns = tgt->lunv;
   1930 	olddevices = tgt->devv;
   1931 	oldextents = tgt->extentv;
   1932 	tgt->lunv = luns;
   1933 	tgt->devv = devices;
   1934 	tgt->extentv = extents;
   1935 	/* XXX - agc - unlock */
   1936 	/* free up storage */
   1937 	(void) free(oldluns);
   1938 	(void) free(olddevices);
   1939 	(void) free(oldextents);
   1940 	return 1;
   1941 }
   1942 
   1943 int
   1944 iscsi_target_start(iscsi_target_t *tgt)
   1945 {
   1946 	uint32_t	 j;
   1947 	targv_t		*lunv;
   1948 	char		*config;
   1949 	char		*dbg;
   1950 	int		 maxsessions;
   1951 	int              i;
   1952 
   1953 	if ((dbg = iscsi_target_getvar(tgt, "debug")) != NULL) {
   1954 		set_debug(dbg);
   1955 	}
   1956 	/* allocate space for disks, extents and targets */
   1957 	NEW(targv_t, tgt->lunv, "iscsi_target_start 1", return -1);
   1958 	NEW(devv_t, tgt->devv, "iscsi_target_start 2", return -1);
   1959 	NEW(extv_t, tgt->extentv, "iscsi_target_start 3", return -1);
   1960 	/* read the configuration file */
   1961 	config = iscsi_target_getvar(tgt, "configfile");
   1962 	if (!read_conf_file(config, tgt->lunv, tgt->devv, tgt->extentv)) {
   1963 		(void) fprintf(stderr, "Error: can't open `%s'\n", config);
   1964 		return 0;
   1965 	}
   1966 	lunv = tgt->lunv;
   1967 	if (lunv->c == 0) {
   1968 		(void) fprintf(stderr, "No targets to initialise\n");
   1969 		return -1;
   1970 	}
   1971 	maxsessions = atoi(iscsi_target_getvar(tgt, "max sessions"));
   1972 	NEWARRAY(target_session_t, g_session, maxsessions, "iscsi_target_start",
   1973 			return -1);
   1974 	device_set_var("blocklen", iscsi_target_getvar(tgt, "blocklen"));
   1975 	if (tgt->state == TARGET_INITIALIZING ||
   1976 	    tgt->state == TARGET_INITIALIZED) {
   1977 		iscsi_err(__FILE__, __LINE__,
   1978 			"duplicate target initialization attempted\n");
   1979 		return -1;
   1980 	}
   1981 	tgt->state = TARGET_INITIALIZING;
   1982 	if (iscsi_queue_init(&g_session_q, maxsessions) != 0) {
   1983 		iscsi_err(__FILE__, __LINE__,
   1984 			"iscsi_queue_init() failed\n");
   1985 		return -1;
   1986 	}
   1987 	tgt->main_pid = getpid();
   1988 	for (i = 0; i < maxsessions; i++) {
   1989 		g_session[i].id = i;
   1990 		g_session[i].d = -1;
   1991 		if (iscsi_queue_insert(&g_session_q, &g_session[i]) != 0) {
   1992 			iscsi_err(__FILE__, __LINE__,
   1993 				"iscsi_queue_insert() failed\n");
   1994 			return -1;
   1995 		}
   1996 	}
   1997 	for (j = 0 ; j < lunv->c ; j++) {
   1998 		int d = device_init(tgt, lunv, &lunv->v[j]);
   1999 
   2000 		if (d < 0) {
   2001 			iscsi_err(__FILE__, __LINE__,
   2002 				"device_init() failed\n");
   2003 			return -1;
   2004 		}
   2005 	}
   2006 	ISCSI_MUTEX_INIT(&g_session_q_mutex, return -1);
   2007 	tgt->listener_listening = 0;
   2008 	tgt->listener_pid = -1;
   2009 	tgt->state = TARGET_INITIALIZED;
   2010 	printf("TARGET: iSCSI Qualified Name (IQN) is %s\n",
   2011 			iscsi_target_getvar(tgt, "iqn"));
   2012 	for (i = 0 ; i < tgt->sockc ; i++) {
   2013 		printf("\tsocket %d listening on port %s\n", tgt->sockv[i],
   2014 			iscsi_target_getvar(tgt, "target port"));
   2015 	}
   2016 	return 0;
   2017 }
   2018 
   2019 int
   2020 iscsi_target_shutdown(iscsi_target_t *tgt)
   2021 {
   2022 	target_session_t	*sess;
   2023 	int			 maxsessions;
   2024 	int			 i;
   2025 
   2026 	if ((tgt->state == TARGET_SHUTTING_DOWN) ||
   2027 	    (tgt->state == TARGET_SHUT_DOWN)) {
   2028 		iscsi_err(__FILE__, __LINE__,
   2029 			"duplicate target shutdown attempted\n");
   2030 		return -1;
   2031 	}
   2032 	tgt->state = TARGET_SHUTTING_DOWN;
   2033 	iscsi_trace(TRACE_ISCSI_DEBUG, "shutting down target\n");
   2034 	maxsessions = atoi(iscsi_target_getvar(tgt, "max sessions"));
   2035 	for (i = 0; i < maxsessions; i++) {
   2036 		sess = &g_session[i];
   2037 
   2038 		/* Need to replace with a call to session_destroy() */
   2039 
   2040 		if (sess->IsLoggedIn) {
   2041 			printf("shutting down socket on sess %d\n", i);
   2042 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2043 				"shutting down socket on sess %d\n", i);
   2044 			if (iscsi_sock_shutdown(sess->sock, 2) != 0) {
   2045 				iscsi_err(__FILE__, __LINE__,
   2046 					"iscsi_sock_shutdown() failed\n");
   2047 				return -1;
   2048 			}
   2049 			printf("waiting for worker %d (pid %d, state %d)\n",
   2050 				i, sess->worker.pid, sess->worker.state);
   2051 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2052 				"waiting for worker %d (pid %d, state %d)\n",
   2053 				i, sess->worker.pid, sess->worker.state);
   2054 			while (sess->worker.state &
   2055 					ISCSI_WORKER_STATE_STARTED) {
   2056 				ISCSI_SPIN;
   2057 			}
   2058 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2059 					"worker %d has exited\n", i);
   2060 		}
   2061 		if (device_shutdown(sess) != 0) {
   2062 			iscsi_err(__FILE__, __LINE__,
   2063 					"device_shutdown() failed\n");
   2064 			return -1;
   2065 		}
   2066 	}
   2067 	iscsi_trace(TRACE_ISCSI_DEBUG, "shutting down accept socket\n");
   2068 	if (iscsi_sock_shutdown(tgt->sockv[0], 2) != 0) {
   2069 		iscsi_err(__FILE__, __LINE__,
   2070 			"iscsi_sock_shutdown() failed\n");
   2071 		return -1;
   2072 	}
   2073 	if (tgt->listener_pid != getpid()) {
   2074 		iscsi_trace(TRACE_ISCSI_DEBUG, "waiting for listener thread\n");
   2075 		while (tgt->listener_listening) {
   2076 			ISCSI_SPIN;
   2077 		}
   2078 		iscsi_trace(TRACE_ISCSI_DEBUG, "listener thread has exited\n");
   2079 	}
   2080 	iscsi_trace(TRACE_ISCSI_DEBUG, "closing accept socket\n");
   2081 	if (iscsi_sock_close(tgt->sockv[0]) != 0) {
   2082 		iscsi_err(__FILE__, __LINE__,
   2083 			"iscsi_sock_close() failed\n");
   2084 		return -1;
   2085 	}
   2086 	ISCSI_MUTEX_DESTROY(&g_session_q_mutex, return -1);
   2087 	iscsi_trace(TRACE_ISCSI_DEBUG, "target shutdown complete\n");
   2088 	tgt->state = TARGET_SHUT_DOWN;
   2089 
   2090 	return 0;
   2091 }
   2092 
   2093 int
   2094 iscsi_target_listen(iscsi_target_t *tgt)
   2095 {
   2096 	struct sockaddr_in6	remoteAddrStorage6;
   2097 	struct sockaddr_in6	localAddrStorage6;
   2098 	struct sockaddr_in	remoteAddrStorage;
   2099 	struct sockaddr_in	localAddrStorage;
   2100 	target_session_t	*sess;
   2101 	socklen_t		remoteAddrLen;
   2102 	socklen_t		localAddrLen;
   2103 	char			targetaddress[2 * 1024];
   2104 	char			remote[1024];
   2105 	char			local[1024];
   2106 	char			*config;
   2107 	int			newconn;
   2108 	int			i;
   2109 
   2110 	ISCSI_THREAD_START("listen_thread");
   2111 	tgt->listener_pid = getpid();
   2112 	tgt->listener_listening++;
   2113 	iscsi_trace(TRACE_ISCSI_DEBUG, "listener thread started\n");
   2114 
   2115 	if (!iscsi_socks_establish(tgt->sockv, tgt->famv, &tgt->sockc,
   2116 			iscsi_target_getvar(tgt, "address family"),
   2117 			atoi(iscsi_target_getvar(tgt, "target port")))) {
   2118 		iscsi_err(__FILE__, __LINE__,
   2119 				"iscsi_sock_establish() failed\n");
   2120 		goto done;
   2121 	}
   2122 
   2123 	iscsi_trace(TRACE_NET_DEBUG, "create, bind, listen OK\n");
   2124 
   2125 	/* Loop for connections: FIX ME with queue */
   2126 
   2127 	while (tgt->state != TARGET_SHUT_DOWN) {
   2128 		ISCSI_LOCK(&g_session_q_mutex, return -1);
   2129 		if ((sess = iscsi_queue_remove(&g_session_q)) == NULL) {
   2130 			iscsi_err(__FILE__, __LINE__,
   2131 			"no free sessions: iscsi_queue_remove() failed\n");
   2132 			goto done;
   2133 		}
   2134 		ISCSI_UNLOCK(&g_session_q_mutex, return -1);
   2135 		assert(sess->d == -1);
   2136 #if 0
   2137 		(void) memset(sess, 0x0, sizeof(*sess));
   2138 #endif
   2139 
   2140 		sess->target = tgt;
   2141 
   2142 		/* Accept connection, spawn session thread, and */
   2143 		/* clean up old threads */
   2144 
   2145 		config = iscsi_target_getvar(tgt, "configfile");
   2146 		i = iscsi_waitfor_connection(tgt->sockv, tgt->sockc, config,
   2147 				&newconn);
   2148 
   2149 		iscsi_trace(TRACE_NET_DEBUG,
   2150 				"waiting for %s connection on port %s\n",
   2151 				iscsi_address_family(tgt->famv[i]),
   2152 				iscsi_target_getvar(tgt, "target port"));
   2153 
   2154 		if (!iscsi_sock_accept(newconn, &sess->sock)) {
   2155 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2156 					"iscsi_sock_accept() failed\n");
   2157 			goto done;
   2158 		}
   2159 
   2160 		switch (tgt->famv[i]) {
   2161 		case AF_INET:
   2162 			sess->address_family = 4;
   2163 			(void) memset(&localAddrStorage, 0x0,
   2164 				localAddrLen = sizeof(localAddrStorage));
   2165 			if (getsockname(sess->sock,
   2166 				(struct sockaddr *)(void *)&localAddrStorage,
   2167 				&localAddrLen) < 0) {
   2168 				iscsi_err(__FILE__, __LINE__,
   2169 					"iscsi_sock_getsockname() failed\n");
   2170 				goto done;
   2171 			}
   2172 			(void) memset(&remoteAddrStorage, 0x0,
   2173 				remoteAddrLen = sizeof(remoteAddrStorage));
   2174 			if (getpeername(sess->sock,
   2175 				(struct sockaddr *)(void *) &remoteAddrStorage,
   2176 				&remoteAddrLen) < 0) {
   2177 				iscsi_err(__FILE__, __LINE__,
   2178 					"iscsi_sock_getpeername() failed\n");
   2179 				goto done;
   2180 			}
   2181 
   2182 #ifdef HAVE_GETNAMEINFO
   2183 			if (getnameinfo((struct sockaddr *)(void *)
   2184 				&localAddrStorage,
   2185 				sizeof(localAddrStorage), local,
   2186 				sizeof(local), NULL, 0, NI_NUMERICHOST) < 0) {
   2187 				iscsi_err(__FILE__, __LINE__,
   2188 					"getnameinfo local failed\n");
   2189 			}
   2190 			if (getnameinfo((struct sockaddr *)(void *)
   2191 				&remoteAddrStorage,
   2192 				sizeof(remoteAddrStorage), remote,
   2193 				sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) {
   2194 				iscsi_err(__FILE__, __LINE__,
   2195 					"getnameinfo remote failed\n");
   2196 			}
   2197 			(void) strlcpy(sess->initiator, remote,
   2198 					sizeof(sess->initiator));
   2199 #else
   2200 			(void) strlcpy(local,
   2201 				inet_ntoa(localAddrStorage.sin_addr),
   2202 				sizeof(local));
   2203 			(void) strlcpy(sess->initiator,
   2204 				inet_ntoa(remoteAddrStorage.sin_addr),
   2205 				sizeof(sess->initiator));
   2206 #endif
   2207 
   2208 			(void) snprintf(targetaddress, sizeof(targetaddress),
   2209 				"%s:%s,1", local,
   2210 				iscsi_target_getvar(tgt, "target port"));
   2211 			iscsi_target_setvar(tgt, "target address",
   2212 				targetaddress);
   2213 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2214 				"IPv4 connection accepted on port %s "
   2215 				"(local IP %s, remote IP %s)\n",
   2216 				iscsi_target_getvar(tgt, "target port"),
   2217 				local, sess->initiator);
   2218 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2219 				"TargetAddress = \"%s\"\n", targetaddress);
   2220 			break;
   2221 
   2222 		case AF_INET6:
   2223 			sess->address_family = 6;
   2224 			(void) memset(&localAddrStorage6, 0x0,
   2225 				localAddrLen = sizeof(localAddrStorage6));
   2226 			if (getsockname(sess->sock, (struct sockaddr *)(void *)
   2227 				&localAddrStorage6, &localAddrLen) < 0) {
   2228 				iscsi_err(__FILE__, __LINE__,
   2229 					"getsockname() failed\n");
   2230 				goto done;
   2231 			}
   2232 
   2233 			(void) memset(&remoteAddrStorage6, 0x0,
   2234 				remoteAddrLen = sizeof(remoteAddrStorage6));
   2235 			if (getpeername(sess->sock, (struct sockaddr *)(void *)
   2236 				&remoteAddrStorage6, &remoteAddrLen) < 0) {
   2237 				iscsi_err(__FILE__, __LINE__,
   2238 					"iscsi_sock_getpeername() failed\n");
   2239 				goto done;
   2240 			}
   2241 
   2242 			if (getnameinfo((struct sockaddr *)(void *)
   2243 				&localAddrStorage6, sizeof(localAddrStorage6),
   2244 				local, sizeof(local), NULL, 0,
   2245 				NI_NUMERICHOST) < 0) {
   2246 				iscsi_err(__FILE__, __LINE__,
   2247 					"getnameinfo local failed\n");
   2248 			}
   2249 			if (getnameinfo((struct sockaddr *)(void *)
   2250 				&remoteAddrStorage6,
   2251 				sizeof(remoteAddrStorage6), remote,
   2252 				sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) {
   2253 				iscsi_err(__FILE__, __LINE__,
   2254 					"getnameinfo remote failed\n");
   2255 			}
   2256 			(void) strlcpy(sess->initiator, remote,
   2257 				sizeof(sess->initiator));
   2258 			(void) snprintf(targetaddress, sizeof(targetaddress),
   2259 				"%s:%s,1", local,
   2260 				iscsi_target_getvar(tgt, "target port"));
   2261 			iscsi_target_setvar(tgt, "target address",
   2262 				targetaddress);
   2263 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2264 				"IPv6 connection accepted on port %s "
   2265 				"(local IP %s, remote IP %s)\n",
   2266 				iscsi_target_getvar(tgt, "target port"),
   2267 				local, sess->initiator);
   2268 			iscsi_trace(TRACE_ISCSI_DEBUG,
   2269 				"TargetAddress = \"%s\"\n", targetaddress);
   2270 			break;
   2271 		}
   2272 		if (iscsi_thread_create(&sess->worker.thread,
   2273 			(void *) worker_proc_t, sess) != 0) {
   2274 			iscsi_err(__FILE__, __LINE__,
   2275 				"iscsi_thread_create() failed\n");
   2276 			goto done;
   2277 		}
   2278 	}
   2279 done:
   2280 	tgt->listener_listening--;
   2281 	return 0;
   2282 }
   2283 
   2284 /* write the pid to the pid file */
   2285 void
   2286 iscsi_target_write_pidfile(const char *f)
   2287 {
   2288 	FILE	*fp;
   2289 
   2290 	if (f == NULL) {
   2291 		f = _PATH_ISCSI_PID_FILE;
   2292 	}
   2293 	if ((fp = fopen(f, "w")) == NULL) {
   2294 		(void) fprintf(stderr, "Couldn't create pid file \"%s\": %s",
   2295 				f, strerror(errno));
   2296 	} else {
   2297 		(void) fprintf(fp, "%ld\n", (long) getpid());
   2298 		(void) fclose(fp);
   2299 	}
   2300 }
   2301 
   2302 /* set a variable */
   2303 int
   2304 iscsi_target_setvar(iscsi_target_t *tgt, const char *name, const char *value)
   2305 {
   2306 	int	i;
   2307 
   2308 	if ((i = findvar(tgt, name)) < 0) {
   2309 		/* add the element to the array */
   2310 		size_arrays(tgt, tgt->size + 15);
   2311 		tgt->name[i = tgt->c++] = strdup(name);
   2312 	} else {
   2313 		/* replace the element in the array */
   2314 		if (tgt->value[i]) {
   2315 			(void) free(tgt->value[i]);
   2316 			tgt->value[i] = NULL;
   2317 		}
   2318 	}
   2319 	/* sanity checks for range of values would go here */
   2320 	tgt->value[i] = strdup(value);
   2321 	return 1;
   2322 }
   2323 
   2324 /* get a variable's value (NULL if not set) */
   2325 char *
   2326 iscsi_target_getvar(iscsi_target_t *tgt, const char *name)
   2327 {
   2328 	int	i;
   2329 
   2330 	return ((i = findvar(tgt, name)) < 0) ? NULL : tgt->value[i];
   2331 }
   2332