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