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