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