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