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