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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * iSNS Client 26 */ 27 28 #include "iscsi.h" /* For ISCSI_MAX_IOVEC */ 29 #include "isns_protocol.h" 30 #include "isns_client.h" 31 #include "persistent.h" 32 33 #ifdef _KERNEL 34 #include <sys/sunddi.h> 35 #else 36 #include <stdlib.h> 37 #endif 38 #include <netinet/tcp.h> 39 #include <sys/types.h> 40 41 /* For local use */ 42 #define ISNS_MAX_IOVEC 5 43 #define MAX_XID (2^16) 44 #define MAX_RCV_RSP_COUNT 10 /* Maximum number of unmatched xid */ 45 #define ISNS_RCV_TIMEOUT 5 46 #define ISNS_RCV_RETRY_MAX 2 47 #define IPV4_RSVD_BYTES 10 48 49 typedef struct isns_reg_arg { 50 iscsi_addr_t *isns_server_addr; 51 uint8_t *node_name; 52 size_t node_name_len; 53 uint8_t *node_alias; 54 size_t node_alias_len; 55 uint32_t node_type; 56 uint8_t *lhba_handle; 57 } isns_reg_arg_t; 58 59 typedef struct isns_async_thread_arg { 60 uint8_t *lhba_handle; 61 void *listening_so; 62 } isns_async_thread_arg_t; 63 64 /* One global queue to serve all LHBA instances. */ 65 static ddi_taskq_t *reg_query_taskq; 66 static kmutex_t reg_query_taskq_mutex; 67 68 /* One global queue to serve all LHBA instances. */ 69 static ddi_taskq_t *scn_taskq; 70 static kmutex_t scn_taskq_mutex; 71 72 /* One globally maintained transaction ID. */ 73 static uint16_t xid = 0; 74 75 /* 76 * One SCN callback registration per LHBA instance. For now, since we 77 * support only one instance, we create one place holder for the 78 * callback. 79 */ 80 void (*scn_callback_p)(void *); 81 82 /* 83 * One thread, port, local address, and listening socket per LHBA instance. 84 * For now, since we support only one instance, we create one set of place 85 * holder for these data. 86 */ 87 static boolean_t esi_scn_thr_to_shutdown = B_FALSE; 88 static iscsi_thread_t *esi_scn_thr_id = NULL; 89 static void *instance_listening_so = NULL; 90 /* 91 * This mutex protects all the per LHBA instance variables, i.e., 92 * esi_scn_thr_to_shutdown, esi_scn_thr_id, and instance_listening_so. 93 */ 94 static kmutex_t esi_scn_thr_mutex; 95 96 /* iSNS related helpers */ 97 /* Return status */ 98 #define ISNS_OK 0 99 #define ISNS_BAD_SVR_ADDR 1 100 #define ISNS_INTERNAL_ERR 2 101 #define ISNS_CANNOT_FIND_LOCAL_ADDR 3 102 static int discover_isns_server(uint8_t *lhba_handle, 103 iscsi_addr_list_t **isns_server_addrs); 104 static int create_esi_scn_thr(uint8_t *lhba_handle, 105 iscsi_addr_t *isns_server_addr); 106 static void esi_scn_thr_cleanup(void); 107 static void register_isns_client(void *arg); 108 static isns_status_t do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr, 109 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type); 110 static isns_status_t do_isns_dev_dereg(iscsi_addr_t *isns_server_addr, 111 uint8_t *node_name); 112 113 /* 114 * Make query to all iSNS servers visible to the specified LHBA. 115 * The query could be made for all target nodes or for a specific target 116 * node. 117 */ 118 static isns_status_t do_isns_query(boolean_t is_query_all_nodes_b, 119 uint8_t *lhba_handle, uint8_t *target_node_name, 120 uint8_t *source_node_name, uint8_t *source_node_alias, 121 uint32_t source_node_type, isns_portal_group_list_t **pg_list); 122 123 /* 124 * Create DevAttrQuery message requesting portal group information for all 125 * target nodes. Send it to the specified iSNS server. Parse the 126 * DevAttrQueryRsp PDU and translate the results into a portal group list 127 * object. 128 */ 129 static isns_status_t do_isns_dev_attr_query_all_nodes( 130 iscsi_addr_t *isns_server_addr, uint8_t *node_name, 131 uint8_t *node_alias, isns_portal_group_list_t **pg_list); 132 133 /* 134 * Create DevAttrQuery message requesting portal group information for the 135 * specified target node. Send it to the specified iSNS server. Parse the 136 * DevAttrQueryRsp PDU and translate the results into a portal group list 137 * object. 138 */ 139 static isns_status_t do_isns_dev_attr_query_one_node( 140 iscsi_addr_t *isns_server_addr, uint8_t *target_node_name, 141 uint8_t *source_node_name, uint8_t *source_node_alias, 142 uint32_t source_node_type, isns_portal_group_list_t **pg_list); 143 144 static void isns_service_esi_scn(iscsi_thread_t *thread, void* arg); 145 static void (*scn_callback_lookup(uint8_t *lhba_handle))(void *); 146 147 /* Transport related helpers */ 148 static void *isns_open(iscsi_addr_t *isns_server_addr); 149 static ssize_t isns_send_pdu(void *socket, isns_pdu_t *pdu); 150 static size_t isns_rcv_pdu(void *so, isns_pdu_t **pdu, size_t *pdu_size); 151 static boolean_t find_listening_addr(iscsi_addr_t *local_addr, 152 void *listening_so); 153 static boolean_t find_local_portal(iscsi_addr_t *isns_server_addr, 154 iscsi_addr_t **local_addr, void **listening_so); 155 156 /* iSNS protocol related helpers */ 157 static size_t isns_create_pdu_header(uint16_t func_id, 158 uint16_t flags, isns_pdu_t **pdu); 159 static int isns_add_attr(isns_pdu_t *pdu, 160 size_t max_pdu_size, uint32_t attr_id, uint32_t attr_len, 161 void *attr_data, uint32_t attr_numeric_data); 162 static uint16_t create_xid(void); 163 static size_t isns_create_dev_attr_reg_pdu( 164 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type, 165 uint16_t *xid, isns_pdu_t **out_pdu); 166 static size_t isns_create_dev_dereg_pdu(uint8_t *node_name, 167 uint16_t *xid_p, isns_pdu_t **out_pdu); 168 static size_t isns_create_dev_attr_qry_target_nodes_pdu( 169 uint8_t *node_name, uint8_t *node_alias, uint16_t *xid, 170 isns_pdu_t **out_pdu); 171 static size_t isns_create_dev_attr_qry_one_pg_pdu( 172 uint8_t *target_node_name, uint8_t *source_node_name, 173 uint16_t *xid, isns_pdu_t **out_pdu); 174 static size_t isns_create_esi_rsp_pdu(uint32_t rsp_status_code, 175 isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu); 176 static size_t isns_create_scn_reg_pdu(uint8_t *node_name, 177 uint8_t *node_alias, uint16_t *xid, isns_pdu_t **out_pdu); 178 static size_t isns_create_scn_dereg_pdu(uint8_t *node_name, 179 uint16_t *xid_p, isns_pdu_t **out_pdu); 180 static size_t isns_create_scn_rsp_pdu(uint32_t rsp_status_code, 181 isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu); 182 static uint32_t isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p); 183 static uint32_t isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p); 184 185 /* 186 * Process and parse a DevAttrQryRsp message. The routine creates a list 187 * of Portal Group objects if the message is parasable without any issue. 188 * If the parsing is not successful, the pg_list will be set to NULL. 189 */ 190 static uint32_t isns_process_dev_attr_qry_target_nodes_pdu( 191 iscsi_addr_t *isns_server_addr, uint16_t payload_funcId, 192 isns_resp_t *resp_p, size_t resp_len, 193 isns_portal_group_list_t **pg_list); 194 static uint32_t isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p); 195 static uint32_t isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p); 196 static uint32_t isns_process_esi(isns_pdu_t *esi_pdu_p); 197 static uint32_t isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle); 198 199 void 200 isns_client_init() 201 { 202 mutex_init(®_query_taskq_mutex, NULL, MUTEX_DRIVER, NULL); 203 mutex_enter(®_query_taskq_mutex); 204 reg_query_taskq = ddi_taskq_create(NULL, "isns_reg_query_taskq", 205 1, TASKQ_DEFAULTPRI, 0); 206 mutex_exit(®_query_taskq_mutex); 207 208 mutex_init(&scn_taskq_mutex, NULL, MUTEX_DRIVER, NULL); 209 mutex_enter(&scn_taskq_mutex); 210 scn_taskq = ddi_taskq_create(NULL, "isns_scn_taskq", 211 1, TASKQ_DEFAULTPRI, 0); 212 mutex_exit(&scn_taskq_mutex); 213 214 mutex_init(&esi_scn_thr_mutex, NULL, MUTEX_DRIVER, NULL); 215 216 /* MISC initializations. */ 217 scn_callback_p = NULL; 218 esi_scn_thr_id = NULL; 219 instance_listening_so = NULL; 220 esi_scn_thr_to_shutdown = B_FALSE; 221 xid = 0; 222 } 223 224 void 225 isns_client_cleanup() 226 { 227 ddi_taskq_t *tmp_taskq_p; 228 229 mutex_enter(&scn_taskq_mutex); 230 tmp_taskq_p = scn_taskq; 231 scn_taskq = NULL; 232 mutex_exit(&scn_taskq_mutex); 233 ddi_taskq_destroy(tmp_taskq_p); 234 235 mutex_enter(®_query_taskq_mutex); 236 tmp_taskq_p = reg_query_taskq; 237 reg_query_taskq = NULL; 238 mutex_exit(®_query_taskq_mutex); 239 ddi_taskq_destroy(tmp_taskq_p); 240 241 mutex_destroy(®_query_taskq_mutex); 242 mutex_destroy(&scn_taskq_mutex); 243 244 esi_scn_thr_cleanup(); 245 246 mutex_destroy(&esi_scn_thr_mutex); 247 } 248 249 isns_status_t 250 isns_reg(uint8_t *lhba_handle, 251 uint8_t *node_name, 252 size_t node_name_len, 253 uint8_t *node_alias, 254 size_t node_alias_len, 255 uint32_t node_type, 256 void (*scn_callback)(void *)) 257 { 258 int i; 259 int list_space; 260 iscsi_addr_list_t *isns_server_addr_list; 261 isns_reg_arg_t *reg_args_p; 262 263 /* Look up the iSNS Server address(es) based on the specified ISID */ 264 if (discover_isns_server(lhba_handle, &isns_server_addr_list) != 265 ISNS_OK) { 266 return (isns_no_svr_found); 267 } 268 269 /* No iSNS server discovered - no registration needed. */ 270 if (isns_server_addr_list->al_out_cnt == 0) { 271 list_space = sizeof (iscsi_addr_list_t); 272 kmem_free(isns_server_addr_list, list_space); 273 isns_server_addr_list = NULL; 274 return (isns_no_svr_found); 275 } 276 277 /* Check and create ESI/SCN threads and populate local address */ 278 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) { 279 if (create_esi_scn_thr(lhba_handle, 280 &(isns_server_addr_list->al_addrs[i])) == ISNS_OK) { 281 break; 282 } 283 } 284 if (i == isns_server_addr_list->al_out_cnt) { 285 /* 286 * Problem creating ESI/SCN thread 287 * Free the server list 288 */ 289 list_space = sizeof (iscsi_addr_list_t); 290 if (isns_server_addr_list->al_out_cnt > 0) { 291 list_space += (sizeof (iscsi_addr_t) * 292 (isns_server_addr_list->al_out_cnt - 1)); 293 } 294 kmem_free(isns_server_addr_list, list_space); 295 isns_server_addr_list = NULL; 296 return (isns_internal_err); 297 } 298 299 /* Register against all iSNS servers discovered. */ 300 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) { 301 reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP); 302 reg_args_p->isns_server_addr = 303 kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 304 bcopy(&isns_server_addr_list->al_addrs[i], 305 reg_args_p->isns_server_addr, sizeof (iscsi_addr_t)); 306 reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP); 307 bcopy(node_name, reg_args_p->node_name, node_name_len); 308 reg_args_p->node_name_len = node_name_len; 309 reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP); 310 bcopy(node_alias, reg_args_p->node_alias, node_alias_len); 311 reg_args_p->node_alias_len = node_alias_len; 312 reg_args_p->node_type = node_type; 313 314 /* Dispatch the registration request */ 315 register_isns_client(reg_args_p); 316 } 317 318 /* Free the server list */ 319 list_space = sizeof (iscsi_addr_list_t); 320 if (isns_server_addr_list->al_out_cnt > 0) { 321 list_space += (sizeof (iscsi_addr_t) * 322 (isns_server_addr_list->al_out_cnt - 1)); 323 } 324 kmem_free(isns_server_addr_list, list_space); 325 isns_server_addr_list = NULL; 326 327 /* Register the scn_callback. */ 328 scn_callback_p = scn_callback; 329 330 return (isns_ok); 331 } 332 333 isns_status_t 334 isns_reg_one_server(entry_t *isns_server, 335 uint8_t *lhba_handle, 336 uint8_t *node_name, 337 size_t node_name_len, 338 uint8_t *node_alias, 339 size_t node_alias_len, 340 uint32_t node_type, 341 void (*scn_callback)(void *)) 342 { 343 int status; 344 iscsi_addr_t *ap; 345 isns_reg_arg_t *reg_args_p; 346 347 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 348 ap->a_port = isns_server->e_port; 349 ap->a_addr.i_insize = isns_server->e_insize; 350 if (isns_server->e_insize == sizeof (struct in_addr)) { 351 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr); 352 } else if (isns_server->e_insize == sizeof (struct in6_addr)) { 353 bcopy(&(isns_server->e_u.u_in6.s6_addr), 354 ap->a_addr.i_addr.in6.s6_addr, 355 sizeof (struct in6_addr)); 356 } else { 357 kmem_free(ap, sizeof (iscsi_addr_t)); 358 return (isns_op_failed); 359 } 360 361 /* Check and create ESI/SCN threads and populate local address */ 362 if ((status = create_esi_scn_thr(lhba_handle, ap)) 363 != ISNS_OK) { 364 /* Problem creating ESI/SCN thread */ 365 DTRACE_PROBE1(isns_reg_one_server_create_esi_scn_thr, 366 int, status); 367 kmem_free(ap, sizeof (iscsi_addr_t)); 368 return (isns_internal_err); 369 } 370 371 reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP); 372 reg_args_p->isns_server_addr = 373 kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 374 bcopy(ap, reg_args_p->isns_server_addr, sizeof (iscsi_addr_t)); 375 reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP); 376 bcopy(node_name, reg_args_p->node_name, node_name_len); 377 reg_args_p->node_name_len = node_name_len; 378 reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP); 379 bcopy(node_alias, reg_args_p->node_alias, node_alias_len); 380 reg_args_p->node_alias_len = node_alias_len; 381 reg_args_p->node_type = node_type; 382 383 /* Dispatch the registration request */ 384 register_isns_client(reg_args_p); 385 386 /* Register the scn_callback. */ 387 scn_callback_p = scn_callback; 388 389 kmem_free(ap, sizeof (iscsi_addr_t)); 390 return (isns_ok); 391 } 392 393 isns_status_t 394 isns_dereg(uint8_t *lhba_handle, 395 uint8_t *node_name) 396 { 397 int i; 398 int isns_svr_lst_sz; 399 int list_space; 400 iscsi_addr_list_t *isns_server_addr_list = NULL; 401 isns_status_t dereg_stat, combined_dereg_stat; 402 403 /* Look up the iSNS Server address(es) based on the specified ISID */ 404 if (discover_isns_server(lhba_handle, &isns_server_addr_list) != 405 ISNS_OK) { 406 return (isns_no_svr_found); 407 } 408 ASSERT(isns_server_addr_list != NULL); 409 if (isns_server_addr_list->al_out_cnt == 0) { 410 isns_svr_lst_sz = sizeof (iscsi_addr_list_t); 411 kmem_free(isns_server_addr_list, isns_svr_lst_sz); 412 isns_server_addr_list = NULL; 413 return (isns_no_svr_found); 414 } 415 416 combined_dereg_stat = isns_ok; 417 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) { 418 dereg_stat = do_isns_dev_dereg( 419 &isns_server_addr_list->al_addrs[i], 420 node_name); 421 if (dereg_stat == isns_ok) { 422 if (combined_dereg_stat != isns_ok) { 423 combined_dereg_stat = isns_op_partially_failed; 424 } 425 } else { 426 if (combined_dereg_stat == isns_ok) { 427 combined_dereg_stat = isns_op_partially_failed; 428 } 429 } 430 } 431 432 /* Free the server list. */ 433 list_space = sizeof (iscsi_addr_list_t); 434 if (isns_server_addr_list->al_out_cnt > 0) { 435 list_space += (sizeof (iscsi_addr_t) * 436 (isns_server_addr_list->al_out_cnt - 1)); 437 } 438 kmem_free(isns_server_addr_list, list_space); 439 isns_server_addr_list = NULL; 440 441 /* Cleanup ESI/SCN thread. */ 442 esi_scn_thr_cleanup(); 443 444 return (combined_dereg_stat); 445 } 446 447 isns_status_t 448 isns_dereg_one_server(entry_t *isns_server, 449 uint8_t *node_name, 450 boolean_t is_last_isns_server_b) 451 { 452 iscsi_addr_t *ap; 453 isns_status_t dereg_stat; 454 455 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP); 456 ap->a_port = isns_server->e_port; 457 ap->a_addr.i_insize = isns_server->e_insize; 458 if (isns_server->e_insize == sizeof (struct in_addr)) { 459 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr); 460 } else if (isns_server->e_insize == sizeof (struct in6_addr)) { 461 bcopy(&(isns_server->e_u.u_in6.s6_addr), 462 ap->a_addr.i_addr.in6.s6_addr, 463 sizeof (struct in6_addr)); 464 } else { 465 kmem_free(ap, sizeof (iscsi_addr_t)); 466 return (isns_op_failed); 467 } 468 469 dereg_stat = do_isns_dev_dereg(ap, node_name); 470 471 kmem_free(ap, sizeof (iscsi_addr_t)); 472 473 if (is_last_isns_server_b == B_TRUE) { 474 /* 475 * Clean up ESI/SCN thread resource if it is the 476 * last known iSNS server. 477 */ 478 esi_scn_thr_cleanup(); 479 } 480 481 return (dereg_stat); 482 } 483 484 isns_status_t 485 isns_query(uint8_t *lhba_handle, 486 uint8_t *node_name, 487 uint8_t *node_alias, 488 uint32_t node_type, 489 isns_portal_group_list_t **pg_list) 490 { 491 return (do_isns_query(B_TRUE, 492 lhba_handle, 493 (uint8_t *)"", 494 node_name, 495 node_alias, 496 node_type, 497 pg_list)); 498 } 499 500 /* ARGSUSED */ 501 isns_status_t 502 isns_query_one_server(iscsi_addr_t *isns_server_addr, 503 uint8_t *lhba_handle, 504 uint8_t *node_name, 505 uint8_t *node_alias, 506 uint32_t node_type, 507 isns_portal_group_list_t **pg_list) 508 { 509 return (do_isns_dev_attr_query_all_nodes(isns_server_addr, 510 node_name, 511 node_alias, 512 pg_list)); 513 } 514 515 isns_status_t 516 isns_query_one_node(uint8_t *target_node_name, 517 uint8_t *lhba_handle, 518 uint8_t *source_node_name, 519 uint8_t *source_node_alias, 520 uint32_t source_node_type, 521 isns_portal_group_list_t **pg_list) 522 { 523 return (do_isns_query(B_FALSE, 524 lhba_handle, 525 target_node_name, 526 source_node_name, 527 source_node_alias, 528 source_node_type, 529 pg_list)); 530 } 531 532 /* ARGSUSED */ 533 isns_status_t 534 isns_query_one_server_one_node(iscsi_addr_t *isns_server_addr, 535 uint8_t *target_node_name, 536 uint8_t *lhba_handle, 537 uint8_t *source_node_name, 538 uint8_t *source_node_alias, 539 uint32_t source_node_type, 540 isns_portal_group_list_t **pg_list) { 541 /* Not supported yet. */ 542 *pg_list = NULL; 543 return (isns_op_failed); 544 } 545 546 /* ARGSUSED */ 547 static 548 int 549 discover_isns_server(uint8_t *lhba_handle, 550 iscsi_addr_list_t **isns_server_addrs) 551 { 552 entry_t e; 553 int i; 554 int isns_server_count = 1; 555 int list_space; 556 void *void_p; 557 558 /* 559 * Use supported iSNS server discovery method to find out all the 560 * iSNS servers. For now, only static configuration method is 561 * supported. 562 */ 563 isns_server_count = 0; 564 void_p = NULL; 565 persistent_isns_addr_lock(); 566 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) { 567 isns_server_count++; 568 } 569 persistent_isns_addr_unlock(); 570 571 list_space = sizeof (iscsi_addr_list_t); 572 if (isns_server_count > 0) { 573 list_space += (sizeof (iscsi_addr_t) * (isns_server_count - 1)); 574 } 575 *isns_server_addrs = (iscsi_addr_list_t *)kmem_zalloc(list_space, 576 KM_SLEEP); 577 (*isns_server_addrs)->al_out_cnt = isns_server_count; 578 579 persistent_isns_addr_lock(); 580 i = 0; 581 void_p = NULL; 582 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) { 583 iscsi_addr_t *ap; 584 585 ap = &((*isns_server_addrs)->al_addrs[i]); 586 ap->a_port = e.e_port; 587 ap->a_addr.i_insize = e.e_insize; 588 if (e.e_insize == sizeof (struct in_addr)) { 589 ap->a_addr.i_addr.in4.s_addr = (e.e_u.u_in4.s_addr); 590 } else if (e.e_insize == sizeof (struct in6_addr)) { 591 bcopy(&e.e_u.u_in6.s6_addr, 592 ap->a_addr.i_addr.in6.s6_addr, 593 sizeof (struct in6_addr)); 594 } else { 595 kmem_free(*isns_server_addrs, list_space); 596 *isns_server_addrs = NULL; 597 (*isns_server_addrs)->al_out_cnt = 0; 598 return (ISNS_BAD_SVR_ADDR); 599 } 600 i++; 601 } 602 persistent_isns_addr_unlock(); 603 604 return (ISNS_OK); 605 } 606 607 static 608 int 609 create_esi_scn_thr(uint8_t *lhba_handle, iscsi_addr_t *isns_server_address) 610 { 611 void *listening_so = NULL; 612 boolean_t found = B_FALSE; 613 614 ASSERT(lhba_handle != NULL); 615 ASSERT(isns_server_address != NULL); 616 617 /* 618 * Bringing up of the thread should happen regardless of the 619 * subsequent registration status. That means, do not destroy the 620 * ESI/SCN thread already created. 621 */ 622 /* Check and create ESI/SCN thread. */ 623 mutex_enter(&esi_scn_thr_mutex); 624 625 /* Determine local port and address. */ 626 found = find_local_portal(isns_server_address, 627 NULL, &listening_so); 628 if (found == B_FALSE) { 629 if (listening_so != NULL) { 630 iscsi_net->close(listening_so); 631 } 632 mutex_exit(&esi_scn_thr_mutex); 633 return (ISNS_CANNOT_FIND_LOCAL_ADDR); 634 } 635 636 if (esi_scn_thr_id == NULL) { 637 char thr_name[ISCSI_TH_MAX_NAME_LEN]; 638 int rval; 639 isns_async_thread_arg_t *larg; 640 641 /* Assume the LHBA handle has a length of 4 */ 642 if (snprintf(thr_name, sizeof (thr_name) - 1, 643 "isns_client_esi_%x%x%x%x", 644 lhba_handle[0], 645 lhba_handle[1], 646 lhba_handle[2], 647 lhba_handle[3]) >= 648 sizeof (thr_name)) { 649 esi_scn_thr_id = NULL; 650 if (listening_so != NULL) { 651 iscsi_net->close(listening_so); 652 listening_so = NULL; 653 } 654 mutex_exit(&esi_scn_thr_mutex); 655 return (ISNS_INTERNAL_ERR); 656 } 657 658 larg = kmem_zalloc(sizeof (isns_async_thread_arg_t), KM_SLEEP); 659 larg->lhba_handle = lhba_handle; 660 larg->listening_so = listening_so; 661 instance_listening_so = listening_so; 662 esi_scn_thr_to_shutdown = B_FALSE; 663 esi_scn_thr_id = iscsi_thread_create(NULL, 664 thr_name, isns_service_esi_scn, (void *)larg); 665 if (esi_scn_thr_id == NULL) { 666 if (listening_so != NULL) { 667 iscsi_net->close(listening_so); 668 listening_so = NULL; 669 instance_listening_so = NULL; 670 } 671 mutex_exit(&esi_scn_thr_mutex); 672 return (ISNS_INTERNAL_ERR); 673 } 674 675 rval = iscsi_thread_start(esi_scn_thr_id); 676 if (rval == B_FALSE) { 677 iscsi_thread_destroy(esi_scn_thr_id); 678 esi_scn_thr_id = NULL; 679 if (listening_so != NULL) { 680 iscsi_net->close(listening_so); 681 listening_so = NULL; 682 instance_listening_so = NULL; 683 } 684 mutex_exit(&esi_scn_thr_mutex); 685 return (ISNS_INTERNAL_ERR); 686 } 687 (void) iscsi_thread_send_wakeup(esi_scn_thr_id); 688 } 689 mutex_exit(&esi_scn_thr_mutex); 690 691 return (ISNS_OK); 692 } 693 694 static 695 void 696 register_isns_client(void *arg) 697 { 698 isns_reg_arg_t *reg_args; 699 isns_status_t status; 700 701 reg_args = (isns_reg_arg_t *)arg; 702 703 /* Deregister stale registration (if any). */ 704 status = do_isns_dev_dereg(reg_args->isns_server_addr, 705 reg_args->node_name); 706 707 if (status == isns_open_conn_err) { 708 /* Cannot open connection to the server. Stop proceeding. */ 709 kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t)); 710 reg_args->isns_server_addr = NULL; 711 kmem_free(reg_args->node_name, reg_args->node_name_len); 712 reg_args->node_name = NULL; 713 kmem_free(reg_args->node_alias, reg_args->node_alias_len); 714 reg_args->node_alias = NULL; 715 kmem_free(reg_args, sizeof (isns_reg_arg_t)); 716 return; 717 } 718 719 DTRACE_PROBE1(register_isns_client_dereg, isns_status_t, status); 720 721 /* New registration. */ 722 status = do_isns_dev_attr_reg(reg_args->isns_server_addr, 723 reg_args->node_name, reg_args->node_alias, reg_args->node_type); 724 725 DTRACE_PROBE1(register_isns_client_reg, isns_status_t, status); 726 727 /* Cleanup */ 728 kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t)); 729 reg_args->isns_server_addr = NULL; 730 kmem_free(reg_args->node_name, reg_args->node_name_len); 731 reg_args->node_name = NULL; 732 kmem_free(reg_args->node_alias, reg_args->node_alias_len); 733 reg_args->node_alias = NULL; 734 kmem_free(reg_args, sizeof (isns_reg_arg_t)); 735 } 736 737 static 738 isns_status_t 739 do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr, 740 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type) 741 { 742 int rcv_rsp_cnt = 0; 743 int rsp_status; 744 isns_pdu_t *in_pdu, *out_pdu; 745 isns_status_t rval; 746 size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0; 747 uint16_t xid; 748 void *so = NULL; 749 750 out_pdu_size = isns_create_dev_attr_reg_pdu( 751 node_name, 752 node_alias, 753 node_type, 754 &xid, &out_pdu); 755 if (out_pdu_size == 0) { 756 return (isns_create_msg_err); 757 } 758 759 ASSERT(out_pdu != NULL); 760 ASSERT(out_pdu_size > 0); 761 762 so = isns_open(isns_server_addr); 763 if (so == NULL) { 764 /* Log a message and return */ 765 kmem_free(out_pdu, out_pdu_size); 766 out_pdu = NULL; 767 return (isns_open_conn_err); 768 } 769 770 if (isns_send_pdu(so, out_pdu) != 0) { 771 iscsi_net->close(so); 772 kmem_free(out_pdu, out_pdu_size); 773 out_pdu = NULL; 774 return (isns_send_msg_err); 775 } 776 777 /* Done with the out PDU - free it */ 778 kmem_free(out_pdu, out_pdu_size); 779 out_pdu = NULL; 780 781 rcv_rsp_cnt = 0; 782 rval = isns_ok; 783 for (;;) { 784 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 785 ASSERT(bytes_received >= (size_t)0); 786 if (bytes_received == 0) { 787 ASSERT(in_pdu == NULL); 788 ASSERT(in_pdu_size == 0); 789 rval = isns_rcv_msg_err; 790 break; 791 } 792 793 ASSERT(in_pdu != NULL); 794 ASSERT(in_pdu_size > 0); 795 796 if (ntohs(in_pdu->xid) != xid) { 797 rcv_rsp_cnt++; 798 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 799 continue; 800 } else { 801 /* Exceed maximum receive count. */ 802 kmem_free(in_pdu, in_pdu_size); 803 in_pdu = NULL; 804 rval = isns_no_rsp_rcvd; 805 break; 806 } 807 } 808 809 rsp_status = isns_process_dev_attr_reg_rsp(in_pdu); 810 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 811 if (rsp_status == ISNS_RSP_SRC_UNAUTHORIZED) { 812 rval = isns_op_partially_failed; 813 } else { 814 rval = isns_op_failed; 815 } 816 } 817 kmem_free(in_pdu, in_pdu_size); 818 in_pdu = NULL; 819 break; 820 } 821 822 if (rval != isns_ok) { 823 iscsi_net->close(so); 824 return (rval); 825 } 826 827 /* Always register SCN */ 828 out_pdu_size = isns_create_scn_reg_pdu( 829 node_name, node_alias, 830 &xid, &out_pdu); 831 if (out_pdu_size == 0) { 832 iscsi_net->close(so); 833 return (isns_create_msg_err); 834 } 835 836 ASSERT(out_pdu != NULL); 837 ASSERT(out_pdu_size > 0); 838 839 if (isns_send_pdu(so, out_pdu) != 0) { 840 iscsi_net->close(so); 841 kmem_free(out_pdu, out_pdu_size); 842 out_pdu = NULL; 843 return (isns_send_msg_err); 844 } 845 846 /* Done with the out PDU - free it */ 847 kmem_free(out_pdu, out_pdu_size); 848 out_pdu = NULL; 849 850 rcv_rsp_cnt = 0; 851 for (;;) { 852 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 853 ASSERT(bytes_received >= (size_t)0); 854 if (bytes_received == 0) { 855 ASSERT(in_pdu == NULL); 856 ASSERT(in_pdu_size == 0); 857 rval = isns_rcv_msg_err; 858 break; 859 } 860 861 ASSERT(in_pdu != NULL); 862 ASSERT(in_pdu_size > 0); 863 864 if (ntohs(in_pdu->xid) != xid) { 865 rcv_rsp_cnt++; 866 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 867 continue; 868 } else { 869 /* Exceed maximum receive count. */ 870 kmem_free(in_pdu, in_pdu_size); 871 in_pdu = NULL; 872 rval = isns_no_rsp_rcvd; 873 break; 874 } 875 } 876 877 rsp_status = isns_process_scn_reg_rsp(in_pdu); 878 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 879 rval = isns_op_failed; 880 } 881 kmem_free(in_pdu, in_pdu_size); 882 in_pdu = NULL; 883 break; 884 } 885 886 iscsi_net->close(so); 887 888 return (rval); 889 } 890 891 static 892 isns_status_t 893 do_isns_dev_dereg(iscsi_addr_t *isns_server_addr, 894 uint8_t *node_name) 895 { 896 int rcv_rsp_cnt = 0; 897 int rsp_status; 898 isns_pdu_t *in_pdu, *out_pdu; 899 isns_status_t rval; 900 size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0; 901 uint16_t xid; 902 void *so = NULL; 903 904 out_pdu_size = isns_create_dev_dereg_pdu( 905 node_name, 906 &xid, &out_pdu); 907 if (out_pdu_size == 0) { 908 return (isns_create_msg_err); 909 } 910 911 ASSERT(out_pdu != NULL); 912 ASSERT(out_pdu_size > 0); 913 914 so = isns_open(isns_server_addr); 915 if (so == NULL) { 916 /* Log a message and return */ 917 kmem_free(out_pdu, out_pdu_size); 918 out_pdu = NULL; 919 return (isns_open_conn_err); 920 } 921 922 if (isns_send_pdu(so, out_pdu) != 0) { 923 iscsi_net->close(so); 924 kmem_free(out_pdu, out_pdu_size); 925 out_pdu = NULL; 926 return (isns_send_msg_err); 927 } 928 929 /* Done with the out PDU - free it */ 930 kmem_free(out_pdu, out_pdu_size); 931 out_pdu = NULL; 932 933 rcv_rsp_cnt = 0; 934 rval = isns_ok; 935 for (;;) { 936 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 937 ASSERT(bytes_received >= (size_t)0); 938 if (bytes_received == 0) { 939 ASSERT(in_pdu == NULL); 940 ASSERT(in_pdu_size == 0); 941 rval = isns_rcv_msg_err; 942 break; 943 } 944 945 ASSERT(in_pdu != NULL); 946 ASSERT(in_pdu_size > 0); 947 948 if (ntohs(in_pdu->xid) != xid) { 949 rcv_rsp_cnt++; 950 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 951 continue; 952 } else { 953 /* Exceed maximum receive count. */ 954 kmem_free(in_pdu, in_pdu_size); 955 in_pdu = NULL; 956 rval = isns_no_rsp_rcvd; 957 break; 958 } 959 } 960 961 rsp_status = isns_process_dev_attr_dereg_rsp(in_pdu); 962 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 963 rval = isns_op_failed; 964 } 965 kmem_free(in_pdu, in_pdu_size); 966 in_pdu = NULL; 967 break; 968 } 969 970 if (rval != isns_ok) { 971 iscsi_net->close(so); 972 return (rval); 973 } 974 975 /* Always deregister SCN */ 976 out_pdu_size = isns_create_scn_dereg_pdu( 977 node_name, 978 &xid, &out_pdu); 979 if (out_pdu_size == 0) { 980 iscsi_net->close(so); 981 return (isns_create_msg_err); 982 } 983 984 ASSERT(out_pdu != NULL); 985 ASSERT(out_pdu_size > 0); 986 987 if (isns_send_pdu(so, out_pdu) != 0) { 988 iscsi_net->close(so); 989 kmem_free(out_pdu, out_pdu_size); 990 out_pdu = NULL; 991 return (isns_send_msg_err); 992 } 993 994 /* Done with the out PDU - free it */ 995 kmem_free(out_pdu, out_pdu_size); 996 out_pdu = NULL; 997 998 rcv_rsp_cnt = 0; 999 for (;;) { 1000 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 1001 ASSERT(bytes_received >= (size_t)0); 1002 if (bytes_received == 0) { 1003 ASSERT(in_pdu == NULL); 1004 ASSERT(in_pdu_size == 0); 1005 rval = isns_rcv_msg_err; 1006 break; 1007 } 1008 1009 ASSERT(in_pdu != NULL); 1010 ASSERT(in_pdu_size > 0); 1011 1012 if (ntohs(in_pdu->xid) != xid) { 1013 rcv_rsp_cnt++; 1014 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 1015 continue; 1016 } else { 1017 /* Exceed maximum receive count. */ 1018 kmem_free(in_pdu, in_pdu_size); 1019 in_pdu = NULL; 1020 rval = isns_no_rsp_rcvd; 1021 break; 1022 } 1023 } 1024 1025 rsp_status = isns_process_scn_dereg_rsp(in_pdu); 1026 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 1027 rval = isns_op_failed; 1028 } 1029 kmem_free(in_pdu, in_pdu_size); 1030 in_pdu = NULL; 1031 break; 1032 } 1033 1034 iscsi_net->close(so); 1035 1036 return (rval); 1037 } 1038 1039 static 1040 isns_status_t 1041 do_isns_query(boolean_t is_query_all_nodes_b, 1042 uint8_t *lhba_handle, 1043 uint8_t *target_node_name, 1044 uint8_t *source_node_name, 1045 uint8_t *source_node_alias, 1046 uint32_t source_node_type, 1047 isns_portal_group_list_t **pg_list) 1048 { 1049 int i, j, k; 1050 int combined_num_of_pgs, combined_pg_lst_sz, 1051 isns_svr_lst_sz, 1052 tmp_pg_list_sz, 1053 tmp_pg_lists_sz; 1054 iscsi_addr_list_t *isns_server_addr_list = NULL; 1055 isns_portal_group_t *pg; 1056 isns_portal_group_list_t *combined_pg_list, 1057 *tmp_pg_list, **tmp_pg_lists; 1058 isns_status_t qry_stat, combined_qry_stat; 1059 1060 /* Look up the iSNS Server address(es) based on the specified ISID */ 1061 if (discover_isns_server(lhba_handle, &isns_server_addr_list) != 1062 ISNS_OK) { 1063 *pg_list = NULL; 1064 return (isns_no_svr_found); 1065 } 1066 if (isns_server_addr_list->al_out_cnt == 0) { 1067 isns_svr_lst_sz = sizeof (iscsi_addr_list_t); 1068 kmem_free(isns_server_addr_list, isns_svr_lst_sz); 1069 isns_server_addr_list = NULL; 1070 *pg_list = NULL; 1071 return (isns_no_svr_found); 1072 } 1073 1074 /* 1075 * isns_server_addr_list->al_out_cnt should not be zero by the 1076 * time it comes to this point. 1077 */ 1078 tmp_pg_lists_sz = isns_server_addr_list->al_out_cnt * 1079 sizeof (isns_portal_group_list_t *); 1080 tmp_pg_lists = (isns_portal_group_list_t **)kmem_zalloc( 1081 tmp_pg_lists_sz, KM_SLEEP); 1082 combined_num_of_pgs = 0; 1083 combined_qry_stat = isns_ok; 1084 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) { 1085 if (is_query_all_nodes_b) { 1086 qry_stat = do_isns_dev_attr_query_all_nodes( 1087 &isns_server_addr_list->al_addrs[i], 1088 source_node_name, 1089 source_node_alias, 1090 &tmp_pg_list); 1091 } else { 1092 qry_stat = do_isns_dev_attr_query_one_node( 1093 &isns_server_addr_list->al_addrs[i], 1094 target_node_name, 1095 source_node_name, 1096 source_node_alias, 1097 source_node_type, 1098 &tmp_pg_list); 1099 } 1100 1101 /* Record the portal group list retrieved from this server. */ 1102 tmp_pg_lists[i] = tmp_pg_list; 1103 if (tmp_pg_list != NULL) { 1104 combined_num_of_pgs += tmp_pg_list->pg_out_cnt; 1105 } 1106 1107 if (qry_stat == isns_ok) { 1108 if (combined_qry_stat != isns_ok) { 1109 combined_qry_stat = isns_op_partially_failed; 1110 } 1111 } else { 1112 if (combined_qry_stat != isns_op_partially_failed) { 1113 if (combined_qry_stat == isns_ok && i > 0) { 1114 combined_qry_stat = 1115 isns_op_partially_failed; 1116 } else { 1117 combined_qry_stat = qry_stat; 1118 } 1119 } 1120 } 1121 1122 if (is_query_all_nodes_b == B_FALSE) { 1123 if (qry_stat == isns_ok) { 1124 /* 1125 * Break out of the loop if we already got 1126 * the node information for one node. 1127 */ 1128 break; 1129 } 1130 } 1131 } 1132 1133 /* Merge the retrieved portal lists */ 1134 combined_pg_lst_sz = sizeof (isns_portal_group_list_t); 1135 if (combined_num_of_pgs > 0) { 1136 combined_pg_lst_sz += (combined_num_of_pgs - 1) * 1137 sizeof (isns_portal_group_t); 1138 } 1139 combined_pg_list = (isns_portal_group_list_t *)kmem_zalloc( 1140 combined_pg_lst_sz, KM_SLEEP); 1141 1142 combined_pg_list->pg_out_cnt = combined_num_of_pgs; 1143 k = 0; 1144 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) { 1145 if (tmp_pg_lists[i] == NULL) { 1146 continue; 1147 } 1148 for (j = 0; j < tmp_pg_lists[i]->pg_out_cnt; j++) { 1149 pg = &(combined_pg_list->pg_list[k]); 1150 bcopy(&(tmp_pg_lists[i]->pg_list[j]), 1151 pg, sizeof (isns_portal_group_t)); 1152 k++; 1153 } 1154 tmp_pg_list_sz = sizeof (isns_portal_group_list_t); 1155 if (tmp_pg_lists[i]->pg_out_cnt > 0) { 1156 tmp_pg_list_sz += (tmp_pg_lists[i]->pg_out_cnt - 1) * 1157 sizeof (isns_portal_group_t); 1158 } 1159 kmem_free(tmp_pg_lists[i], tmp_pg_list_sz); 1160 tmp_pg_lists[i] = NULL; 1161 } 1162 kmem_free(tmp_pg_lists, tmp_pg_lists_sz); 1163 tmp_pg_lists = NULL; 1164 1165 isns_svr_lst_sz = sizeof (iscsi_addr_list_t); 1166 if (isns_server_addr_list->al_out_cnt > 0) { 1167 isns_svr_lst_sz += (sizeof (iscsi_addr_t) * 1168 (isns_server_addr_list->al_out_cnt - 1)); 1169 } 1170 kmem_free(isns_server_addr_list, isns_svr_lst_sz); 1171 isns_server_addr_list = NULL; 1172 1173 DTRACE_PROBE1(list, isns_portal_group_list_t *, combined_pg_list); 1174 1175 *pg_list = combined_pg_list; 1176 return (combined_qry_stat); 1177 } 1178 1179 static 1180 isns_status_t 1181 do_isns_dev_attr_query_all_nodes(iscsi_addr_t *isns_server_addr, 1182 uint8_t *node_name, 1183 uint8_t *node_alias, 1184 isns_portal_group_list_t **pg_list) 1185 { 1186 int bytes_received; 1187 int rcv_rsp_cnt = 0; 1188 int rsp_status; 1189 uint16_t xid, seq_id = 0, func_id; 1190 isns_pdu_t *in_pdu, *out_pdu; 1191 isns_pdu_mult_payload_t *combined_pdu = NULL, *old_combined_pdu = NULL; 1192 isns_status_t qry_stat; 1193 size_t out_pdu_size = 0, in_pdu_size = 0; 1194 size_t old_combined_pdu_size = 0, combined_pdu_size = 0; 1195 void *so = NULL; 1196 uint8_t *payload_ptr; 1197 1198 /* Initialize */ 1199 *pg_list = NULL; 1200 1201 so = isns_open(isns_server_addr); 1202 if (so == NULL) { 1203 /* Log a message and return */ 1204 return (isns_open_conn_err); 1205 } 1206 1207 /* 1208 * Then, ask for all PG attributes. Filter the non-target nodes. 1209 */ 1210 out_pdu_size = isns_create_dev_attr_qry_target_nodes_pdu( 1211 node_name, node_alias, &xid, &out_pdu); 1212 if (out_pdu_size == 0) { 1213 iscsi_net->close(so); 1214 return (isns_create_msg_err); 1215 } 1216 1217 ASSERT(out_pdu != NULL); 1218 ASSERT(out_pdu_size > 0); 1219 1220 if (isns_send_pdu(so, out_pdu) != 0) { 1221 iscsi_net->close(so); 1222 kmem_free(out_pdu, out_pdu_size); 1223 out_pdu = NULL; 1224 return (isns_send_msg_err); 1225 } 1226 1227 /* Done with the out PDU - free it */ 1228 kmem_free(out_pdu, out_pdu_size); 1229 out_pdu = NULL; 1230 1231 rcv_rsp_cnt = 0; 1232 qry_stat = isns_ok; 1233 for (;;) { 1234 uint16_t flags; 1235 1236 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 1237 ASSERT(bytes_received >= 0); 1238 if (bytes_received == 0) { 1239 ASSERT(in_pdu == NULL); 1240 ASSERT(in_pdu_size == 0); 1241 qry_stat = isns_rcv_msg_err; 1242 break; 1243 } 1244 1245 ASSERT(in_pdu != NULL); 1246 ASSERT(in_pdu_size > 0); 1247 1248 /* 1249 * make sure we are processing the right transaction id 1250 */ 1251 if (ntohs(in_pdu->xid) != xid) { 1252 rcv_rsp_cnt++; 1253 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 1254 kmem_free(in_pdu, in_pdu_size); 1255 in_pdu = NULL; 1256 continue; 1257 } else { 1258 /* Exceed maximum receive count. */ 1259 kmem_free(in_pdu, in_pdu_size); 1260 in_pdu = NULL; 1261 qry_stat = isns_no_rsp_rcvd; 1262 break; 1263 } 1264 } 1265 1266 /* 1267 * check to see if FIRST and LAST PDU flag is set 1268 * if they are both set, then this response only has one 1269 * pdu and we can process the pdu 1270 */ 1271 flags = in_pdu->flags; 1272 if (((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) && 1273 ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU)) { 1274 rsp_status = 1275 isns_process_dev_attr_qry_target_nodes_pdu( 1276 isns_server_addr, 1277 in_pdu->func_id, 1278 (isns_resp_t *)in_pdu->payload, 1279 (size_t)in_pdu->payload_len, 1280 pg_list); 1281 kmem_free(in_pdu, in_pdu_size); 1282 in_pdu = NULL; 1283 break; 1284 } 1285 /* 1286 * this pdu is part of a multi-pdu response. save off the 1287 * the payload of this pdu and continue processing 1288 */ 1289 if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) { 1290 /* This is the first pdu, make sure sequence ID is 0 */ 1291 if (in_pdu->seq != 0) { 1292 cmn_err(CE_NOTE, "isns query response invalid: " 1293 "first pdu is not sequence ID 0"); 1294 kmem_free(in_pdu, in_pdu_size); 1295 in_pdu = NULL; 1296 return (isns_op_failed); 1297 } 1298 seq_id = 0; 1299 1300 /* create new pdu and copy in data from old pdu */ 1301 combined_pdu_size = ISNSP_MULT_PAYLOAD_HEADER_SIZE + 1302 in_pdu->payload_len; 1303 combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc( 1304 combined_pdu_size, KM_SLEEP); 1305 func_id = in_pdu->func_id; 1306 combined_pdu->payload_len = in_pdu->payload_len; 1307 bcopy(in_pdu->payload, combined_pdu->payload, 1308 in_pdu->payload_len); 1309 1310 /* done with in_pdu, free it */ 1311 kmem_free(in_pdu, in_pdu_size); 1312 in_pdu = NULL; 1313 } else { 1314 seq_id++; 1315 if (in_pdu->seq != seq_id) { 1316 cmn_err(CE_NOTE, "isns query response invalid: " 1317 "Missing sequence ID %d from isns query " 1318 "response.", seq_id); 1319 kmem_free(in_pdu, in_pdu_size); 1320 in_pdu = NULL; 1321 if (combined_pdu != NULL) { 1322 kmem_free(combined_pdu, 1323 combined_pdu_size); 1324 combined_pdu = NULL; 1325 } 1326 return (isns_op_failed); 1327 } 1328 /* 1329 * if conbined_pdu_size is still zero, then we never 1330 * processed the first pdu 1331 */ 1332 if (combined_pdu_size == 0) { 1333 cmn_err(CE_NOTE, "isns query response invalid: " 1334 "Did not receive first pdu.\n"); 1335 kmem_free(in_pdu, in_pdu_size); 1336 in_pdu = NULL; 1337 return (isns_op_failed); 1338 } 1339 /* save off the old combined pdu */ 1340 old_combined_pdu_size = combined_pdu_size; 1341 old_combined_pdu = combined_pdu; 1342 1343 /* 1344 * alloc a new pdu big enough to also hold the new 1345 * pdu payload 1346 */ 1347 combined_pdu_size += in_pdu->payload_len; 1348 combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc( 1349 combined_pdu_size, KM_SLEEP); 1350 1351 /* 1352 * copy the old pdu into the new allocated pdu buffer 1353 * and append on the new pdu payload that we just 1354 * received 1355 */ 1356 bcopy(old_combined_pdu, combined_pdu, 1357 old_combined_pdu_size); 1358 1359 payload_ptr = combined_pdu->payload + 1360 combined_pdu->payload_len; 1361 combined_pdu->payload_len += in_pdu->payload_len; 1362 bcopy(in_pdu->payload, payload_ptr, 1363 in_pdu->payload_len); 1364 1365 /* free in_pdu and old_combined_pdu */ 1366 kmem_free(in_pdu, in_pdu_size); 1367 kmem_free(old_combined_pdu, old_combined_pdu_size); 1368 in_pdu = NULL; 1369 old_combined_pdu = NULL; 1370 } 1371 /* 1372 * check to see if this is the LAST pdu. 1373 * if it is, we can process it and move on 1374 * otherwise continue to wait for the next pdu 1375 */ 1376 if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) { 1377 rsp_status = 1378 isns_process_dev_attr_qry_target_nodes_pdu( 1379 isns_server_addr, 1380 func_id, 1381 (isns_resp_t *)combined_pdu->payload, 1382 combined_pdu->payload_len, 1383 pg_list); 1384 kmem_free(combined_pdu, combined_pdu_size); 1385 combined_pdu = NULL; 1386 break; 1387 } 1388 } 1389 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 1390 qry_stat = isns_op_failed; 1391 } 1392 1393 iscsi_net->close(so); 1394 1395 return (qry_stat); 1396 } 1397 1398 /* ARGSUSED */ 1399 static 1400 isns_status_t 1401 do_isns_dev_attr_query_one_node(iscsi_addr_t *isns_server_addr, 1402 uint8_t *target_node_name, 1403 uint8_t *source_node_name, 1404 uint8_t *source_node_alias, 1405 uint32_t source_node_type, 1406 isns_portal_group_list_t **pg_list) 1407 { 1408 int bytes_received; 1409 int rcv_rsp_cnt; 1410 int rsp_status; 1411 isns_pdu_t *in_pdu, *out_pdu; 1412 isns_status_t rval; 1413 size_t out_pdu_size = 0, in_pdu_size = 0; 1414 uint16_t xid; 1415 void *so = NULL; 1416 1417 /* Obtain the list of target type storage nodes first */ 1418 out_pdu_size = isns_create_dev_attr_qry_one_pg_pdu( 1419 target_node_name, source_node_name, &xid, &out_pdu); 1420 if (out_pdu_size == 0) { 1421 return (isns_create_msg_err); 1422 } 1423 1424 ASSERT(out_pdu != NULL); 1425 ASSERT(out_pdu_size > 0); 1426 1427 so = isns_open(isns_server_addr); 1428 if (so == NULL) { 1429 /* Log a message and return */ 1430 kmem_free(out_pdu, out_pdu_size); 1431 out_pdu = NULL; 1432 return (isns_open_conn_err); 1433 } 1434 1435 if (isns_send_pdu(so, out_pdu) != 0) { 1436 iscsi_net->close(so); 1437 kmem_free(out_pdu, out_pdu_size); 1438 out_pdu = NULL; 1439 return (isns_send_msg_err); 1440 } 1441 1442 /* Done with the out PDU - free it */ 1443 kmem_free(out_pdu, out_pdu_size); 1444 out_pdu = NULL; 1445 1446 rcv_rsp_cnt = 0; 1447 rval = isns_ok; 1448 for (;;) { 1449 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size); 1450 ASSERT(bytes_received >= 0); 1451 if (bytes_received == 0) { 1452 ASSERT(in_pdu == NULL); 1453 ASSERT(in_pdu_size == 0); 1454 rval = isns_rcv_msg_err; 1455 break; 1456 } 1457 1458 ASSERT(in_pdu != NULL); 1459 ASSERT(in_pdu_size > 0); 1460 1461 if (ntohs(in_pdu->xid) != xid) { 1462 rcv_rsp_cnt++; 1463 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) { 1464 continue; 1465 } else { 1466 /* Exceed maximum receive count. */ 1467 kmem_free(in_pdu, in_pdu_size); 1468 in_pdu = NULL; 1469 rval = isns_no_rsp_rcvd; 1470 break; 1471 } 1472 } 1473 1474 rsp_status = isns_process_dev_attr_qry_target_nodes_pdu( 1475 isns_server_addr, in_pdu->func_id, 1476 (isns_resp_t *)in_pdu->payload, (size_t)in_pdu->payload_len, 1477 pg_list); 1478 if (rsp_status != ISNS_RSP_SUCCESSFUL) { 1479 rval = isns_op_failed; 1480 } 1481 kmem_free(in_pdu, in_pdu_size); 1482 in_pdu = NULL; 1483 break; 1484 } 1485 1486 iscsi_net->close(so); 1487 1488 return (rval); 1489 } 1490 1491 static 1492 void 1493 *isns_open(iscsi_addr_t *isns_server_addr) 1494 { 1495 int rval = 0; 1496 union { 1497 struct sockaddr sin; 1498 struct sockaddr_in s_in4; 1499 struct sockaddr_in6 s_in6; 1500 } sa_rsvr = { 0 }; 1501 void *so; 1502 struct sockaddr_in6 t_addr; 1503 socklen_t t_addrlen; 1504 1505 bzero(&t_addr, sizeof (struct sockaddr_in6)); 1506 t_addrlen = sizeof (struct sockaddr_in6); 1507 if (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) { 1508 /* IPv4 */ 1509 sa_rsvr.s_in4.sin_family = AF_INET; 1510 sa_rsvr.s_in4.sin_port = htons(isns_server_addr->a_port); 1511 sa_rsvr.s_in4.sin_addr.s_addr = 1512 isns_server_addr->a_addr.i_addr.in4.s_addr; 1513 1514 /* Create socket */ 1515 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0); 1516 } else { 1517 /* IPv6 */ 1518 sa_rsvr.s_in6.sin6_family = AF_INET6; 1519 bcopy(&(isns_server_addr->a_addr.i_addr.in6), 1520 sa_rsvr.s_in6.sin6_addr.s6_addr, 1521 sizeof (struct in6_addr)); 1522 sa_rsvr.s_in6.sin6_port = htons(isns_server_addr->a_port); 1523 /* Create socket */ 1524 so = iscsi_net->socket(AF_INET6, SOCK_STREAM, 0); 1525 } 1526 1527 if (so == NULL) { 1528 return (NULL); 1529 } 1530 1531 rval = iscsi_net->connect(so, &sa_rsvr.sin, 1532 (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) ? 1533 sizeof (struct sockaddr_in) : 1534 sizeof (struct sockaddr_in6), 0, 0); 1535 1536 if (rval != 0) { 1537 /* Flag value 2 indicates both cantsend and cantrecv */ 1538 iscsi_net->shutdown(so, 2); 1539 iscsi_net->close(so); 1540 return (NULL); 1541 } 1542 1543 (void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr, 1544 &t_addrlen); 1545 1546 return (so); 1547 } 1548 1549 static ssize_t 1550 isns_send_pdu(void *socket, isns_pdu_t *pdu) 1551 { 1552 int iovlen = 0; 1553 iovec_t iovec[ISNS_MAX_IOVEC]; 1554 struct msghdr msg; 1555 size_t send_len; 1556 size_t total_len = 0; 1557 1558 ASSERT(iovlen < ISNS_MAX_IOVEC); 1559 iovec[iovlen].iov_base = (void *)pdu; 1560 iovec[iovlen].iov_len = (ISNSP_HEADER_SIZE); 1561 total_len += (ISNSP_HEADER_SIZE); 1562 iovlen++; 1563 1564 ASSERT(iovlen < ISNS_MAX_IOVEC); 1565 iovec[iovlen].iov_base = (void *)pdu->payload; 1566 iovec[iovlen].iov_len = ntohs(pdu->payload_len); 1567 total_len += ntohs(pdu->payload_len); 1568 iovlen++; 1569 1570 /* Initialization of the message header. */ 1571 bzero(&msg, sizeof (msg)); 1572 msg.msg_iov = &iovec[0]; 1573 msg.msg_flags = MSG_WAITALL; 1574 msg.msg_iovlen = iovlen; 1575 1576 send_len = iscsi_net->sendmsg(socket, &msg); 1577 return (send_len == total_len ? 0 : -1); 1578 } 1579 1580 static 1581 size_t 1582 isns_rcv_pdu(void *socket, isns_pdu_t **pdu, size_t *pdu_size) 1583 { 1584 int poll_cnt; 1585 iovec_t iovec[ISNS_MAX_IOVEC]; 1586 isns_pdu_t *tmp_pdu_hdr; 1587 size_t bytes_received, total_bytes_received = 0, payload_len = 0; 1588 struct msghdr msg; 1589 uint8_t *tmp_pdu_data; 1590 1591 /* Receive the header first */ 1592 tmp_pdu_hdr = (isns_pdu_t *)kmem_zalloc(ISNSP_HEADER_SIZE, KM_SLEEP); 1593 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t)); 1594 iovec[0].iov_base = (void *)tmp_pdu_hdr; 1595 iovec[0].iov_len = ISNSP_HEADER_SIZE; 1596 1597 /* Initialization of the message header. */ 1598 bzero(&msg, sizeof (msg)); 1599 msg.msg_iov = &iovec[0]; 1600 msg.msg_flags = MSG_WAITALL; 1601 msg.msg_iovlen = 1; 1602 1603 /* Poll and receive the packets. */ 1604 poll_cnt = 0; 1605 do { 1606 bytes_received = iscsi_net->recvmsg(socket, &msg, 1607 ISNS_RCV_TIMEOUT); 1608 if (bytes_received == 0) { 1609 /* Not yet. Increase poll count and try again. */ 1610 poll_cnt++; 1611 continue; 1612 } else { 1613 /* OK data received. */ 1614 break; 1615 } 1616 } while (poll_cnt < ISNS_RCV_RETRY_MAX); 1617 1618 DTRACE_PROBE2(isns_rcv_pdu_hdr_summary, 1619 int, poll_cnt, int, bytes_received); 1620 if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 1621 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1622 *pdu = NULL; 1623 *pdu_size = 0; 1624 return (0); 1625 } 1626 if (bytes_received == 0 || bytes_received != ISNSP_HEADER_SIZE) { 1627 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1628 *pdu = NULL; 1629 *pdu_size = 0; 1630 return (0); 1631 } 1632 total_bytes_received += bytes_received; 1633 1634 payload_len = ntohs(tmp_pdu_hdr->payload_len); 1635 DTRACE_PROBE1(isns_rcv_pdu_probe1, int, payload_len); 1636 /* Verify the received payload len is within limit */ 1637 if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) { 1638 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1639 *pdu = NULL; 1640 *pdu_size = 0; 1641 return (0); 1642 } 1643 1644 /* Proceed to receive additional data. */ 1645 tmp_pdu_data = kmem_zalloc(payload_len, KM_SLEEP); 1646 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t)); 1647 iovec[0].iov_base = (void *)tmp_pdu_data; 1648 iovec[0].iov_len = payload_len; 1649 1650 /* Initialization of the message header. */ 1651 bzero(&msg, sizeof (msg)); 1652 msg.msg_iov = &iovec[0]; 1653 msg.msg_flags = MSG_WAITALL; 1654 msg.msg_iovlen = 1; 1655 1656 /* Poll and receive the rest of the PDU. */ 1657 poll_cnt = 0; 1658 do { 1659 bytes_received = iscsi_net->recvmsg(socket, &msg, 1660 ISNS_RCV_TIMEOUT); 1661 if (bytes_received == 0) { 1662 /* Not yet. Increase poll count and try again. */ 1663 poll_cnt++; 1664 continue; 1665 } else { 1666 /* OK data received. */ 1667 break; 1668 } 1669 } while (poll_cnt < ISNS_RCV_RETRY_MAX); 1670 1671 DTRACE_PROBE2(isns_rcv_pdu_data_summary, 1672 int, poll_cnt, int, bytes_received); 1673 1674 if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 1675 kmem_free(tmp_pdu_data, payload_len); 1676 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1677 *pdu = NULL; 1678 *pdu_size = 0; 1679 return (0); 1680 } 1681 if (bytes_received == 0 || bytes_received != payload_len) { 1682 kmem_free(tmp_pdu_data, payload_len); 1683 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1684 *pdu = NULL; 1685 *pdu_size = 0; 1686 return (0); 1687 } 1688 total_bytes_received += bytes_received; 1689 1690 *pdu_size = ISNSP_HEADER_SIZE + payload_len; 1691 (*pdu) = (isns_pdu_t *)kmem_zalloc((*pdu_size), KM_SLEEP); 1692 (*pdu)->version = ntohs(tmp_pdu_hdr->version); 1693 (*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id); 1694 (*pdu)->payload_len = payload_len; 1695 (*pdu)->flags = ntohs(tmp_pdu_hdr->flags); 1696 (*pdu)->xid = ntohs(tmp_pdu_hdr->xid); 1697 (*pdu)->seq = ntohs(tmp_pdu_hdr->seq); 1698 bcopy(tmp_pdu_data, &((*pdu)->payload), payload_len); 1699 1700 kmem_free(tmp_pdu_data, payload_len); 1701 tmp_pdu_data = NULL; 1702 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1703 tmp_pdu_hdr = NULL; 1704 1705 return (total_bytes_received); 1706 } 1707 1708 1709 /* 1710 * isns_create_dev_attr_reg_pdu - isns client registration pdu 1711 */ 1712 static size_t 1713 isns_create_dev_attr_reg_pdu( 1714 uint8_t *node_name, 1715 uint8_t *node_alias, 1716 uint32_t node_type, 1717 uint16_t *xid_p, 1718 isns_pdu_t **out_pdu) 1719 { 1720 in_port_t local_port; 1721 isns_pdu_t *pdu; 1722 size_t pdu_size, node_name_len, node_alias_len; 1723 uint16_t flags; 1724 boolean_t rval = B_FALSE; 1725 iscsi_addr_t local_addr; 1726 1727 ASSERT(node_name != NULL); 1728 ASSERT(node_alias != NULL); 1729 1730 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1731 node_name_len = strlen((char *)node_name) + 1; 1732 node_alias_len = strlen((char *)node_alias) + 1; 1733 1734 if (node_name_len == 1) { 1735 *out_pdu = NULL; 1736 return (0); 1737 } 1738 1739 /* 1740 * Create DevAttrReg Message 1741 * 1742 * Enable the replace bit so that we can update 1743 * existing registration 1744 */ 1745 flags = ISNS_FLAG_FIRST_PDU | 1746 ISNS_FLAG_LAST_PDU | 1747 ISNS_FLAG_REPLACE_REG; 1748 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_REG, flags, &pdu); 1749 *xid_p = pdu->xid; 1750 1751 /* Source attribute */ 1752 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1753 node_name_len, node_name, 0) != 0) { 1754 kmem_free(pdu, pdu_size); 1755 *out_pdu = NULL; 1756 return (0); 1757 } 1758 1759 /* 1760 * Message Key Attributes 1761 * 1762 * EID attribute - Section 6.2.1 1763 * This is required for re-registrations or Replace 1764 * Bit is ignored - Section 5.6.5.1 1765 */ 1766 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1767 node_name_len, node_name, 0) != 0) { 1768 kmem_free(pdu, pdu_size); 1769 *out_pdu = NULL; 1770 return (0); 1771 } 1772 1773 /* Delimiter */ 1774 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 1775 != 0) { 1776 kmem_free(pdu, pdu_size); 1777 *out_pdu = NULL; 1778 return (0); 1779 } 1780 1781 /* EID attribute - Section 6.2.1 */ 1782 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1783 node_name_len, node_name, 0) != 0) { 1784 kmem_free(pdu, pdu_size); 1785 *out_pdu = NULL; 1786 return (0); 1787 } 1788 1789 /* ENTITY Protocol - Section 6.2.2 */ 1790 if (isns_add_attr(pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID, 4, 1791 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { 1792 kmem_free(pdu, pdu_size); 1793 *out_pdu = NULL; 1794 return (0); 1795 } 1796 1797 /* iSCSI Name - Section 6.4.1 */ 1798 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1799 node_name_len, node_name, 0) != 0) { 1800 kmem_free(pdu, pdu_size); 1801 *out_pdu = NULL; 1802 return (0); 1803 } 1804 1805 /* iSCSI Alias - Section 6.4.3 Optional */ 1806 if (node_alias_len > 1) { 1807 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_ALIAS_ATTR_ID, 1808 node_alias_len, node_alias, 0) != 0) { 1809 kmem_free(pdu, pdu_size); 1810 *out_pdu = NULL; 1811 return (0); 1812 } 1813 } 1814 1815 /* iSCSI Node Type - Section 6.4.2 */ 1816 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 1817 0, node_type) != 0) { 1818 kmem_free(pdu, pdu_size); 1819 *out_pdu = NULL; 1820 return (0); 1821 } 1822 1823 mutex_enter(&esi_scn_thr_mutex); 1824 if (instance_listening_so != NULL) { 1825 rval = find_listening_addr(&local_addr, instance_listening_so); 1826 if (rval == B_FALSE) { 1827 kmem_free(pdu, pdu_size); 1828 *out_pdu = NULL; 1829 mutex_exit(&esi_scn_thr_mutex); 1830 return (0); 1831 } 1832 } else { 1833 kmem_free(pdu, pdu_size); 1834 *out_pdu = NULL; 1835 mutex_exit(&esi_scn_thr_mutex); 1836 return (0); 1837 } 1838 local_port = local_addr.a_port; 1839 /* Portal IP Address - Section 6.5.2 */ 1840 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_IP_ADDR_ATTR_ID, 16, 1841 &(local_addr.a_addr.i_addr.in4), 1842 local_addr.a_addr.i_insize) != 0) { 1843 kmem_free(pdu, pdu_size); 1844 *out_pdu = NULL; 1845 mutex_exit(&esi_scn_thr_mutex); 1846 return (0); 1847 } 1848 mutex_exit(&esi_scn_thr_mutex); 1849 1850 /* Portal Port - Section 6.5.3 */ 1851 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_PORT_ATTR_ID, 4, 0, 1852 local_port) != 0) { 1853 kmem_free(pdu, pdu_size); 1854 *out_pdu = NULL; 1855 return (0); 1856 } 1857 1858 /* SCN Port - Section 6.3.7 */ 1859 if (isns_add_attr(pdu, pdu_size, ISNS_SCN_PORT_ATTR_ID, 4, 0, 1860 local_port) != 0) { 1861 kmem_free(pdu, pdu_size); 1862 *out_pdu = NULL; 1863 return (0); 1864 } 1865 1866 /* ESI Port - Section 6.3.5 */ 1867 if (isns_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 0, 1868 local_port) != 0) { 1869 kmem_free(pdu, pdu_size); 1870 *out_pdu = NULL; 1871 return (0); 1872 } 1873 1874 *out_pdu = pdu; 1875 return (pdu_size); 1876 } 1877 1878 /* 1879 * isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration. 1880 */ 1881 static size_t 1882 isns_create_dev_dereg_pdu( 1883 uint8_t *node_name, 1884 uint16_t *xid_p, 1885 isns_pdu_t **out_pdu) 1886 { 1887 isns_pdu_t *pdu; 1888 size_t pdu_size, node_name_len; 1889 uint16_t flags; 1890 1891 ASSERT(node_name != NULL); 1892 1893 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1894 node_name_len = strlen((char *)node_name) + 1; 1895 1896 if (node_name_len == 1) { 1897 *out_pdu = NULL; 1898 return (0); 1899 } 1900 1901 /* 1902 * Create DevDeReg Message 1903 */ 1904 flags = ISNS_FLAG_FIRST_PDU | 1905 ISNS_FLAG_LAST_PDU; 1906 pdu_size = isns_create_pdu_header(ISNS_DEV_DEREG, flags, &pdu); 1907 *xid_p = pdu->xid; 1908 1909 /* Source attribute */ 1910 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1911 node_name_len, node_name, 0) != 0) { 1912 kmem_free(pdu, pdu_size); 1913 *out_pdu = NULL; 1914 return (0); 1915 } 1916 1917 /* Delimiter */ 1918 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 1919 != 0) { 1920 kmem_free(pdu, pdu_size); 1921 *out_pdu = NULL; 1922 return (0); 1923 } 1924 1925 /* Entity Identifier */ 1926 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1927 node_name_len, node_name, 0) != 0) { 1928 kmem_free(pdu, pdu_size); 1929 *out_pdu = NULL; 1930 return (0); 1931 } 1932 1933 *out_pdu = pdu; 1934 return (pdu_size); 1935 } 1936 1937 /* 1938 * isns_create_dev_attr_target_nodes_pdu - get all accessible targets 1939 * 1940 * Querys for a list of all accessible target nodes for this 1941 * initiator. Requests all required login information (name, 1942 * ip, port, tpgt). 1943 */ 1944 static size_t 1945 isns_create_dev_attr_qry_target_nodes_pdu( 1946 uint8_t *node_name, 1947 uint8_t *node_alias, 1948 uint16_t *xid_p, isns_pdu_t **out_pdu) 1949 { 1950 isns_pdu_t *pdu_p; 1951 uint16_t flags; 1952 size_t pdu_size, node_name_len; 1953 1954 ASSERT(node_name != NULL); 1955 ASSERT(node_alias != NULL); 1956 1957 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1958 node_name_len = strlen((char *)node_name) + 1; 1959 1960 if (node_name_len == 1) { 1961 *out_pdu = NULL; 1962 return (0); 1963 } 1964 1965 /* Create DevAttrQry Message */ 1966 flags = ISNS_FLAG_FIRST_PDU | 1967 ISNS_FLAG_LAST_PDU; 1968 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p); 1969 *xid_p = pdu_p->xid; 1970 1971 /* Source attribute */ 1972 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1973 node_name_len, node_name, 0) != 0) { 1974 kmem_free(pdu_p, pdu_size); 1975 *out_pdu = NULL; 1976 return (0); 1977 } 1978 1979 /* 1980 * Message Key Attribute 1981 * 1982 * iSCSI Node Type 1983 * Query target nodes only 1984 */ 1985 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 1986 4, 0, ISNS_TARGET_NODE_TYPE) != 0) { 1987 kmem_free(pdu_p, pdu_size); 1988 *out_pdu = NULL; 1989 return (0); 1990 } 1991 1992 /* Delimiter */ 1993 if (isns_add_attr(pdu_p, pdu_size, 1994 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) { 1995 kmem_free(pdu_p, pdu_size); 1996 *out_pdu = NULL; 1997 return (0); 1998 } 1999 2000 /* PG iSCSI Name - Zero length TLV */ 2001 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID, 2002 0, 0, 0) != 0) { 2003 kmem_free(pdu_p, pdu_size); 2004 *out_pdu = NULL; 2005 return (0); 2006 } 2007 2008 /* PG Portal IP Address - Zero length TLV */ 2009 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 2010 0, 0, 0) != 0) { 2011 kmem_free(pdu_p, pdu_size); 2012 *out_pdu = NULL; 2013 return (0); 2014 } 2015 2016 /* PG Portal Port - Zero length TLV */ 2017 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID, 2018 0, 0, 0) != 0) { 2019 kmem_free(pdu_p, pdu_size); 2020 *out_pdu = NULL; 2021 return (0); 2022 } 2023 2024 /* PG Portal Group Tag - Zero length TLV */ 2025 if (isns_add_attr(pdu_p, pdu_size, 2026 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) { 2027 kmem_free(pdu_p, pdu_size); 2028 *out_pdu = NULL; 2029 return (0); 2030 } 2031 2032 *out_pdu = pdu_p; 2033 return (pdu_size); 2034 } 2035 2036 static 2037 size_t 2038 isns_create_dev_attr_qry_one_pg_pdu( 2039 uint8_t *target_node_name, 2040 uint8_t *source_node_name, 2041 uint16_t *xid_p, 2042 isns_pdu_t **out_pdu) 2043 { 2044 isns_pdu_t *pdu_p; 2045 uint16_t flags; 2046 size_t pdu_size, source_node_name_len, target_node_name_len; 2047 2048 ASSERT(target_node_name != NULL); 2049 ASSERT(source_node_name != NULL); 2050 2051 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2052 source_node_name_len = strlen((char *)source_node_name) + 1; 2053 target_node_name_len = strlen((char *)target_node_name) + 1; 2054 2055 if (source_node_name_len == 1) { 2056 *out_pdu = NULL; 2057 return (0); 2058 } 2059 2060 /* Create DevAttrQry message scoped to target_node_name */ 2061 flags = ISNS_FLAG_FIRST_PDU | 2062 ISNS_FLAG_LAST_PDU; 2063 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p); 2064 *xid_p = pdu_p->xid; 2065 2066 /* Source attribute */ 2067 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2068 source_node_name_len, source_node_name, 0) != 0) { 2069 kmem_free(pdu_p, pdu_size); 2070 *out_pdu = NULL; 2071 return (0); 2072 } 2073 2074 /* Message key attribute */ 2075 /* iSCSI Node Name */ 2076 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2077 target_node_name_len, 2078 target_node_name, 0) != 0) { 2079 kmem_free(pdu_p, pdu_size); 2080 *out_pdu = NULL; 2081 return (0); 2082 } 2083 2084 /* Delimiter */ 2085 if (isns_add_attr(pdu_p, pdu_size, 2086 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) { 2087 kmem_free(pdu_p, pdu_size); 2088 *out_pdu = NULL; 2089 return (0); 2090 } 2091 2092 /* PG iSCSI Name - Zero length TLV */ 2093 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID, 2094 0, 0, 0) != 0) { 2095 kmem_free(pdu_p, pdu_size); 2096 *out_pdu = NULL; 2097 return (0); 2098 } 2099 2100 /* PG Portal IP Address - Zero length TLV */ 2101 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 2102 0, 0, 0) != 0) { 2103 kmem_free(pdu_p, pdu_size); 2104 *out_pdu = NULL; 2105 return (0); 2106 } 2107 2108 /* PG Portal Port - Zero length TLV */ 2109 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID, 2110 0, 0, 0) != 0) { 2111 kmem_free(pdu_p, pdu_size); 2112 *out_pdu = NULL; 2113 return (0); 2114 } 2115 2116 /* PG Portal Group Tag - Zero length TLV */ 2117 if (isns_add_attr(pdu_p, pdu_size, 2118 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) { 2119 kmem_free(pdu_p, pdu_size); 2120 *out_pdu = NULL; 2121 return (0); 2122 } 2123 2124 *out_pdu = pdu_p; 2125 return (pdu_size); 2126 } 2127 2128 static 2129 size_t 2130 isns_create_scn_reg_pdu( 2131 uint8_t *node_name, 2132 uint8_t *node_alias, 2133 uint16_t *xid_p, 2134 isns_pdu_t **out_pdu) 2135 { 2136 isns_pdu_t *pdu; 2137 size_t pdu_size, node_name_len; 2138 uint16_t flags; 2139 2140 ASSERT(node_name != NULL); 2141 ASSERT(node_alias != NULL); 2142 2143 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2144 node_name_len = strlen((char *)node_name) + 1; 2145 2146 if (node_name_len == 1) { 2147 *out_pdu = NULL; 2148 return (0); 2149 } 2150 2151 /* Create SCNReg Message */ 2152 flags = ISNS_FLAG_FIRST_PDU | 2153 ISNS_FLAG_LAST_PDU; 2154 pdu_size = isns_create_pdu_header(ISNS_SCN_REG, flags, &pdu); 2155 *xid_p = pdu->xid; 2156 2157 /* Source attribute */ 2158 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2159 node_name_len, node_name, 0) != 0) { 2160 kmem_free(pdu, pdu_size); 2161 *out_pdu = NULL; 2162 return (0); 2163 } 2164 2165 /* Message attribute */ 2166 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2167 node_name_len, node_name, 0) != 0) { 2168 kmem_free(pdu, pdu_size); 2169 *out_pdu = NULL; 2170 return (0); 2171 } 2172 2173 /* Delimiter */ 2174 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2175 != 0) { 2176 kmem_free(pdu, pdu_size); 2177 *out_pdu = NULL; 2178 return (0); 2179 } 2180 2181 /* Operating attribute */ 2182 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_SCN_BITMAP_ATTR_ID, 2183 4, 2184 0, 2185 /* 2186 * Microsoft seems to not differentiate between init and 2187 * target. Hence, it makes no difference to turn on/off 2188 * the initiator/target bit. 2189 */ 2190 ISNS_TARGET_SELF_INFO_ONLY | 2191 ISNS_OBJ_REMOVED | 2192 ISNS_OBJ_ADDED | 2193 ISNS_OBJ_UPDATED) != 0) { 2194 kmem_free(pdu, pdu_size); 2195 *out_pdu = NULL; 2196 return (0); 2197 } 2198 2199 *out_pdu = pdu; 2200 return (pdu_size); 2201 } 2202 2203 static 2204 size_t 2205 isns_create_scn_dereg_pdu( 2206 uint8_t *node_name, 2207 uint16_t *xid_p, 2208 isns_pdu_t **out_pdu) 2209 { 2210 isns_pdu_t *pdu; 2211 size_t pdu_size, node_name_len; 2212 uint16_t flags; 2213 2214 ASSERT(node_name != NULL); 2215 2216 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2217 node_name_len = strlen((char *)node_name) + 1; 2218 2219 if (node_name_len == 1) { 2220 *out_pdu = NULL; 2221 return (0); 2222 } 2223 2224 /* Create SCNReg Message */ 2225 flags = ISNS_FLAG_FIRST_PDU | 2226 ISNS_FLAG_LAST_PDU; 2227 pdu_size = isns_create_pdu_header(ISNS_SCN_DEREG, flags, &pdu); 2228 *xid_p = pdu->xid; 2229 2230 /* Source attribute */ 2231 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2232 node_name_len, node_name, 0) != 0) { 2233 kmem_free(pdu, pdu_size); 2234 *out_pdu = NULL; 2235 return (0); 2236 } 2237 2238 /* Message attribute */ 2239 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2240 node_name_len, node_name, 0) != 0) { 2241 kmem_free(pdu, pdu_size); 2242 *out_pdu = NULL; 2243 return (0); 2244 } 2245 2246 /* Delimiter */ 2247 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2248 != 0) { 2249 kmem_free(pdu, pdu_size); 2250 *out_pdu = NULL; 2251 return (0); 2252 } 2253 2254 /* No operating attribute */ 2255 2256 *out_pdu = pdu; 2257 return (pdu_size); 2258 } 2259 2260 static 2261 size_t 2262 isns_create_esi_rsp_pdu(uint32_t rsp_status_code, 2263 isns_pdu_t *esi_pdu, 2264 uint16_t *xid_p, 2265 isns_pdu_t **out_pdu) 2266 { 2267 isns_pdu_t *pdu_p; 2268 uint16_t flags; 2269 uint8_t *payload_ptr; 2270 uint32_t swapped_status_code = htonl(rsp_status_code); 2271 size_t pdu_size, payload_len = 0; 2272 2273 /* Create ESIRsp Message */ 2274 flags = ISNS_FLAG_FIRST_PDU | 2275 ISNS_FLAG_LAST_PDU; 2276 pdu_size = isns_create_pdu_header(ISNS_ESI_RSP, flags, &pdu_p); 2277 *xid_p = pdu_p->xid; 2278 2279 payload_len = ntohs(pdu_p->payload_len); 2280 2281 /* Status Code */ 2282 payload_ptr = pdu_p->payload + payload_len; 2283 bcopy(&swapped_status_code, payload_ptr, 4); 2284 payload_len += 4; 2285 2286 payload_ptr = pdu_p->payload + payload_len; 2287 if ((esi_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) { 2288 bcopy(esi_pdu->payload, payload_ptr, 2289 (esi_pdu->payload_len)); 2290 payload_len += (esi_pdu->payload_len); 2291 } else { 2292 bcopy(esi_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE); 2293 payload_len += ISNSP_MAX_PAYLOAD_SIZE; 2294 } 2295 pdu_p->payload_len = htons(payload_len); 2296 2297 /* Delimiter */ 2298 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2299 != 0) { 2300 kmem_free(pdu_p, pdu_size); 2301 *out_pdu = NULL; 2302 return (0); 2303 } 2304 2305 *out_pdu = pdu_p; 2306 return (pdu_size); 2307 } 2308 2309 static 2310 size_t 2311 isns_create_scn_rsp_pdu(uint32_t rsp_status_code, 2312 isns_pdu_t *scn_pdu, 2313 uint16_t *xid_p, 2314 isns_pdu_t **out_pdu) 2315 { 2316 isns_pdu_t *pdu_p; 2317 uint16_t flags; 2318 uint8_t *payload_ptr; 2319 uint32_t swapped_status_code = htonl(rsp_status_code); 2320 size_t pdu_size, payload_len = 0; 2321 2322 /* Create SCNRsp Message */ 2323 flags = ISNS_FLAG_FIRST_PDU | 2324 ISNS_FLAG_LAST_PDU; 2325 pdu_size = isns_create_pdu_header(ISNS_SCN_RSP, flags, &pdu_p); 2326 *xid_p = pdu_p->xid; 2327 2328 payload_len = ntohs(pdu_p->payload_len); 2329 2330 /* Status Code */ 2331 payload_ptr = pdu_p->payload + payload_len; 2332 bcopy(&swapped_status_code, payload_ptr, 4); 2333 payload_len += 4; 2334 2335 payload_ptr = pdu_p->payload + payload_len; 2336 if ((scn_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) { 2337 bcopy(scn_pdu->payload, payload_ptr, 2338 (scn_pdu->payload_len)); 2339 payload_len += (scn_pdu->payload_len); 2340 } else { 2341 bcopy(scn_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE); 2342 payload_len += ISNSP_MAX_PAYLOAD_SIZE; 2343 } 2344 pdu_p->payload_len = htons(payload_len); 2345 2346 /* Delimiter */ 2347 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2348 != 0) { 2349 kmem_free(pdu_p, pdu_size); 2350 *out_pdu = NULL; 2351 return (0); 2352 } 2353 2354 *out_pdu = pdu_p; 2355 return (pdu_size); 2356 } 2357 2358 static 2359 uint32_t 2360 isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p) 2361 { 2362 isns_resp_t *resp_p; 2363 2364 if (resp_pdu_p->func_id != ISNS_DEV_ATTR_REG_RSP) { 2365 /* If this happens the iSNS server may have a problem. */ 2366 return (ISNS_RSP_MSG_FORMAT_ERROR); 2367 } 2368 2369 /* Check response's status code */ 2370 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2371 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2372 return (ntohl(resp_p->status)); 2373 } 2374 2375 return (ISNS_RSP_SUCCESSFUL); 2376 } 2377 2378 static 2379 uint32_t 2380 isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p) 2381 { 2382 isns_resp_t *resp_p; 2383 2384 if (resp_pdu_p->func_id != ISNS_DEV_DEREG_RSP) { 2385 /* If this happens the iSNS server may have a problem. */ 2386 return (ISNS_RSP_MSG_FORMAT_ERROR); 2387 } 2388 2389 /* Check response's status code */ 2390 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2391 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2392 return (ntohl(resp_p->status)); 2393 } 2394 2395 return (ISNS_RSP_SUCCESSFUL); 2396 } 2397 2398 static 2399 uint32_t 2400 isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p) 2401 { 2402 isns_resp_t *resp_p; 2403 2404 ASSERT(resp_pdu_p != NULL); 2405 if (resp_pdu_p->func_id != ISNS_SCN_REG_RSP) { 2406 /* If this happens the iSNS server may have a problem. */ 2407 return (ISNS_RSP_MSG_FORMAT_ERROR); 2408 } 2409 2410 /* Check response's status code */ 2411 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2412 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2413 return (ntohl(resp_p->status)); 2414 } 2415 return (ISNS_RSP_SUCCESSFUL); 2416 } 2417 2418 static 2419 uint32_t 2420 isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p) 2421 { 2422 isns_resp_t *resp_p; 2423 2424 ASSERT(resp_pdu_p != NULL); 2425 if (resp_pdu_p->func_id != ISNS_SCN_DEREG_RSP) { 2426 /* If this happens the iSNS server may have a problem. */ 2427 return (ISNS_RSP_MSG_FORMAT_ERROR); 2428 } 2429 2430 /* Check response's status code */ 2431 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2432 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2433 return (ntohl(resp_p->status)); 2434 } 2435 return (ISNS_RSP_SUCCESSFUL); 2436 } 2437 2438 static 2439 uint32_t 2440 isns_process_dev_attr_qry_target_nodes_pdu( 2441 iscsi_addr_t *isns_server_addr, uint16_t payload_funcId, 2442 isns_resp_t *resp_p, size_t resp_len, 2443 isns_portal_group_list_t **pg_list) 2444 { 2445 boolean_t done_b, found_delimiter_b, target_node_type_b; 2446 int num_of_pgs = 0, pg_sz, idx; 2447 isns_tlv_t *attr_tlv_p; 2448 uint8_t *data_p; 2449 uint32_t len, total_payload_len = 0; 2450 isns_portal_group_t *pg; 2451 uint8_t junk[IPV4_RSVD_BYTES]; 2452 2453 *pg_list = NULL; 2454 bzero(junk, IPV4_RSVD_BYTES); 2455 2456 if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) { 2457 /* If this happens the iSNS server may have a problem. */ 2458 return (ISNS_RSP_MSG_FORMAT_ERROR); 2459 } 2460 2461 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2462 return (ntohl(resp_p->status)); 2463 } 2464 2465 /* 2466 * If payload is smaller than the length of even 1 attribute 2467 * there is something wrong with the PDU. 2468 */ 2469 if (resp_len < (ISNS_TLV_ATTR_ID_LEN + 2470 ISNS_TLV_ATTR_LEN_LEN)) { 2471 return (ISNS_RSP_MSG_FORMAT_ERROR); 2472 } 2473 2474 /* 2475 * Expected DevAttrQryRsp message format: 2476 * 2477 * Status Code 2478 * iSCSI Node Type 2479 * Delimiter 2480 * PG iSCSI Name [Optional] 2481 * PG Portal IP Address [Optional] 2482 * PG Portal Port [Optional] 2483 * PG Tag [Optional] 2484 * PG iSCSI Name [Optional] 2485 * PG Portal IP Address [Optional] 2486 * PG Portal Port [Optional] 2487 * PG Tag [Optional] 2488 * . 2489 * . 2490 * . 2491 */ 2492 data_p = resp_p->data; 2493 done_b = B_FALSE; 2494 found_delimiter_b = B_FALSE; 2495 num_of_pgs = 0; 2496 total_payload_len = sizeof (resp_p->status); 2497 /* Find out the number of entries retrieved */ 2498 while (!done_b) { 2499 attr_tlv_p = (isns_tlv_t *)data_p; 2500 if (ntohl(attr_tlv_p->attr_id) == ISNS_DELIMITER_ATTR_ID) { 2501 if (found_delimiter_b) { 2502 done_b = B_TRUE; 2503 } else { 2504 found_delimiter_b = B_TRUE; 2505 } 2506 } else if (ntohl(attr_tlv_p->attr_id) == 2507 ISNS_PG_TAG_ATTR_ID) { 2508 if (ntohl(attr_tlv_p->attr_len) > 0) { 2509 /* 2510 * Count only those iSCSI node that have a 2511 * non-NULL PGT value as valid Entity. 2512 * Per rfc4171 section 3.4 - If the PGT value 2513 * registered for a specified Portal and iSCSI 2514 * Node is NULL, or if no PGT value is 2515 * registered, then the Portal does not provide 2516 * access to that iSCSI Node in the Entity. 2517 */ 2518 num_of_pgs++; 2519 } 2520 } 2521 len = ntohl(attr_tlv_p->attr_len); 2522 2523 total_payload_len += (ISNS_TLV_ATTR_ID_LEN + 2524 ISNS_TLV_ATTR_LEN_LEN + len); 2525 if (total_payload_len >= resp_len) { 2526 done_b = B_TRUE; 2527 } else { 2528 data_p += (ISNS_TLV_ATTR_ID_LEN + 2529 ISNS_TLV_ATTR_LEN_LEN + len); 2530 } 2531 } 2532 2533 pg_sz = sizeof (isns_portal_group_list_t); 2534 if (num_of_pgs > 0) { 2535 pg_sz += (num_of_pgs - 1) * sizeof (isns_portal_group_t); 2536 } 2537 DTRACE_PROBE1(isns_process_dev_attr_qry_target_nodes_pdu_pg_size, 2538 int, pg_sz); 2539 /* 2540 * Once we passed this point, if for any reason we need to return 2541 * because of a failure, we need to free the memory allocated for 2542 * the pg_list and nullify it. 2543 */ 2544 *pg_list = (isns_portal_group_list_t *)kmem_zalloc(pg_sz, KM_SLEEP); 2545 (*pg_list)->pg_out_cnt = 0; 2546 2547 /* Assign the isns_server information to all portal groups */ 2548 for (idx = 0; idx < num_of_pgs; idx++) { 2549 pg = &((*pg_list)->pg_list[idx]); 2550 bcopy(&isns_server_addr->a_addr, &pg->isns_server_ip, 2551 sizeof (iscsi_ipaddr_t)); 2552 pg->isns_server_port = isns_server_addr->a_port; 2553 } 2554 2555 data_p = resp_p->data; 2556 done_b = B_FALSE; 2557 found_delimiter_b = B_FALSE; 2558 total_payload_len = sizeof (resp_p->status); 2559 while (!done_b) { 2560 attr_tlv_p = (isns_tlv_t *)data_p; 2561 pg = &((*pg_list)->pg_list[(*pg_list)->pg_out_cnt]); 2562 switch (ntohl(attr_tlv_p->attr_id)) { 2563 case ISNS_DELIMITER_ATTR_ID: 2564 if (found_delimiter_b) { 2565 done_b = B_TRUE; 2566 } else { 2567 found_delimiter_b = B_TRUE; 2568 } 2569 break; 2570 2571 case ISNS_PG_ISCSI_NAME_ATTR_ID: 2572 target_node_type_b = B_TRUE; 2573 bcopy(attr_tlv_p->attr_value, 2574 (char *)pg->pg_iscsi_name, 2575 ntohl(attr_tlv_p->attr_len) < 2576 ISCSI_MAX_NAME_LEN ? 2577 ntohl(attr_tlv_p->attr_len) : 2578 ISCSI_MAX_NAME_LEN); 2579 2580 DTRACE_PROBE1(isns_dev_attr_qry_process1, 2581 char *, (char *)pg->pg_iscsi_name); 2582 break; 2583 2584 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 2585 if (target_node_type_b) { 2586 /* 2587 * Section 6.3.1 - The Portal IP Address 2588 * is a 16-byte field that may contain 2589 * an IPv4 or IPv6 address. When this 2590 * field contains an IPv4 address, it 2591 * is stored as an IPv4-mapped IPv6 2592 * address 2593 */ 2594 if (ntohl(attr_tlv_p->attr_len) != 16) { 2595 #define STRING_AALR "address attribute length received " 2596 #define STRING_FISE16 "from iSNS server, Expected = 16, " 2597 cmn_err(CE_NOTE, "Wrong IP " 2598 STRING_AALR 2599 STRING_FISE16 2600 "Received = %d", 2601 ntohl( 2602 attr_tlv_p->attr_len)); 2603 return ( 2604 ISNS_RSP_MSG_FORMAT_ERROR); 2605 #undef STRING_AALR 2606 #undef STRING_FISE16 2607 } 2608 2609 /* 2610 * Section 6.3.1 and RFC 2373 state 2611 * that an IPv4 address will be denoted 2612 * by the 10 top bytes as all zero 2613 * followed by either 2 bytes of 2614 * 0x0000 or 0xFFFF The 0x0000 states 2615 * that the address is is IPv6 capable 2616 * and 0xFFFF states its not capable. 2617 */ 2618 if ((bcmp(attr_tlv_p->attr_value, junk, 2619 IPV4_RSVD_BYTES) == 0) && 2620 (((attr_tlv_p->attr_value[10] == 2621 0x00) && 2622 (attr_tlv_p->attr_value[11] == 2623 0x00)) || 2624 ((attr_tlv_p->attr_value[10] == 2625 0xFF) && 2626 (attr_tlv_p->attr_value[11] == 2627 0xFF)))) { 2628 2629 /* IPv4 */ 2630 bcopy(attr_tlv_p->attr_value + 2631 12, &pg->pg_ip_addr.u_ip4, 2632 sizeof (struct in_addr)); 2633 pg->insize = 2634 sizeof (struct in_addr); 2635 } else { 2636 /* IPv6 */ 2637 bcopy(attr_tlv_p->attr_value, 2638 &pg->pg_ip_addr.u_ip6, 2639 sizeof (struct in6_addr)); 2640 pg->insize = 2641 sizeof (struct in6_addr); 2642 } 2643 } 2644 break; 2645 2646 case ISNS_PG_PORTAL_PORT_ATTR_ID: 2647 if (target_node_type_b) { 2648 pg->pg_port = 2649 ntohl(*(uint32_t *) 2650 (*attr_tlv_p). 2651 attr_value); 2652 } 2653 2654 break; 2655 2656 case ISNS_PG_TAG_ATTR_ID: 2657 if (target_node_type_b) { 2658 pg->pg_tag = 2659 ntohl(*(uint32_t *) 2660 (*attr_tlv_p). 2661 attr_value); 2662 } 2663 target_node_type_b = B_FALSE; 2664 if (ntohl(attr_tlv_p->attr_len) > 0) { 2665 /* 2666 * Only the iSCSI node that has a 2667 * non-NULL PGT value is an valid 2668 * Entity. 2669 */ 2670 (*pg_list)->pg_out_cnt++; 2671 } 2672 break; 2673 2674 default: 2675 break; 2676 } 2677 2678 len = ntohl(attr_tlv_p->attr_len); 2679 total_payload_len += (ISNS_TLV_ATTR_ID_LEN + 2680 ISNS_TLV_ATTR_LEN_LEN + len); 2681 if ((total_payload_len >= resp_len) || 2682 ((*pg_list)->pg_out_cnt == num_of_pgs)) { 2683 done_b = B_TRUE; 2684 } else { 2685 data_p += (ISNS_TLV_ATTR_ID_LEN + 2686 ISNS_TLV_ATTR_LEN_LEN + len); 2687 } 2688 } 2689 2690 return (ISNS_RSP_SUCCESSFUL); 2691 } 2692 2693 /* ARGSUSED */ 2694 static 2695 uint32_t 2696 isns_process_esi(isns_pdu_t *esi_pdu_p) 2697 { 2698 /* There's nothing particular to process for ESI. */ 2699 return (ISNS_RSP_SUCCESSFUL); 2700 } 2701 2702 static 2703 uint32_t 2704 isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle) 2705 { 2706 boolean_t dest_attr_found_b; 2707 boolean_t done_b; 2708 boolean_t scn_type_found_b; 2709 isns_scn_callback_arg_t *scn_args_p; 2710 isns_tlv_t *attr_tlv_p; 2711 uint8_t *data_p; 2712 uint8_t *src_attr; 2713 uint32_t attr_eff_len, normalized_attr_len; 2714 uint32_t scn_type; 2715 uint32_t total_payload_len; 2716 void (*scn_callback_to_use)(void *); 2717 2718 /* get the lhba_handle to use for the call back */ 2719 scn_callback_to_use = scn_callback_lookup(lhba_handle); 2720 if (scn_callback_to_use == NULL) { 2721 return (ISNS_RSP_INTERNAL_ERROR); 2722 } 2723 2724 dest_attr_found_b = B_FALSE; 2725 scn_type = 0; 2726 scn_type_found_b = B_FALSE; 2727 data_p = scn_pdu_p->payload; 2728 done_b = B_FALSE; 2729 total_payload_len = 0; 2730 src_attr = (uint8_t *)kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 2731 /* 2732 * Section 5.6.5.8 states an SCN can have more than one 2733 * source attribute. Process all attributes until we 2734 * each process all the data or encounter the delimiter. 2735 */ 2736 while (!done_b) { 2737 attr_tlv_p = (isns_tlv_t *)data_p; 2738 2739 switch (ntohl(attr_tlv_p->attr_id)) { 2740 /* ISNS_ISCSI_NAME_ATTR_ID - attribute name */ 2741 case ISNS_ISCSI_NAME_ATTR_ID: 2742 attr_eff_len = strlen( 2743 (char *)attr_tlv_p->attr_value) + 1; 2744 /* 2745 * The attribute length must be 4-byte aligned. 2746 * Section 5.1.3, RFC 4171. 2747 */ 2748 normalized_attr_len = (attr_eff_len % 4) == 0 ? 2749 (attr_eff_len) : 2750 (attr_eff_len + (4 - (attr_eff_len % 4))); 2751 if (normalized_attr_len != 2752 ntohl(attr_tlv_p->attr_len)) { 2753 /* This SCN is bad. */ 2754 kmem_free(src_attr, ISCSI_MAX_NAME_LEN); 2755 return (ISNS_RSP_MSG_FORMAT_ERROR); 2756 } 2757 2758 /* Check if this was the Destination Attribute */ 2759 if ((dest_attr_found_b == B_TRUE) && 2760 (scn_type_found_b == B_TRUE)) { 2761 bzero(src_attr, ISCSI_MAX_NAME_LEN); 2762 bcopy(attr_tlv_p->attr_value, 2763 (char *)src_attr, 2764 ntohl(attr_tlv_p->attr_len) < 2765 ISCSI_MAX_NAME_LEN ? 2766 ntohl(attr_tlv_p->attr_len) : 2767 ISCSI_MAX_NAME_LEN); 2768 2769 /* allocate new callback structure */ 2770 scn_args_p = 2771 (isns_scn_callback_arg_t *)kmem_zalloc( 2772 sizeof (isns_scn_callback_arg_t), 2773 KM_SLEEP); 2774 scn_args_p->scn_type = ntohl(scn_type); 2775 bcopy(src_attr, scn_args_p->source_key_attr, 2776 sizeof (scn_args_p->source_key_attr)); 2777 2778 /* Dispatch the callback to process the SCN */ 2779 mutex_enter(&scn_taskq_mutex); 2780 if (scn_taskq != NULL) { 2781 (void) ddi_taskq_dispatch(scn_taskq, 2782 scn_callback_to_use, 2783 scn_args_p, DDI_SLEEP); 2784 } 2785 mutex_exit(&scn_taskq_mutex); 2786 } else { 2787 /* Skip Destination Attribute */ 2788 dest_attr_found_b = B_TRUE; 2789 } 2790 break; 2791 2792 /* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */ 2793 case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: 2794 /* 2795 * Determine the type of action to take for this SCN. 2796 */ 2797 scn_type_found_b = B_TRUE; 2798 bcopy(&(attr_tlv_p->attr_value), &scn_type, 4); 2799 break; 2800 2801 /* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */ 2802 case ISNS_DELIMITER_ATTR_ID: 2803 done_b = B_TRUE; 2804 break; 2805 } 2806 2807 if (done_b == B_FALSE) { 2808 total_payload_len += ntohl(attr_tlv_p->attr_len) + 2809 ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN; 2810 if ((total_payload_len >= scn_pdu_p->payload_len) || 2811 (total_payload_len > ISNSP_MAX_PAYLOAD_SIZE)) { 2812 /* No more Attributes to process */ 2813 done_b = B_TRUE; 2814 } else { 2815 if (scn_pdu_p->payload_len - 2816 total_payload_len <= 2817 ISNS_TLV_ATTR_ID_LEN + 2818 ISNS_TLV_ATTR_LEN_LEN) { 2819 /* 2820 * The rest of the data in the PDU 2821 * is less than the size of a valid 2822 * iSNS TLV. This next attribute 2823 * probably spans across the PDU 2824 * boundary. For now, do not 2825 * process it further. 2826 */ 2827 done_b = B_TRUE; 2828 } else { 2829 /* Advance to the next Attribute */ 2830 data_p += (ISNS_TLV_ATTR_ID_LEN + 2831 ISNS_TLV_ATTR_LEN_LEN + 2832 ntohl(attr_tlv_p->attr_len)); 2833 } 2834 } 2835 } 2836 } 2837 2838 kmem_free(src_attr, ISCSI_MAX_NAME_LEN); 2839 return (ISNS_RSP_SUCCESSFUL); 2840 } 2841 2842 static 2843 size_t 2844 isns_create_pdu_header(uint16_t func_id, uint16_t flags, isns_pdu_t **pdu) 2845 { 2846 /* 2847 * It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough 2848 * since we are creating our own PDU which is fully under our control. 2849 */ 2850 size_t pdu_size = ISNSP_MAX_PDU_SIZE; 2851 2852 *pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_SLEEP); 2853 (void) memset((*pdu), 0, pdu_size); 2854 (*pdu)->version = htons((uint16_t)ISNSP_VERSION); 2855 (*pdu)->func_id = htons((uint16_t)func_id); 2856 (*pdu)->payload_len = htons(0); 2857 (*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT)); 2858 (*pdu)->xid = htons(create_xid()); 2859 (*pdu)->seq = htons(0); 2860 2861 return (pdu_size); 2862 } 2863 2864 static 2865 int 2866 isns_add_attr(isns_pdu_t *pdu, 2867 size_t max_pdu_size, 2868 uint32_t attr_id, 2869 uint32_t attr_len, 2870 void *attr_data, 2871 uint32_t attr_numeric_data) 2872 { 2873 isns_tlv_t *attr_tlv; 2874 uint8_t *payload_ptr; 2875 uint16_t payload_len; 2876 uint32_t normalized_attr_len; 2877 uint64_t attr_tlv_len; 2878 2879 /* The attribute length must be 4-byte aligned. Section 5.1.3. */ 2880 normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) : 2881 (attr_len + (4 - (attr_len % 4))); 2882 attr_tlv_len = ISNS_TLV_ATTR_ID_LEN 2883 + ISNS_TLV_ATTR_LEN_LEN 2884 + normalized_attr_len; 2885 /* Check if we are going to exceed the maximum PDU length. */ 2886 payload_len = ntohs(pdu->payload_len); 2887 if ((payload_len + attr_tlv_len) > max_pdu_size) { 2888 return (1); 2889 } 2890 2891 attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP); 2892 2893 attr_tlv->attr_id = htonl(attr_id); 2894 2895 switch (attr_id) { 2896 case ISNS_DELIMITER_ATTR_ID: 2897 break; 2898 2899 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 2900 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 2901 if (attr_numeric_data == sizeof (in_addr_t)) { 2902 /* IPv4 */ 2903 attr_tlv->attr_value[10] = 0xFF; 2904 attr_tlv->attr_value[11] = 0xFF; 2905 bcopy(attr_data, ((attr_tlv->attr_value) + 12), 2906 sizeof (in_addr_t)); 2907 } else if (attr_numeric_data == sizeof (in6_addr_t)) { 2908 /* IPv6 */ 2909 bcopy(attr_data, attr_tlv->attr_value, 2910 sizeof (in6_addr_t)); 2911 } else if (attr_numeric_data == 0) { 2912 /* EMPTY */ 2913 /* Do nothing */ 2914 } else { 2915 kmem_free(attr_tlv, attr_tlv_len); 2916 attr_tlv = NULL; 2917 return (1); 2918 } 2919 break; 2920 2921 case ISNS_EID_ATTR_ID: 2922 case ISNS_ISCSI_NAME_ATTR_ID: 2923 case ISNS_ISCSI_ALIAS_ATTR_ID: 2924 case ISNS_PG_ISCSI_NAME_ATTR_ID: 2925 bcopy((char *)attr_data, 2926 attr_tlv->attr_value, 2927 attr_len); 2928 break; 2929 2930 default: 2931 switch (normalized_attr_len) { 2932 case 0: 2933 break; 2934 2935 case 4: 2936 *(uint32_t *)attr_tlv->attr_value = 2937 htonl(attr_numeric_data); 2938 break; 2939 2940 case 8: 2941 *(uint64_t *)attr_tlv->attr_value = 2942 BE_64((uint64_t) 2943 attr_numeric_data); 2944 break; 2945 } 2946 } 2947 2948 attr_tlv->attr_len = htonl(normalized_attr_len); 2949 /* 2950 * Convert the network byte ordered payload length to host byte 2951 * ordered for local address calculation. 2952 */ 2953 payload_len = ntohs(pdu->payload_len); 2954 payload_ptr = pdu->payload + payload_len; 2955 bcopy(attr_tlv, payload_ptr, attr_tlv_len); 2956 payload_len += attr_tlv_len; 2957 2958 /* 2959 * Convert the host byte ordered payload length back to network 2960 * byte ordered - it's now ready to be sent on the wire. 2961 */ 2962 pdu->payload_len = htons(payload_len); 2963 2964 kmem_free(attr_tlv, attr_tlv_len); 2965 attr_tlv = NULL; 2966 2967 return (0); 2968 } 2969 2970 /* ARGSUSED */ 2971 static 2972 void 2973 isns_service_esi_scn(iscsi_thread_t *thread, void *arg) 2974 { 2975 int clnt_len; 2976 isns_async_thread_arg_t *larg; 2977 isns_pdu_t *in_pdu; 2978 size_t bytes_received, in_pdu_size = 0; 2979 uint8_t *lhba_handle; 2980 struct sockaddr_in6 t_addr; 2981 socklen_t t_addrlen; 2982 union { 2983 struct sockaddr sin; 2984 struct sockaddr_in s_in4; 2985 struct sockaddr_in6 s_in6; 2986 } clnt_addr = { 0 }; 2987 union { 2988 struct sockaddr_in soa4; 2989 struct sockaddr_in6 soa6; 2990 } local_conn_prop; 2991 void *listening_so, *connecting_so; 2992 2993 larg = (isns_async_thread_arg_t *)arg; 2994 listening_so = larg->listening_so; 2995 lhba_handle = larg->lhba_handle; 2996 2997 /* Done using the argument - free it */ 2998 kmem_free(larg, sizeof (*larg)); 2999 bzero(&t_addr, sizeof (struct sockaddr_in6)); 3000 t_addrlen = sizeof (struct sockaddr_in6); 3001 3002 (void) iscsi_net->getsockname(listening_so, 3003 (struct sockaddr *)&t_addr, &t_addrlen); 3004 if (t_addrlen <= sizeof (local_conn_prop)) { 3005 bcopy(&t_addr, &local_conn_prop, t_addrlen); 3006 } 3007 3008 if (iscsi_net->listen(listening_so, 5) < 0) { 3009 iscsi_net->close(listening_so); 3010 } 3011 3012 for (;;) { 3013 int rval; 3014 isns_pdu_t *out_pdu; 3015 size_t out_pdu_size; 3016 3017 clnt_len = sizeof (clnt_addr); 3018 3019 /* Blocking call */ 3020 connecting_so = iscsi_net->accept( 3021 listening_so, &clnt_addr.sin, &clnt_len); 3022 3023 mutex_enter(&esi_scn_thr_mutex); 3024 if (esi_scn_thr_to_shutdown == B_TRUE) { 3025 /* Terminate the thread if instructed to do so. */ 3026 mutex_exit(&esi_scn_thr_mutex); 3027 return; 3028 } 3029 mutex_exit(&esi_scn_thr_mutex); 3030 3031 if (connecting_so == NULL) { 3032 iscsi_net->close(listening_so); 3033 continue; 3034 } 3035 3036 bytes_received = isns_rcv_pdu(connecting_so, &in_pdu, 3037 &in_pdu_size); 3038 if (in_pdu == NULL) { 3039 continue; 3040 } 3041 if (bytes_received == 0) { 3042 continue; 3043 } 3044 3045 switch (in_pdu->func_id) { 3046 case ISNS_ESI: 3047 case ISNS_SCN: 3048 if (in_pdu->func_id == ISNS_ESI) { 3049 rval = isns_process_esi(in_pdu); 3050 out_pdu_size = isns_create_esi_rsp_pdu( 3051 rval, 3052 in_pdu, 3053 &xid, 3054 &out_pdu); 3055 } else if (in_pdu->func_id == ISNS_SCN) { 3056 rval = isns_process_scn(in_pdu, 3057 lhba_handle); 3058 out_pdu_size = isns_create_scn_rsp_pdu( 3059 rval, 3060 in_pdu, 3061 &xid, 3062 &out_pdu); 3063 } else { 3064 /* 3065 * Ignore all traffics other than 3066 * ESI and SCN. 3067 */ 3068 kmem_free(in_pdu, in_pdu_size); 3069 in_pdu = NULL; 3070 continue; 3071 } 3072 3073 if (out_pdu_size == 0) { 3074 kmem_free(in_pdu, in_pdu_size); 3075 in_pdu = NULL; 3076 continue; 3077 } 3078 3079 (void) isns_send_pdu(connecting_so, out_pdu); 3080 3081 kmem_free(out_pdu, out_pdu_size); 3082 out_pdu = NULL; 3083 kmem_free(in_pdu, in_pdu_size); 3084 in_pdu = NULL; 3085 3086 iscsi_net->close(connecting_so); 3087 break; 3088 3089 default: 3090 kmem_free(in_pdu, in_pdu_size); 3091 in_pdu = NULL; 3092 continue; 3093 } 3094 } 3095 } 3096 3097 static 3098 boolean_t 3099 find_listening_addr(iscsi_addr_t *local_addr, void *listening_so) 3100 { 3101 union { 3102 struct sockaddr_in soa4; 3103 struct sockaddr_in6 soa6; 3104 } local_conn_prop = { 0 }; 3105 3106 struct sockaddr_in6 t_addr; 3107 socklen_t t_addrlen; 3108 3109 if (local_addr == NULL || listening_so == NULL) { 3110 return (B_FALSE); 3111 } 3112 3113 bzero(&t_addr, sizeof (struct sockaddr_in6)); 3114 t_addrlen = sizeof (struct sockaddr_in6); 3115 3116 (void) iscsi_net->getsockname(listening_so, (struct sockaddr *)&t_addr, 3117 &t_addrlen); 3118 if (t_addrlen > sizeof (local_conn_prop)) { 3119 return (B_FALSE); 3120 } 3121 bcopy(&t_addr, &local_conn_prop, t_addrlen); 3122 if (local_conn_prop.soa4.sin_family == AF_INET) { 3123 local_addr->a_addr.i_addr.in4.s_addr = 3124 local_conn_prop.soa4.sin_addr.s_addr; 3125 local_addr->a_addr.i_insize = sizeof (in_addr_t); 3126 } else if (local_conn_prop.soa4.sin_family == AF_INET6) { 3127 /* Currently, IPv6 is not supported */ 3128 return (B_FALSE); 3129 } else { 3130 return (B_FALSE); 3131 } 3132 3133 local_addr->a_port = ntohs(local_conn_prop.soa4.sin_port); 3134 3135 return (B_TRUE); 3136 } 3137 3138 static 3139 boolean_t 3140 find_local_portal(iscsi_addr_t *isns_server_addr, 3141 iscsi_addr_t **local_addr, void **listening_so) 3142 { 3143 union { 3144 struct sockaddr_in soa4; 3145 struct sockaddr_in6 soa6; 3146 } local_conn_prop = { 0 }; 3147 union { 3148 struct sockaddr sin; 3149 struct sockaddr_in s_in4; 3150 struct sockaddr_in6 s_in6; 3151 } serv_addr = { 0 }; 3152 void *so; 3153 struct sockaddr_in6 t_addr; 3154 socklen_t t_addrlen; 3155 3156 if (listening_so == NULL) { 3157 return (B_FALSE); 3158 } 3159 3160 if (local_addr != NULL) { 3161 *local_addr = NULL; 3162 } 3163 3164 *listening_so = NULL; 3165 bzero(&t_addr, sizeof (struct sockaddr_in6)); 3166 t_addrlen = sizeof (struct sockaddr_in6); 3167 3168 /* 3169 * Determine the local IP address. 3170 */ 3171 if (local_addr != NULL) { 3172 so = isns_open(isns_server_addr); 3173 if (so == NULL) { 3174 return (B_FALSE); 3175 } 3176 3177 iscsi_net->getsockname(so, 3178 (struct sockaddr *)&t_addr, &t_addrlen); 3179 if (t_addrlen > sizeof (local_conn_prop)) { 3180 iscsi_net->close(so); 3181 return (B_FALSE); 3182 } 3183 3184 bcopy(&t_addr, &local_conn_prop, t_addrlen); 3185 t_addrlen = sizeof (struct sockaddr_in6); 3186 if (local_conn_prop.soa4.sin_family == AF_INET) { 3187 *local_addr = 3188 (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), 3189 KM_SLEEP); 3190 (*local_addr)->a_addr.i_addr.in4.s_addr = 3191 local_conn_prop.soa4.sin_addr.s_addr; 3192 (*local_addr)->a_addr.i_insize = sizeof (in_addr_t); 3193 } else if (local_conn_prop.soa4.sin_family == AF_INET6) { 3194 /* Currently, IPv6 is not supported */ 3195 return (B_FALSE); 3196 } else { 3197 iscsi_net->close(so); 3198 return (B_FALSE); 3199 } 3200 3201 iscsi_net->close(so); 3202 } 3203 /* 3204 * Determine the local IP address. (End) 3205 */ 3206 3207 serv_addr.s_in4.sin_family = AF_INET; 3208 /* 3209 * Use INADDR_ANY to accept connections from any of the connected 3210 * networks. 3211 */ 3212 serv_addr.s_in4.sin_addr.s_addr = htonl(INADDR_ANY); 3213 /* 3214 * Use port number 0 to allow the system to assign a unique unused 3215 * port. 3216 */ 3217 serv_addr.s_in4.sin_port = htons(0); 3218 3219 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0); 3220 if (so == NULL) { 3221 if (local_addr != NULL && (*local_addr != NULL)) { 3222 kmem_free((*local_addr), sizeof (iscsi_addr_t)); 3223 *local_addr = NULL; 3224 } 3225 return (B_FALSE); 3226 } 3227 3228 if (iscsi_net->bind(so, &serv_addr.sin, 3229 sizeof (struct sockaddr), 0, 0) < 0) { 3230 if (local_addr != NULL && (*local_addr != NULL)) { 3231 kmem_free((*local_addr), sizeof (iscsi_addr_t)); 3232 *local_addr = NULL; 3233 } 3234 iscsi_net->close(so); 3235 return (B_FALSE); 3236 } 3237 3238 if (local_addr != NULL && (*local_addr != NULL)) { 3239 (void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr, 3240 &t_addrlen); 3241 if (t_addrlen <= sizeof (local_conn_prop)) { 3242 bcopy(&t_addr, &local_conn_prop, t_addrlen); 3243 (*local_addr)->a_port = 3244 ntohs(local_conn_prop.soa4.sin_port); 3245 } else { 3246 (*local_addr)->a_port = ISNS_DEFAULT_ESI_SCN_PORT; 3247 } 3248 } 3249 3250 *listening_so = so; 3251 3252 return (B_TRUE); 3253 } 3254 3255 /* ARGSUSED */ 3256 static 3257 void 3258 (*scn_callback_lookup(uint8_t *lhba_handle))(void *) 3259 { 3260 /* 3261 * When we support multiple HBA instance we will use lhba_handle 3262 * to look up the associated SCN callback. For now, we only support 3263 * one HBA instance therefore we always return the same SCN callback. 3264 */ 3265 return (scn_callback_p); 3266 } 3267 3268 static 3269 uint16_t 3270 create_xid() 3271 { 3272 return (xid++ % MAX_XID); 3273 } 3274 3275 static 3276 void 3277 esi_scn_thr_cleanup() 3278 { 3279 boolean_t unblock_esi_scn_thr_b = B_FALSE; 3280 iscsi_addr_t local_addr; 3281 3282 mutex_enter(&esi_scn_thr_mutex); 3283 if (esi_scn_thr_to_shutdown == B_FALSE) { 3284 3285 /* Instruct the ESI/SCN to shut itself down. */ 3286 esi_scn_thr_to_shutdown = B_TRUE; 3287 if (instance_listening_so != NULL && 3288 (find_listening_addr(&local_addr, 3289 instance_listening_so) == B_TRUE)) { 3290 isns_pdu_t *out_pdu; 3291 size_t out_pdu_size; 3292 void *connecting_so; 3293 3294 /* 3295 * Open a connection to the local address and send 3296 * a dummy header to unblock the accept call so that 3297 * the ESI/SCN thread has a chance to terminate 3298 * itself. 3299 */ 3300 connecting_so = isns_open(&local_addr); 3301 if (connecting_so == NULL) { 3302 unblock_esi_scn_thr_b = B_FALSE; 3303 esi_scn_thr_to_shutdown = B_FALSE; 3304 } else { 3305 out_pdu_size = isns_create_pdu_header(0, 3306 ISNS_FLAG_FIRST_PDU | 3307 ISNS_FLAG_LAST_PDU, 3308 &out_pdu); 3309 if (isns_send_pdu(connecting_so, 3310 out_pdu) != 0) { 3311 unblock_esi_scn_thr_b = B_FALSE; 3312 esi_scn_thr_to_shutdown = B_FALSE; 3313 } else { 3314 unblock_esi_scn_thr_b = B_TRUE; 3315 } 3316 iscsi_net->close(connecting_so); 3317 kmem_free(out_pdu, out_pdu_size); 3318 out_pdu = NULL; 3319 } 3320 } 3321 3322 if (unblock_esi_scn_thr_b == B_TRUE) { 3323 mutex_exit(&esi_scn_thr_mutex); 3324 (void) iscsi_thread_stop(esi_scn_thr_id); 3325 iscsi_thread_destroy(esi_scn_thr_id); 3326 mutex_enter(&esi_scn_thr_mutex); 3327 esi_scn_thr_id = NULL; 3328 3329 /* 3330 * Shutdown and close the listening socket. 3331 */ 3332 iscsi_net->shutdown(instance_listening_so, 2); 3333 iscsi_net->close(instance_listening_so); 3334 instance_listening_so = NULL; 3335 } 3336 } 3337 mutex_exit(&esi_scn_thr_mutex); 3338 } 3339