1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2017 Nexenta Systems, Inc. 25 */ 26 27 #include <sys/cpuvar.h> 28 #include <sys/types.h> 29 #include <sys/conf.h> 30 #include <sys/file.h> 31 #include <sys/ddi.h> 32 #include <sys/sunddi.h> 33 #include <sys/modctl.h> 34 #include <sys/sysmacros.h> 35 #include <sys/socket.h> 36 #include <sys/strsubr.h> 37 #include <inet/tcp.h> 38 #include <sys/nvpair.h> 39 40 #include <sys/stmf.h> 41 #include <sys/stmf_ioctl.h> 42 #include <sys/portif.h> 43 #include <sys/idm/idm.h> 44 #include <sys/idm/idm_conn_sm.h> 45 #include <sys/idm/idm_text.h> 46 #include <sys/idm/idm_so.h> 47 48 #include "iscsit_isns.h" 49 #include "iscsit.h" 50 51 #define IPADDRSTRLEN INET6_ADDRSTRLEN /* space for ipaddr string */ 52 #define PORTALSTRLEN (IPADDRSTRLEN+16) /* add space for :port,tag */ 53 54 void 55 iscsit_text_cmd_fini(iscsit_conn_t *ict); 56 57 static void 58 iscsit_bump_ttt(iscsit_conn_t *ict) 59 { 60 /* 61 * Set the target task tag. The value will be zero when 62 * the connection is created. Increment it and wrap it 63 * back to one if we hit the reserved value. 64 * 65 * The TTT is fabricated since there is no real task associated 66 * with a text request. The idm task range is reused here since 67 * no real tasks can be started from a discovery session and 68 * thus no conflicts are possible. 69 */ 70 if (++ict->ict_text_rsp_ttt == IDM_TASKIDS_MAX) 71 ict->ict_text_rsp_ttt = 1; 72 } 73 74 static void 75 iscsit_text_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status) 76 { 77 iscsit_conn_t *ict = pdu->isp_private; 78 79 idm_pdu_free(pdu); 80 if (status != IDM_STATUS_SUCCESS) { 81 /* 82 * Could not send the last text response. 83 * Clear any state and bump the TTT so subsequent 84 * requests will not match. 85 */ 86 iscsit_text_cmd_fini(ict); 87 iscsit_bump_ttt(ict); 88 } 89 iscsit_conn_rele(ict); 90 } 91 92 static void 93 iscsit_text_reject(idm_pdu_t *req_pdu, uint8_t reason_code) 94 { 95 iscsit_conn_t *ict = req_pdu->isp_ic->ic_handle; 96 97 /* 98 * A reject means abandoning this text request. 99 * Cleanup any state from the request and increment the TTT 100 * in case the initiator does not get the reject response 101 * and attempts to resume this request. 102 */ 103 iscsit_text_cmd_fini(ict); 104 iscsit_bump_ttt(ict); 105 iscsit_send_reject(ict, req_pdu, reason_code); 106 idm_pdu_complete(req_pdu, IDM_STATUS_SUCCESS); 107 108 } 109 110 111 /* 112 * Add individual <TargetAddress=ipaddr> tuple to the nvlist 113 */ 114 static void 115 iscsit_add_portal(struct sockaddr_storage *ss, int tag, nvlist_t *nv_resp) 116 { 117 char ipaddr[IPADDRSTRLEN]; /* ip address string */ 118 char ta_value[PORTALSTRLEN]; /* target address value */ 119 struct sockaddr_in *sin; 120 struct sockaddr_in6 *sin6; 121 122 switch (ss->ss_family) { 123 case AF_INET: 124 sin = (struct sockaddr_in *)ss; 125 (void) inet_ntop(AF_INET, &sin->sin_addr, ipaddr, 126 sizeof (ipaddr)); 127 (void) snprintf(ta_value, sizeof (ta_value), "%s:%d,%d", 128 ipaddr, ntohs(sin->sin_port), tag); 129 break; 130 case AF_INET6: 131 sin6 = (struct sockaddr_in6 *)ss; 132 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, ipaddr, 133 sizeof (ipaddr)); 134 (void) snprintf(ta_value, sizeof (ta_value), "[%s]:%d,%d", 135 ipaddr, ntohs(sin6->sin6_port), tag); 136 break; 137 default: 138 ASSERT(0); 139 return; 140 } 141 (void) nvlist_add_string(nv_resp, "TargetAddress", ta_value); 142 } 143 144 /* 145 * Process the special case of the default portal group. 146 * Network addresses are obtained from the network stack and 147 * require some reformatting. 148 */ 149 static void 150 iscsit_add_default_portals(iscsit_conn_t *ict, idm_addr_list_t *ipaddr_p, 151 nvlist_t *nv_resp) 152 { 153 int pass, i; 154 idm_addr_t *tip; 155 struct sockaddr_storage ss; 156 struct sockaddr_in *sin; 157 struct sockaddr_in6 *sin6; 158 159 /* 160 * If this request was received on one of the portals, 161 * output that portal first. Most initiators will try to 162 * connect on the first portal in the SendTargets response. 163 * For example, this will avoid the confusing situation of a 164 * discovery coming in on an IB interface and the initiator 165 * then doing the normal login on an ethernet interface. 166 */ 167 sin = (struct sockaddr_in *)&ss; 168 sin6 = (struct sockaddr_in6 *)&ss; 169 for (pass = 1; pass <= 2; pass++) { 170 tip = &ipaddr_p->al_addrs[0]; 171 for (i = 0; i < ipaddr_p->al_out_cnt; i++, tip++) { 172 /* Convert the address into sockaddr_storage format */ 173 switch (tip->a_addr.i_insize) { 174 case sizeof (struct in_addr): 175 sin->sin_family = AF_INET; 176 sin->sin_port = htons(ISCSI_LISTEN_PORT); 177 sin->sin_addr = tip->a_addr.i_addr.in4; 178 break; 179 case sizeof (struct in6_addr): 180 sin6->sin6_family = AF_INET6; 181 sin6->sin6_port = htons(ISCSI_LISTEN_PORT); 182 sin6->sin6_addr = tip->a_addr.i_addr.in6; 183 break; 184 default: 185 ASSERT(0); 186 continue; 187 } 188 switch (pass) { 189 case 1: 190 /* 191 * On the first pass, skip portals that 192 * do not match the incoming connection. 193 */ 194 if (idm_ss_compare(&ss, &ict->ict_ic->ic_laddr, 195 B_TRUE, B_TRUE) != 0) 196 continue; 197 break; 198 case 2: 199 /* 200 * On the second pass, process the 201 * remaining portals. 202 */ 203 if (idm_ss_compare(&ss, &ict->ict_ic->ic_laddr, 204 B_TRUE, B_TRUE) == 0) 205 continue; 206 break; 207 } 208 /* 209 * Add portal to the response list. 210 * By convention, the default portal group tag == 1 211 */ 212 iscsit_add_portal(&ss, 1, nv_resp); 213 } 214 } 215 } 216 217 /* 218 * Process a portal group from the configuration database. 219 */ 220 static void 221 iscsit_add_portals(iscsit_conn_t *ict, iscsit_tpgt_t *tpg_list, 222 nvlist_t *nv_resp) 223 { 224 int pass; 225 iscsit_portal_t *portal, *next_portal; 226 iscsit_tpg_t *tpg; 227 struct sockaddr_storage *ss; 228 229 /* 230 * As with the default portal group, output the portal used by 231 * the incoming request first. 232 */ 233 tpg = tpg_list->tpgt_tpg; 234 for (pass = 1; pass <= 2; pass++) { 235 for (portal = avl_first(&tpg->tpg_portal_list); 236 portal != NULL; 237 portal = next_portal) { 238 239 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal); 240 ss = &portal->portal_addr; 241 switch (pass) { 242 case 1: 243 /* 244 * On the first pass, skip portals that 245 * do not match the incoming connection. 246 */ 247 if (idm_ss_compare(ss, &ict->ict_ic->ic_laddr, 248 B_TRUE, B_TRUE) != 0) 249 continue; 250 break; 251 case 2: 252 /* 253 * On the second pass, process the 254 * remaining portals. 255 */ 256 if (idm_ss_compare(ss, &ict->ict_ic->ic_laddr, 257 B_TRUE, B_TRUE) == 0) 258 continue; 259 break; 260 } 261 /* Add portal to the response list */ 262 iscsit_add_portal(ss, tpg_list->tpgt_tag, nv_resp); 263 } 264 } 265 } 266 267 /* 268 * Process all the portal groups bound to a particular target. 269 */ 270 static void 271 iscsit_add_tpgs(iscsit_conn_t *ict, iscsit_tgt_t *target, 272 idm_addr_list_t *ipaddr_p, nvlist_t *nv_resp) 273 { 274 iscsit_tpgt_t *tpg_list; 275 276 /* 277 * Look through the portal groups associated with this target. 278 */ 279 mutex_enter(&target->target_mutex); 280 tpg_list = avl_first(&target->target_tpgt_list); 281 282 /* check for the default portal group */ 283 if (tpg_list->tpgt_tpg == iscsit_global.global_default_tpg) { 284 /* 285 * The default portal group is a special case and will 286 * return all reasonable interfaces on this node. 287 * 288 * A target cannot be bound to other portal groups 289 * if it is bound to the default portal group. 290 */ 291 ASSERT(AVL_NEXT(&target->target_tpgt_list, tpg_list) == NULL); 292 293 if (ipaddr_p != NULL) { 294 /* convert the ip address list to nvlist format */ 295 iscsit_add_default_portals(ict, ipaddr_p, nv_resp); 296 } 297 mutex_exit(&target->target_mutex); 298 return; 299 } 300 301 /* 302 * Not the default portal group - process the user defined tpgs 303 */ 304 ASSERT(tpg_list != NULL); 305 while (tpg_list != NULL) { 306 307 ASSERT(tpg_list->tpgt_tpg != iscsit_global.global_default_tpg); 308 309 /* 310 * Found a defined portal group - add each portal address. 311 * As with the default portal group, make 2 passes over 312 * the addresses in order to output the connection 313 * address first. 314 */ 315 iscsit_add_portals(ict, tpg_list, nv_resp); 316 317 tpg_list = AVL_NEXT(&target->target_tpgt_list, tpg_list); 318 } 319 mutex_exit(&target->target_mutex); 320 } 321 322 #ifdef DEBUG 323 /* 324 * To test with smaller PDUs in order to force multi-PDU responses, 325 * set this value such that: 0 < test_max_len < 8192 326 */ 327 uint32_t iscsit_text_max_len = ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 328 #endif 329 330 /* 331 * Format a text response PDU from the text buffer and send it. 332 */ 333 static void 334 iscsit_send_next_text_response(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) 335 { 336 iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr; 337 iscsi_text_rsp_hdr_t *th_resp; 338 idm_pdu_t *resp; 339 uint32_t len, remainder, max_len; 340 char *base; 341 boolean_t final; 342 343 max_len = ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 344 #ifdef DEBUG 345 if (iscsit_text_max_len > 0 && iscsit_text_max_len < max_len) 346 max_len = iscsit_text_max_len; 347 #endif 348 do { 349 remainder = ict->ict_text_rsp_valid_len - ict->ict_text_rsp_off; 350 if (remainder <= max_len) { 351 len = remainder; 352 final = B_TRUE; 353 } else { 354 len = max_len; 355 final = B_FALSE; 356 } 357 /* 358 * Allocate a PDU and copy in text response buffer 359 */ 360 resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), len); 361 idm_pdu_init(resp, ict->ict_ic, ict, 362 iscsit_text_resp_complete_cb); 363 /* Advance the StatSN for each Text Response sent */ 364 resp->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; 365 base = ict->ict_text_rsp_buf + ict->ict_text_rsp_off; 366 bcopy(base, resp->isp_data, len); 367 /* 368 * Fill in the response header 369 */ 370 th_resp = (iscsi_text_rsp_hdr_t *)resp->isp_hdr; 371 bzero(th_resp, sizeof (*th_resp)); 372 th_resp->opcode = ISCSI_OP_TEXT_RSP; 373 th_resp->itt = th_req->itt; 374 hton24(th_resp->dlength, len); 375 if (final) { 376 th_resp->flags = ISCSI_FLAG_FINAL; 377 th_resp->ttt = ISCSI_RSVD_TASK_TAG; 378 kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len); 379 ict->ict_text_rsp_buf = NULL; 380 ict->ict_text_rsp_len = 0; 381 ict->ict_text_rsp_valid_len = 0; 382 ict->ict_text_rsp_off = 0; 383 } else { 384 th_resp->flags = ISCSI_FLAG_TEXT_CONTINUE; 385 th_resp->ttt = ict->ict_text_rsp_ttt; 386 ict->ict_text_rsp_off += len; 387 } 388 /* Send the response on its way */ 389 iscsit_conn_hold(ict); 390 iscsit_pdu_tx(resp); 391 } while (!final); 392 /* Free the request pdu */ 393 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS); 394 } 395 396 /* 397 * Clean-up the text buffer if it exists. 398 */ 399 void 400 iscsit_text_cmd_fini(iscsit_conn_t *ict) 401 { 402 if (ict->ict_text_rsp_buf != NULL) { 403 ASSERT(ict->ict_text_rsp_len != 0); 404 kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len); 405 } 406 ict->ict_text_rsp_buf = NULL; 407 ict->ict_text_rsp_len = 0; 408 ict->ict_text_rsp_valid_len = 0; 409 ict->ict_text_rsp_off = 0; 410 } 411 412 /* 413 * Process an iSCSI text command. 414 * 415 * This code only handles the common case of a text command 416 * containing the single tuple SendTargets=All issued during 417 * a discovery session. The request will always arrive in a 418 * single PDU, but the response may span multiple PDUs if the 419 * configuration is large. I.e. many targets and portals. 420 * 421 * The request is checked for correctness and then the response 422 * is generated from the global target into nvlist format. Then 423 * the nvlist is reformatted into idm textbuf format which reflects 424 * the iSCSI defined <name=value> specification. Finally, the 425 * textbuf is sent to the initiator in one or more text response PDUs 426 */ 427 void 428 iscsit_pdu_op_text_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) 429 { 430 iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr; 431 nvlist_t *nv_resp; 432 char *kv_pair; 433 int flags; 434 char *textbuf; 435 int textbuflen; 436 int validlen; 437 int rc; 438 439 flags = th_req->flags; 440 if ((flags & ISCSI_FLAG_FINAL) != ISCSI_FLAG_FINAL) { 441 /* Cannot handle multi-PDU requests now */ 442 iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); 443 return; 444 } 445 if (th_req->ttt != ISCSI_RSVD_TASK_TAG) { 446 /* 447 * This is the initiator acknowledging our last PDU and 448 * indicating it is ready for the next PDU in the sequence. 449 */ 450 /* 451 * There can only be one outstanding text request on a 452 * connection. Make sure this one PDU has the current TTT. 453 */ 454 /* XXX combine the following 3 checks after testing */ 455 if (th_req->ttt != ict->ict_text_rsp_ttt) { 456 /* Not part of this sequence */ 457 iscsit_text_reject(rx_pdu, 458 ISCSI_REJECT_CMD_NOT_SUPPORTED); 459 return; 460 } 461 /* 462 * ITT should match what was saved from first PDU. 463 */ 464 if (th_req->itt != ict->ict_text_req_itt) { 465 /* Not part of this sequence */ 466 iscsit_text_reject(rx_pdu, 467 ISCSI_REJECT_CMD_NOT_SUPPORTED); 468 return; 469 } 470 /* 471 * Cannot deal with more key/value pairs now. 472 */ 473 if (rx_pdu->isp_datalen != 0) { 474 iscsit_text_reject(rx_pdu, 475 ISCSI_REJECT_CMD_NOT_SUPPORTED); 476 return; 477 } 478 iscsit_send_next_text_response(ict, rx_pdu); 479 return; 480 } 481 482 /* 483 * Initiator has started a new text request. Only 484 * one can be active at a time, so abandon any previous 485 * text request on this connection. 486 */ 487 iscsit_text_cmd_fini(ict); 488 489 /* Set the target task tag. */ 490 iscsit_bump_ttt(ict); 491 492 /* Save the initiator task tag */ 493 ict->ict_text_req_itt = th_req->itt; 494 495 /* 496 * Make sure this is a proper SendTargets request 497 */ 498 textbuf = (char *)rx_pdu->isp_data; 499 textbuflen = rx_pdu->isp_datalen; 500 kv_pair = "SendTargets=All"; 501 if (textbuflen >= strlen(kv_pair) && 502 strcmp(kv_pair, textbuf) == 0 && 503 ict->ict_op.op_discovery_session == B_TRUE) { 504 /* 505 * Most common case of SendTargets=All during discovery. 506 */ 507 idm_addr_list_t *ipaddr_p; 508 iscsit_tgt_t *tgt, *ntgt; 509 int ipsize; 510 511 512 /* Create an nvlist for response */ 513 if (nvlist_alloc(&nv_resp, 0, KM_SLEEP) != 0) { 514 iscsit_text_reject(rx_pdu, 515 ISCSI_REJECT_CMD_NOT_SUPPORTED); 516 return; 517 } 518 519 /* Get the list of local interface addresses */ 520 ipsize = idm_get_ipaddr(&ipaddr_p); 521 522 /* Add targets to the response list */ 523 ISCSIT_GLOBAL_LOCK(RW_READER); 524 for (tgt = avl_first(&iscsit_global.global_target_list); 525 tgt != NULL; tgt = ntgt) { 526 struct sockaddr_storage v4sa, *sa; 527 iscsit_tgt_state_t state; 528 iscsit_portal_t *portal; 529 iscsit_tpgt_t *tpgt; 530 531 ntgt = AVL_NEXT(&iscsit_global.global_target_list, tgt); 532 533 /* Only report online and onlining targets */ 534 state = tgt->target_state; 535 if (state != TS_ONLINING && state != TS_ONLINE && 536 state != TS_STMF_ONLINE) 537 continue; 538 539 /* 540 * Report target if: 541 * - it is bound to default TPG 542 * - one of the addresses of TPGs the target is bound 543 * to matches incoming connection dst address 544 */ 545 sa = &ict->ict_ic->ic_laddr; 546 mutex_enter(&tgt->target_mutex); 547 tpgt = avl_first(&tgt->target_tpgt_list); 548 if (!(IS_DEFAULT_TPGT(tpgt))) { 549 portal = iscsit_tgt_lookup_portal(tgt, sa, 550 &tpgt); 551 if (portal == NULL && 552 iscsit_is_v4_mapped(sa, &v4sa)) { 553 portal = iscsit_tgt_lookup_portal(tgt, 554 &v4sa, &tpgt); 555 } 556 if (portal == NULL) { 557 mutex_exit(&tgt->target_mutex); 558 continue; 559 } 560 iscsit_portal_rele(portal); 561 iscsit_tpgt_rele(tpgt); 562 } 563 mutex_exit(&tgt->target_mutex); 564 565 if (nvlist_add_string(nv_resp, "TargetName", 566 tgt->target_name) == 0) { 567 /* Add the portal groups bound to this target */ 568 iscsit_add_tpgs(ict, tgt, ipaddr_p, nv_resp); 569 } 570 } 571 ISCSIT_GLOBAL_UNLOCK(); 572 if (ipsize > 0) 573 kmem_free(ipaddr_p, ipsize); 574 575 /* Convert the response nvlist into an idm text buffer */ 576 textbuf = 0; 577 textbuflen = 0; 578 validlen = 0; 579 rc = idm_nvlist_to_textbuf(nv_resp, &textbuf, 580 &textbuflen, &validlen); 581 nvlist_free(nv_resp); 582 if (rc != 0) { 583 if (textbuf && textbuflen) 584 kmem_free(textbuf, textbuflen); 585 iscsit_text_reject(rx_pdu, 586 ISCSI_REJECT_CMD_NOT_SUPPORTED); 587 return; 588 } 589 ict->ict_text_rsp_buf = textbuf; 590 ict->ict_text_rsp_len = textbuflen; 591 ict->ict_text_rsp_valid_len = validlen; 592 ict->ict_text_rsp_off = 0; 593 iscsit_send_next_text_response(ict, rx_pdu); 594 } else { 595 /* 596 * Other cases to handle 597 * Discovery session: 598 * SendTargets=<target_name> 599 * Normal session 600 * SendTargets=<NULL> - assume target name of session 601 * All others 602 * Error 603 */ 604 iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); 605 return; 606 } 607 } 608