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