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