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