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