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 2008 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 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 1522 if (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) { 1523 /* IPv4 */ 1524 sa_rsvr.s_in4.sin_family = AF_INET; 1525 sa_rsvr.s_in4.sin_port = htons(isns_server_addr->a_port); 1526 sa_rsvr.s_in4.sin_addr.s_addr = 1527 isns_server_addr->a_addr.i_addr.in4.s_addr; 1528 1529 /* Create socket */ 1530 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0); 1531 } else { 1532 /* IPv6 */ 1533 sa_rsvr.s_in6.sin6_family = AF_INET6; 1534 bcopy(&(isns_server_addr->a_addr.i_addr.in6), 1535 sa_rsvr.s_in6.sin6_addr.s6_addr, 1536 sizeof (struct in6_addr)); 1537 sa_rsvr.s_in6.sin6_port = htons(isns_server_addr->a_port); 1538 /* Create socket */ 1539 so = iscsi_net->socket(AF_INET6, SOCK_STREAM, 0); 1540 } 1541 1542 if (so == NULL) { 1543 return (NULL); 1544 } 1545 1546 rval = iscsi_net->connect(so, &sa_rsvr.sin, 1547 (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) ? 1548 sizeof (struct sockaddr_in) : 1549 sizeof (struct sockaddr_in6), 0, 0); 1550 1551 if (rval != 0) { 1552 /* Flag value 2 indicates both cantsend and cantrecv */ 1553 iscsi_net->shutdown(so, 2); 1554 iscsi_net->close(so); 1555 return (NULL); 1556 } 1557 1558 (void) iscsi_net->getsockname(so); 1559 1560 return (so); 1561 } 1562 1563 static ssize_t 1564 isns_send_pdu(void *socket, isns_pdu_t *pdu) 1565 { 1566 int iovlen = 0; 1567 iovec_t iovec[ISNS_MAX_IOVEC]; 1568 struct msghdr msg; 1569 size_t send_len; 1570 size_t total_len = 0; 1571 1572 ASSERT(iovlen < ISNS_MAX_IOVEC); 1573 iovec[iovlen].iov_base = (void *)pdu; 1574 iovec[iovlen].iov_len = (ISNSP_HEADER_SIZE); 1575 total_len += (ISNSP_HEADER_SIZE); 1576 iovlen++; 1577 1578 ASSERT(iovlen < ISNS_MAX_IOVEC); 1579 iovec[iovlen].iov_base = (void *)pdu->payload; 1580 iovec[iovlen].iov_len = ntohs(pdu->payload_len); 1581 total_len += ntohs(pdu->payload_len); 1582 iovlen++; 1583 1584 /* Initialization of the message header. */ 1585 bzero(&msg, sizeof (msg)); 1586 msg.msg_iov = &iovec[0]; 1587 msg.msg_flags = MSG_WAITALL; 1588 msg.msg_iovlen = iovlen; 1589 1590 send_len = iscsi_net->sendmsg(socket, &msg); 1591 return (send_len == total_len ? 0 : -1); 1592 } 1593 1594 static 1595 size_t 1596 isns_rcv_pdu(void *socket, isns_pdu_t **pdu, size_t *pdu_size) 1597 { 1598 int poll_cnt; 1599 iovec_t iovec[ISNS_MAX_IOVEC]; 1600 isns_pdu_t *tmp_pdu_hdr; 1601 size_t bytes_received, total_bytes_received = 0, payload_len = 0; 1602 struct msghdr msg; 1603 uint8_t *tmp_pdu_data; 1604 1605 /* Receive the header first */ 1606 tmp_pdu_hdr = (isns_pdu_t *)kmem_zalloc(ISNSP_HEADER_SIZE, KM_SLEEP); 1607 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t)); 1608 iovec[0].iov_base = (void *)tmp_pdu_hdr; 1609 iovec[0].iov_len = ISNSP_HEADER_SIZE; 1610 1611 /* Initialization of the message header. */ 1612 bzero(&msg, sizeof (msg)); 1613 msg.msg_iov = &iovec[0]; 1614 msg.msg_flags = MSG_WAITALL; 1615 msg.msg_iovlen = 1; 1616 1617 /* Poll and receive the packets. */ 1618 poll_cnt = 0; 1619 do { 1620 bytes_received = iscsi_net->recvmsg(socket, &msg, 1621 ISNS_RCV_TIMEOUT); 1622 if (bytes_received == 0) { 1623 /* Not yet. Increase poll count and try again. */ 1624 poll_cnt++; 1625 continue; 1626 } else { 1627 /* OK data received. */ 1628 break; 1629 } 1630 } while (poll_cnt < ISNS_RCV_RETRY_MAX); 1631 1632 DTRACE_PROBE2(isns_rcv_pdu_hdr_summary, 1633 int, poll_cnt, int, bytes_received); 1634 if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 1635 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1636 *pdu = NULL; 1637 *pdu_size = 0; 1638 return (0); 1639 } 1640 if (bytes_received == 0 || bytes_received != ISNSP_HEADER_SIZE) { 1641 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1642 *pdu = NULL; 1643 *pdu_size = 0; 1644 return (0); 1645 } 1646 total_bytes_received += bytes_received; 1647 1648 payload_len = ntohs(tmp_pdu_hdr->payload_len); 1649 DTRACE_PROBE1(isns_rcv_pdu_probe1, int, payload_len); 1650 /* Verify the received payload len is within limit */ 1651 if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) { 1652 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1653 *pdu = NULL; 1654 *pdu_size = 0; 1655 return (0); 1656 } 1657 1658 /* Proceed to receive additional data. */ 1659 tmp_pdu_data = kmem_zalloc(payload_len, KM_SLEEP); 1660 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t)); 1661 iovec[0].iov_base = (void *)tmp_pdu_data; 1662 iovec[0].iov_len = payload_len; 1663 1664 /* Initialization of the message header. */ 1665 bzero(&msg, sizeof (msg)); 1666 msg.msg_iov = &iovec[0]; 1667 msg.msg_flags = MSG_WAITALL; 1668 msg.msg_iovlen = 1; 1669 1670 /* Poll and receive the rest of the PDU. */ 1671 poll_cnt = 0; 1672 do { 1673 bytes_received = iscsi_net->recvmsg(socket, &msg, 1674 ISNS_RCV_TIMEOUT); 1675 if (bytes_received == 0) { 1676 /* Not yet. Increase poll count and try again. */ 1677 poll_cnt++; 1678 continue; 1679 } else { 1680 /* OK data received. */ 1681 break; 1682 } 1683 } while (poll_cnt < ISNS_RCV_RETRY_MAX); 1684 1685 DTRACE_PROBE2(isns_rcv_pdu_data_summary, 1686 int, poll_cnt, int, bytes_received); 1687 1688 if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 1689 kmem_free(tmp_pdu_data, payload_len); 1690 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1691 *pdu = NULL; 1692 *pdu_size = 0; 1693 return (0); 1694 } 1695 if (bytes_received == 0 || bytes_received != payload_len) { 1696 kmem_free(tmp_pdu_data, payload_len); 1697 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1698 *pdu = NULL; 1699 *pdu_size = 0; 1700 return (0); 1701 } 1702 total_bytes_received += bytes_received; 1703 1704 *pdu_size = ISNSP_HEADER_SIZE + payload_len; 1705 (*pdu) = (isns_pdu_t *)kmem_zalloc((*pdu_size), KM_SLEEP); 1706 (*pdu)->version = ntohs(tmp_pdu_hdr->version); 1707 (*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id); 1708 (*pdu)->payload_len = payload_len; 1709 (*pdu)->flags = ntohs(tmp_pdu_hdr->flags); 1710 (*pdu)->xid = ntohs(tmp_pdu_hdr->xid); 1711 (*pdu)->seq = ntohs(tmp_pdu_hdr->seq); 1712 bcopy(tmp_pdu_data, &((*pdu)->payload), payload_len); 1713 1714 kmem_free(tmp_pdu_data, payload_len); 1715 tmp_pdu_data = NULL; 1716 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE); 1717 tmp_pdu_hdr = NULL; 1718 1719 return (total_bytes_received); 1720 } 1721 1722 1723 /* 1724 * isns_create_dev_attr_reg_pdu - isns client registration pdu 1725 */ 1726 static size_t 1727 isns_create_dev_attr_reg_pdu( 1728 uint8_t *node_name, 1729 uint8_t *node_alias, 1730 uint32_t node_type, 1731 uint16_t *xid_p, 1732 isns_pdu_t **out_pdu) 1733 { 1734 in_port_t local_port; 1735 isns_pdu_t *pdu; 1736 size_t pdu_size, node_name_len, node_alias_len; 1737 uint16_t flags; 1738 1739 ASSERT(node_name != NULL); 1740 ASSERT(node_alias != NULL); 1741 ASSERT(local_addr != NULL); 1742 1743 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1744 node_name_len = strlen((char *)node_name) + 1; 1745 node_alias_len = strlen((char *)node_alias) + 1; 1746 1747 if (node_name_len == 1) { 1748 *out_pdu = NULL; 1749 return (0); 1750 } 1751 1752 /* 1753 * Create DevAttrReg Message 1754 * 1755 * Enable the replace bit so that we can update 1756 * existing registration 1757 */ 1758 flags = ISNS_FLAG_FIRST_PDU | 1759 ISNS_FLAG_LAST_PDU | 1760 ISNS_FLAG_REPLACE_REG; 1761 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_REG, flags, &pdu); 1762 *xid_p = pdu->xid; 1763 1764 /* Source attribute */ 1765 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1766 node_name_len, node_name, 0) != 0) { 1767 kmem_free(pdu, pdu_size); 1768 *out_pdu = NULL; 1769 return (0); 1770 } 1771 1772 /* 1773 * Message Key Attributes 1774 * 1775 * EID attribute - Section 6.2.1 1776 * This is required for re-registrations or Replace 1777 * Bit is ignored - Section 5.6.5.1 1778 */ 1779 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1780 node_name_len, node_name, 0) != 0) { 1781 kmem_free(pdu, pdu_size); 1782 *out_pdu = NULL; 1783 return (0); 1784 } 1785 1786 /* Delimiter */ 1787 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 1788 != 0) { 1789 kmem_free(pdu, pdu_size); 1790 *out_pdu = NULL; 1791 return (0); 1792 } 1793 1794 /* EID attribute - Section 6.2.1 */ 1795 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1796 node_name_len, node_name, 0) != 0) { 1797 kmem_free(pdu, pdu_size); 1798 *out_pdu = NULL; 1799 return (0); 1800 } 1801 1802 /* ENTITY Protocol - Section 6.2.2 */ 1803 if (isns_add_attr(pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID, 4, 1804 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { 1805 kmem_free(pdu, pdu_size); 1806 *out_pdu = NULL; 1807 return (0); 1808 } 1809 1810 /* iSCSI Name - Section 6.4.1 */ 1811 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1812 node_name_len, node_name, 0) != 0) { 1813 kmem_free(pdu, pdu_size); 1814 *out_pdu = NULL; 1815 return (0); 1816 } 1817 1818 /* iSCSI Alias - Section 6.4.3 Optional */ 1819 if (node_alias_len > 1) { 1820 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_ALIAS_ATTR_ID, 1821 node_alias_len, node_alias, 0) != 0) { 1822 kmem_free(pdu, pdu_size); 1823 *out_pdu = NULL; 1824 return (0); 1825 } 1826 } 1827 1828 /* iSCSI Node Type - Section 6.4.2 */ 1829 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 1830 0, node_type) != 0) { 1831 kmem_free(pdu, pdu_size); 1832 *out_pdu = NULL; 1833 return (0); 1834 } 1835 1836 mutex_enter(&esi_scn_thr_mutex); 1837 local_port = local_addr->a_port; 1838 mutex_exit(&esi_scn_thr_mutex); 1839 1840 mutex_enter(&esi_scn_thr_mutex); 1841 /* Portal IP Address - Section 6.5.2 */ 1842 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_IP_ADDR_ATTR_ID, 16, 1843 &(local_addr->a_addr.i_addr.in4), 1844 local_addr->a_addr.i_insize) != 0) { 1845 kmem_free(pdu, pdu_size); 1846 *out_pdu = NULL; 1847 mutex_exit(&esi_scn_thr_mutex); 1848 return (0); 1849 } 1850 mutex_exit(&esi_scn_thr_mutex); 1851 1852 /* Portal Port - Section 6.5.3 */ 1853 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_PORT_ATTR_ID, 4, 0, 1854 local_port) != 0) { 1855 kmem_free(pdu, pdu_size); 1856 *out_pdu = NULL; 1857 return (0); 1858 } 1859 1860 /* SCN Port - Section 6.3.7 */ 1861 if (isns_add_attr(pdu, pdu_size, ISNS_SCN_PORT_ATTR_ID, 4, 0, 1862 local_port) != 0) { 1863 kmem_free(pdu, pdu_size); 1864 *out_pdu = NULL; 1865 return (0); 1866 } 1867 1868 /* ESI Port - Section 6.3.5 */ 1869 if (isns_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 0, 1870 local_port) != 0) { 1871 kmem_free(pdu, pdu_size); 1872 *out_pdu = NULL; 1873 return (0); 1874 } 1875 1876 *out_pdu = pdu; 1877 return (pdu_size); 1878 } 1879 1880 /* 1881 * isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration. 1882 */ 1883 static size_t 1884 isns_create_dev_dereg_pdu( 1885 uint8_t *node_name, 1886 uint16_t *xid_p, 1887 isns_pdu_t **out_pdu) 1888 { 1889 isns_pdu_t *pdu; 1890 size_t pdu_size, node_name_len; 1891 uint16_t flags; 1892 1893 ASSERT(node_name != NULL); 1894 1895 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1896 node_name_len = strlen((char *)node_name) + 1; 1897 1898 if (node_name_len == 1) { 1899 *out_pdu = NULL; 1900 return (0); 1901 } 1902 1903 /* 1904 * Create DevDeReg Message 1905 */ 1906 flags = ISNS_FLAG_FIRST_PDU | 1907 ISNS_FLAG_LAST_PDU; 1908 pdu_size = isns_create_pdu_header(ISNS_DEV_DEREG, flags, &pdu); 1909 *xid_p = pdu->xid; 1910 1911 /* Source attribute */ 1912 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1913 node_name_len, node_name, 0) != 0) { 1914 kmem_free(pdu, pdu_size); 1915 *out_pdu = NULL; 1916 return (0); 1917 } 1918 1919 /* Delimiter */ 1920 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 1921 != 0) { 1922 kmem_free(pdu, pdu_size); 1923 *out_pdu = NULL; 1924 return (0); 1925 } 1926 1927 /* Entity Identifier */ 1928 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID, 1929 node_name_len, node_name, 0) != 0) { 1930 kmem_free(pdu, pdu_size); 1931 *out_pdu = NULL; 1932 return (0); 1933 } 1934 1935 *out_pdu = pdu; 1936 return (pdu_size); 1937 } 1938 1939 /* 1940 * isns_create_dev_attr_target_nodes_pdu - get all accessible targets 1941 * 1942 * Querys for a list of all accessible target nodes for this 1943 * initiator. Requests all required login information (name, 1944 * ip, port, tpgt). 1945 */ 1946 static size_t 1947 isns_create_dev_attr_qry_target_nodes_pdu( 1948 uint8_t *node_name, 1949 uint8_t *node_alias, 1950 uint16_t *xid_p, isns_pdu_t **out_pdu) 1951 { 1952 isns_pdu_t *pdu_p; 1953 uint16_t flags; 1954 size_t pdu_size, node_name_len; 1955 1956 ASSERT(node_name != NULL); 1957 ASSERT(node_alias != NULL); 1958 1959 /* RFC 4171 section 6.1 - NULLs included in the length. */ 1960 node_name_len = strlen((char *)node_name) + 1; 1961 1962 if (node_name_len == 1) { 1963 *out_pdu = NULL; 1964 return (0); 1965 } 1966 1967 /* Create DevAttrQry Message */ 1968 flags = ISNS_FLAG_FIRST_PDU | 1969 ISNS_FLAG_LAST_PDU; 1970 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p); 1971 *xid_p = pdu_p->xid; 1972 1973 /* Source attribute */ 1974 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 1975 node_name_len, node_name, 0) != 0) { 1976 kmem_free(pdu_p, pdu_size); 1977 *out_pdu = NULL; 1978 return (0); 1979 } 1980 1981 /* 1982 * Message Key Attribute 1983 * 1984 * iSCSI Node Type 1985 * Query target nodes only 1986 */ 1987 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 1988 4, 0, ISNS_TARGET_NODE_TYPE) != 0) { 1989 kmem_free(pdu_p, pdu_size); 1990 *out_pdu = NULL; 1991 return (0); 1992 } 1993 1994 /* Delimiter */ 1995 if (isns_add_attr(pdu_p, pdu_size, 1996 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) { 1997 kmem_free(pdu_p, pdu_size); 1998 *out_pdu = NULL; 1999 return (0); 2000 } 2001 2002 /* PG iSCSI Name - Zero length TLV */ 2003 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID, 2004 0, 0, 0) != 0) { 2005 kmem_free(pdu_p, pdu_size); 2006 *out_pdu = NULL; 2007 return (0); 2008 } 2009 2010 /* PG Portal IP Address - Zero length TLV */ 2011 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 2012 0, 0, 0) != 0) { 2013 kmem_free(pdu_p, pdu_size); 2014 *out_pdu = NULL; 2015 return (0); 2016 } 2017 2018 /* PG Portal Port - Zero length TLV */ 2019 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID, 2020 0, 0, 0) != 0) { 2021 kmem_free(pdu_p, pdu_size); 2022 *out_pdu = NULL; 2023 return (0); 2024 } 2025 2026 /* PG Portal Group Tag - Zero length TLV */ 2027 if (isns_add_attr(pdu_p, pdu_size, 2028 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) { 2029 kmem_free(pdu_p, pdu_size); 2030 *out_pdu = NULL; 2031 return (0); 2032 } 2033 2034 *out_pdu = pdu_p; 2035 return (pdu_size); 2036 } 2037 2038 static 2039 size_t 2040 isns_create_dev_attr_qry_one_pg_pdu( 2041 uint8_t *target_node_name, 2042 uint8_t *source_node_name, 2043 uint16_t *xid_p, 2044 isns_pdu_t **out_pdu) 2045 { 2046 isns_pdu_t *pdu_p; 2047 uint16_t flags; 2048 size_t pdu_size, source_node_name_len, target_node_name_len; 2049 2050 ASSERT(target_node_name != NULL); 2051 ASSERT(source_node_name != NULL); 2052 2053 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2054 source_node_name_len = strlen((char *)source_node_name) + 1; 2055 target_node_name_len = strlen((char *)target_node_name) + 1; 2056 2057 if (source_node_name_len == 1) { 2058 *out_pdu = NULL; 2059 return (0); 2060 } 2061 2062 /* Create DevAttrQry message scoped to target_node_name */ 2063 flags = ISNS_FLAG_FIRST_PDU | 2064 ISNS_FLAG_LAST_PDU; 2065 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p); 2066 *xid_p = pdu_p->xid; 2067 2068 /* Source attribute */ 2069 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2070 source_node_name_len, source_node_name, 0) != 0) { 2071 kmem_free(pdu_p, pdu_size); 2072 *out_pdu = NULL; 2073 return (0); 2074 } 2075 2076 /* Message key attribute */ 2077 /* iSCSI Node Name */ 2078 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2079 target_node_name_len, 2080 target_node_name, 0) != 0) { 2081 kmem_free(pdu_p, pdu_size); 2082 *out_pdu = NULL; 2083 return (0); 2084 } 2085 2086 /* Delimiter */ 2087 if (isns_add_attr(pdu_p, pdu_size, 2088 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) { 2089 kmem_free(pdu_p, pdu_size); 2090 *out_pdu = NULL; 2091 return (0); 2092 } 2093 2094 /* PG iSCSI Name - Zero length TLV */ 2095 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID, 2096 0, 0, 0) != 0) { 2097 kmem_free(pdu_p, pdu_size); 2098 *out_pdu = NULL; 2099 return (0); 2100 } 2101 2102 /* PG Portal IP Address - Zero length TLV */ 2103 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 2104 0, 0, 0) != 0) { 2105 kmem_free(pdu_p, pdu_size); 2106 *out_pdu = NULL; 2107 return (0); 2108 } 2109 2110 /* PG Portal Port - Zero length TLV */ 2111 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID, 2112 0, 0, 0) != 0) { 2113 kmem_free(pdu_p, pdu_size); 2114 *out_pdu = NULL; 2115 return (0); 2116 } 2117 2118 /* PG Portal Group Tag - Zero length TLV */ 2119 if (isns_add_attr(pdu_p, pdu_size, 2120 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) { 2121 kmem_free(pdu_p, pdu_size); 2122 *out_pdu = NULL; 2123 return (0); 2124 } 2125 2126 *out_pdu = pdu_p; 2127 return (pdu_size); 2128 } 2129 2130 static 2131 size_t 2132 isns_create_scn_reg_pdu( 2133 uint8_t *node_name, 2134 uint8_t *node_alias, 2135 uint16_t *xid_p, 2136 isns_pdu_t **out_pdu) 2137 { 2138 isns_pdu_t *pdu; 2139 size_t pdu_size, node_name_len; 2140 uint16_t flags; 2141 2142 ASSERT(node_name != NULL); 2143 ASSERT(node_alias != NULL); 2144 2145 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2146 node_name_len = strlen((char *)node_name) + 1; 2147 2148 if (node_name_len == 1) { 2149 *out_pdu = NULL; 2150 return (0); 2151 } 2152 2153 /* Create SCNReg Message */ 2154 flags = ISNS_FLAG_FIRST_PDU | 2155 ISNS_FLAG_LAST_PDU; 2156 pdu_size = isns_create_pdu_header(ISNS_SCN_REG, flags, &pdu); 2157 *xid_p = pdu->xid; 2158 2159 /* Source attribute */ 2160 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2161 node_name_len, node_name, 0) != 0) { 2162 kmem_free(pdu, pdu_size); 2163 *out_pdu = NULL; 2164 return (0); 2165 } 2166 2167 /* Message attribute */ 2168 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2169 node_name_len, node_name, 0) != 0) { 2170 kmem_free(pdu, pdu_size); 2171 *out_pdu = NULL; 2172 return (0); 2173 } 2174 2175 /* Delimiter */ 2176 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2177 != 0) { 2178 kmem_free(pdu, pdu_size); 2179 *out_pdu = NULL; 2180 return (0); 2181 } 2182 2183 /* Operating attribute */ 2184 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_SCN_BITMAP_ATTR_ID, 2185 4, 2186 0, 2187 /* 2188 * Microsoft seems to not differentiate between init and 2189 * target. Hence, it makes no difference to turn on/off 2190 * the initiator/target bit. 2191 */ 2192 ISNS_TARGET_SELF_INFO_ONLY | 2193 ISNS_OBJ_REMOVED | 2194 ISNS_OBJ_ADDED | 2195 ISNS_OBJ_UPDATED) != 0) { 2196 kmem_free(pdu, pdu_size); 2197 *out_pdu = NULL; 2198 return (0); 2199 } 2200 2201 *out_pdu = pdu; 2202 return (pdu_size); 2203 } 2204 2205 static 2206 size_t 2207 isns_create_scn_dereg_pdu( 2208 uint8_t *node_name, 2209 uint16_t *xid_p, 2210 isns_pdu_t **out_pdu) 2211 { 2212 isns_pdu_t *pdu; 2213 size_t pdu_size, node_name_len; 2214 uint16_t flags; 2215 2216 ASSERT(node_name != NULL); 2217 2218 /* RFC 4171 section 6.1 - NULLs included in the length. */ 2219 node_name_len = strlen((char *)node_name) + 1; 2220 2221 if (node_name_len == 1) { 2222 *out_pdu = NULL; 2223 return (0); 2224 } 2225 2226 /* Create SCNReg Message */ 2227 flags = ISNS_FLAG_FIRST_PDU | 2228 ISNS_FLAG_LAST_PDU; 2229 pdu_size = isns_create_pdu_header(ISNS_SCN_DEREG, flags, &pdu); 2230 *xid_p = pdu->xid; 2231 2232 /* Source attribute */ 2233 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2234 node_name_len, node_name, 0) != 0) { 2235 kmem_free(pdu, pdu_size); 2236 *out_pdu = NULL; 2237 return (0); 2238 } 2239 2240 /* Message attribute */ 2241 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID, 2242 node_name_len, node_name, 0) != 0) { 2243 kmem_free(pdu, pdu_size); 2244 *out_pdu = NULL; 2245 return (0); 2246 } 2247 2248 /* Delimiter */ 2249 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2250 != 0) { 2251 kmem_free(pdu, pdu_size); 2252 *out_pdu = NULL; 2253 return (0); 2254 } 2255 2256 /* No operating attribute */ 2257 2258 *out_pdu = pdu; 2259 return (pdu_size); 2260 } 2261 2262 static 2263 size_t 2264 isns_create_esi_rsp_pdu(uint32_t rsp_status_code, 2265 isns_pdu_t *esi_pdu, 2266 uint16_t *xid_p, 2267 isns_pdu_t **out_pdu) 2268 { 2269 isns_pdu_t *pdu_p; 2270 uint16_t flags; 2271 uint8_t *payload_ptr; 2272 uint32_t swapped_status_code = htonl(rsp_status_code); 2273 size_t pdu_size, payload_len = 0; 2274 2275 /* Create ESIRsp Message */ 2276 flags = ISNS_FLAG_FIRST_PDU | 2277 ISNS_FLAG_LAST_PDU; 2278 pdu_size = isns_create_pdu_header(ISNS_ESI_RSP, flags, &pdu_p); 2279 *xid_p = pdu_p->xid; 2280 2281 payload_len = ntohs(pdu_p->payload_len); 2282 2283 /* Status Code */ 2284 payload_ptr = pdu_p->payload + payload_len; 2285 bcopy(&swapped_status_code, payload_ptr, 4); 2286 payload_len += 4; 2287 2288 payload_ptr = pdu_p->payload + payload_len; 2289 if ((esi_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) { 2290 bcopy(esi_pdu->payload, payload_ptr, 2291 (esi_pdu->payload_len)); 2292 payload_len += (esi_pdu->payload_len); 2293 } else { 2294 bcopy(esi_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE); 2295 payload_len += ISNSP_MAX_PAYLOAD_SIZE; 2296 } 2297 pdu_p->payload_len = htons(payload_len); 2298 2299 /* Delimiter */ 2300 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2301 != 0) { 2302 kmem_free(pdu_p, pdu_size); 2303 *out_pdu = NULL; 2304 return (0); 2305 } 2306 2307 *out_pdu = pdu_p; 2308 return (pdu_size); 2309 } 2310 2311 static 2312 size_t 2313 isns_create_scn_rsp_pdu(uint32_t rsp_status_code, 2314 isns_pdu_t *scn_pdu, 2315 uint16_t *xid_p, 2316 isns_pdu_t **out_pdu) 2317 { 2318 isns_pdu_t *pdu_p; 2319 uint16_t flags; 2320 uint8_t *payload_ptr; 2321 uint32_t swapped_status_code = htonl(rsp_status_code); 2322 size_t pdu_size, payload_len = 0; 2323 2324 /* Create SCNRsp Message */ 2325 flags = ISNS_FLAG_FIRST_PDU | 2326 ISNS_FLAG_LAST_PDU; 2327 pdu_size = isns_create_pdu_header(ISNS_SCN_RSP, flags, &pdu_p); 2328 *xid_p = pdu_p->xid; 2329 2330 payload_len = ntohs(pdu_p->payload_len); 2331 2332 /* Status Code */ 2333 payload_ptr = pdu_p->payload + payload_len; 2334 bcopy(&swapped_status_code, payload_ptr, 4); 2335 payload_len += 4; 2336 2337 payload_ptr = pdu_p->payload + payload_len; 2338 if ((scn_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) { 2339 bcopy(scn_pdu->payload, payload_ptr, 2340 (scn_pdu->payload_len)); 2341 payload_len += (scn_pdu->payload_len); 2342 } else { 2343 bcopy(scn_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE); 2344 payload_len += ISNSP_MAX_PAYLOAD_SIZE; 2345 } 2346 pdu_p->payload_len = htons(payload_len); 2347 2348 /* Delimiter */ 2349 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0) 2350 != 0) { 2351 kmem_free(pdu_p, pdu_size); 2352 *out_pdu = NULL; 2353 return (0); 2354 } 2355 2356 *out_pdu = pdu_p; 2357 return (pdu_size); 2358 } 2359 2360 static 2361 uint32_t 2362 isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p) 2363 { 2364 isns_resp_t *resp_p; 2365 2366 if (resp_pdu_p->func_id != ISNS_DEV_ATTR_REG_RSP) { 2367 /* If this happens the iSNS server may have a problem. */ 2368 return (ISNS_RSP_MSG_FORMAT_ERROR); 2369 } 2370 2371 /* Check response's status code */ 2372 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2373 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2374 return (ntohl(resp_p->status)); 2375 } 2376 2377 return (ISNS_RSP_SUCCESSFUL); 2378 } 2379 2380 static 2381 uint32_t 2382 isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p) 2383 { 2384 isns_resp_t *resp_p; 2385 2386 if (resp_pdu_p->func_id != ISNS_DEV_DEREG_RSP) { 2387 /* If this happens the iSNS server may have a problem. */ 2388 return (ISNS_RSP_MSG_FORMAT_ERROR); 2389 } 2390 2391 /* Check response's status code */ 2392 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2393 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2394 return (ntohl(resp_p->status)); 2395 } 2396 2397 return (ISNS_RSP_SUCCESSFUL); 2398 } 2399 2400 static 2401 uint32_t 2402 isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p) 2403 { 2404 isns_resp_t *resp_p; 2405 2406 ASSERT(resp_pdu_p != NULL); 2407 if (resp_pdu_p->func_id != ISNS_SCN_REG_RSP) { 2408 /* If this happens the iSNS server may have a problem. */ 2409 return (ISNS_RSP_MSG_FORMAT_ERROR); 2410 } 2411 2412 /* Check response's status code */ 2413 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2414 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2415 return (ntohl(resp_p->status)); 2416 } 2417 return (ISNS_RSP_SUCCESSFUL); 2418 } 2419 2420 static 2421 uint32_t 2422 isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p) 2423 { 2424 isns_resp_t *resp_p; 2425 2426 ASSERT(resp_pdu_p != NULL); 2427 if (resp_pdu_p->func_id != ISNS_SCN_DEREG_RSP) { 2428 /* If this happens the iSNS server may have a problem. */ 2429 return (ISNS_RSP_MSG_FORMAT_ERROR); 2430 } 2431 2432 /* Check response's status code */ 2433 resp_p = (isns_resp_t *)resp_pdu_p->payload; 2434 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2435 return (ntohl(resp_p->status)); 2436 } 2437 return (ISNS_RSP_SUCCESSFUL); 2438 } 2439 2440 static 2441 uint32_t 2442 isns_process_dev_attr_qry_target_nodes_pdu( 2443 iscsi_addr_t *isns_server_addr, uint16_t payload_funcId, 2444 isns_resp_t *resp_p, size_t resp_len, 2445 isns_portal_group_list_t **pg_list) 2446 { 2447 boolean_t done_b, found_delimiter_b, target_node_type_b; 2448 int num_of_pgs = 0, pg_sz, idx; 2449 isns_tlv_t *attr_tlv_p; 2450 uint8_t *data_p; 2451 uint32_t len, total_payload_len = 0; 2452 isns_portal_group_t *pg; 2453 uint8_t junk[IPV4_RSVD_BYTES]; 2454 2455 *pg_list = NULL; 2456 bzero(junk, IPV4_RSVD_BYTES); 2457 2458 if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) { 2459 /* If this happens the iSNS server may have a problem. */ 2460 return (ISNS_RSP_MSG_FORMAT_ERROR); 2461 } 2462 2463 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) { 2464 return (ntohl(resp_p->status)); 2465 } 2466 2467 /* 2468 * If payload is smaller than the length of even 1 attribute 2469 * there is something wrong with the PDU. 2470 */ 2471 if (resp_len < (ISNS_TLV_ATTR_ID_LEN + 2472 ISNS_TLV_ATTR_LEN_LEN)) { 2473 return (ISNS_RSP_MSG_FORMAT_ERROR); 2474 } 2475 2476 /* 2477 * Expected DevAttrQryRsp message format: 2478 * 2479 * Status Code 2480 * iSCSI Node Type 2481 * Delimiter 2482 * PG iSCSI Name [Optional] 2483 * PG Portal IP Address [Optional] 2484 * PG Portal Port [Optional] 2485 * PG Tag [Optional] 2486 * PG iSCSI Name [Optional] 2487 * PG Portal IP Address [Optional] 2488 * PG Portal Port [Optional] 2489 * PG Tag [Optional] 2490 * . 2491 * . 2492 * . 2493 */ 2494 data_p = resp_p->data; 2495 done_b = B_FALSE; 2496 found_delimiter_b = B_FALSE; 2497 num_of_pgs = 0; 2498 total_payload_len = sizeof (resp_p->status); 2499 /* Find out the number of entries retrieved */ 2500 while (!done_b) { 2501 attr_tlv_p = (isns_tlv_t *)data_p; 2502 if (ntohl(attr_tlv_p->attr_id) == ISNS_DELIMITER_ATTR_ID) { 2503 if (found_delimiter_b) { 2504 done_b = B_TRUE; 2505 } else { 2506 found_delimiter_b = B_TRUE; 2507 } 2508 } else if (ntohl(attr_tlv_p->attr_id) == 2509 ISNS_PG_TAG_ATTR_ID) { 2510 num_of_pgs++; 2511 } 2512 len = ntohl(attr_tlv_p->attr_len); 2513 2514 total_payload_len += (ISNS_TLV_ATTR_ID_LEN + 2515 ISNS_TLV_ATTR_LEN_LEN + len); 2516 if (total_payload_len >= resp_len) { 2517 done_b = B_TRUE; 2518 } else { 2519 data_p += (ISNS_TLV_ATTR_ID_LEN + 2520 ISNS_TLV_ATTR_LEN_LEN + len); 2521 } 2522 } 2523 2524 pg_sz = sizeof (isns_portal_group_list_t); 2525 if (num_of_pgs > 0) { 2526 pg_sz += (num_of_pgs - 1) * sizeof (isns_portal_group_t); 2527 } 2528 DTRACE_PROBE1(isns_process_dev_attr_qry_target_nodes_pdu_pg_size, 2529 int, pg_sz); 2530 /* 2531 * Once we passed this point, if for any reason we need to return 2532 * because of a failure, we need to free the memory allocated for 2533 * the pg_list and nullify it. 2534 */ 2535 *pg_list = (isns_portal_group_list_t *)kmem_zalloc(pg_sz, KM_SLEEP); 2536 (*pg_list)->pg_out_cnt = 0; 2537 2538 /* Assign the isns_server information to all portal groups */ 2539 for (idx = 0; idx < num_of_pgs; idx++) { 2540 pg = &((*pg_list)->pg_list[idx]); 2541 bcopy(&isns_server_addr->a_addr, &pg->isns_server_ip, 2542 sizeof (iscsi_ipaddr_t)); 2543 pg->isns_server_port = isns_server_addr->a_port; 2544 } 2545 2546 data_p = resp_p->data; 2547 done_b = B_FALSE; 2548 found_delimiter_b = B_FALSE; 2549 total_payload_len = sizeof (resp_p->status); 2550 while (!done_b) { 2551 attr_tlv_p = (isns_tlv_t *)data_p; 2552 pg = &((*pg_list)->pg_list[(*pg_list)->pg_out_cnt]); 2553 switch (ntohl(attr_tlv_p->attr_id)) { 2554 case ISNS_DELIMITER_ATTR_ID: 2555 if (found_delimiter_b) { 2556 done_b = B_TRUE; 2557 } else { 2558 found_delimiter_b = B_TRUE; 2559 } 2560 break; 2561 2562 case ISNS_PG_ISCSI_NAME_ATTR_ID: 2563 target_node_type_b = B_TRUE; 2564 bcopy(attr_tlv_p->attr_value, 2565 (char *)pg->pg_iscsi_name, 2566 ntohl(attr_tlv_p->attr_len) < 2567 ISCSI_MAX_NAME_LEN ? 2568 ntohl(attr_tlv_p->attr_len) : 2569 ISCSI_MAX_NAME_LEN); 2570 2571 DTRACE_PROBE1(isns_dev_attr_qry_process1, 2572 char *, (char *)pg->pg_iscsi_name); 2573 break; 2574 2575 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 2576 if (target_node_type_b) { 2577 /* 2578 * Section 6.3.1 - The Portal IP Address 2579 * is a 16-byte field that may contain 2580 * an IPv4 or IPv6 address. When this 2581 * field contains an IPv4 address, it 2582 * is stored as an IPv4-mapped IPv6 2583 * address 2584 */ 2585 if (ntohl(attr_tlv_p->attr_len) != 16) { 2586 #define STRING_AALR "address attribute length received " 2587 #define STRING_FISE16 "from iSNS server, Expected = 16, " 2588 cmn_err(CE_NOTE, "Wrong IP " 2589 STRING_AALR 2590 STRING_FISE16 2591 "Received = %d", 2592 ntohl( 2593 attr_tlv_p->attr_len)); 2594 return ( 2595 ISNS_RSP_MSG_FORMAT_ERROR); 2596 #undef STRING_AALR 2597 #undef STRING_FISE16 2598 } 2599 2600 /* 2601 * Section 6.3.1 and RFC 2373 state 2602 * that an IPv4 address will be denoted 2603 * by the 10 top bytes as all zero 2604 * followed by either 2 bytes of 2605 * 0x0000 or 0xFFFF The 0x0000 states 2606 * that the address is is IPv6 capable 2607 * and 0xFFFF states its not capable. 2608 */ 2609 if ((bcmp(attr_tlv_p->attr_value, junk, 2610 IPV4_RSVD_BYTES) == 0) && 2611 (((attr_tlv_p->attr_value[10] == 2612 0x00) && 2613 (attr_tlv_p->attr_value[11] == 2614 0x00)) || 2615 ((attr_tlv_p->attr_value[10] == 2616 0xFF) && 2617 (attr_tlv_p->attr_value[11] == 2618 0xFF)))) { 2619 2620 /* IPv4 */ 2621 bcopy(attr_tlv_p->attr_value + 2622 12, &pg->pg_ip_addr.u_ip4, 2623 sizeof (struct in_addr)); 2624 pg->insize = 2625 sizeof (struct in_addr); 2626 } else { 2627 /* IPv6 */ 2628 bcopy(attr_tlv_p->attr_value, 2629 &pg->pg_ip_addr.u_ip6, 2630 sizeof (struct in6_addr)); 2631 pg->insize = 2632 sizeof (struct in6_addr); 2633 } 2634 } 2635 break; 2636 2637 case ISNS_PG_PORTAL_PORT_ATTR_ID: 2638 if (target_node_type_b) { 2639 pg->pg_port = 2640 ntohl(*(uint32_t *) 2641 (*attr_tlv_p). 2642 attr_value); 2643 } 2644 2645 break; 2646 2647 case ISNS_PG_TAG_ATTR_ID: 2648 if (target_node_type_b) { 2649 pg->pg_tag = 2650 ntohl(*(uint32_t *) 2651 (*attr_tlv_p). 2652 attr_value); 2653 } 2654 (*pg_list)->pg_out_cnt++; 2655 target_node_type_b = B_FALSE; 2656 break; 2657 2658 default: 2659 break; 2660 } 2661 2662 len = ntohl(attr_tlv_p->attr_len); 2663 total_payload_len += (ISNS_TLV_ATTR_ID_LEN + 2664 ISNS_TLV_ATTR_LEN_LEN + len); 2665 if ((total_payload_len >= resp_len) || 2666 ((*pg_list)->pg_out_cnt == num_of_pgs)) { 2667 done_b = B_TRUE; 2668 } else { 2669 data_p += (ISNS_TLV_ATTR_ID_LEN + 2670 ISNS_TLV_ATTR_LEN_LEN + len); 2671 } 2672 } 2673 2674 return (ISNS_RSP_SUCCESSFUL); 2675 } 2676 2677 /* ARGSUSED */ 2678 static 2679 uint32_t 2680 isns_process_esi(isns_pdu_t *esi_pdu_p) 2681 { 2682 /* There's nothing particular to process for ESI. */ 2683 return (ISNS_RSP_SUCCESSFUL); 2684 } 2685 2686 static 2687 uint32_t 2688 isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle) 2689 { 2690 boolean_t dest_attr_found_b; 2691 boolean_t done_b; 2692 boolean_t scn_type_found_b; 2693 isns_scn_callback_arg_t *scn_args_p; 2694 isns_tlv_t *attr_tlv_p; 2695 uint8_t *data_p; 2696 uint8_t *src_attr; 2697 uint32_t attr_eff_len, normalized_attr_len; 2698 uint32_t scn_type; 2699 uint32_t total_payload_len; 2700 void (*scn_callback_to_use)(void *); 2701 2702 /* get the lhba_handle to use for the call back */ 2703 scn_callback_to_use = scn_callback_lookup(lhba_handle); 2704 if (scn_callback_to_use == NULL) { 2705 return (ISNS_RSP_INTERNAL_ERROR); 2706 } 2707 2708 dest_attr_found_b = B_FALSE; 2709 scn_type = 0; 2710 scn_type_found_b = B_FALSE; 2711 data_p = scn_pdu_p->payload; 2712 done_b = B_FALSE; 2713 total_payload_len = 0; 2714 src_attr = (uint8_t *)kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP); 2715 /* 2716 * Section 5.6.5.8 states an SCN can have more than one 2717 * source attribute. Process all attributes until we 2718 * each process all the data or encounter the delimiter. 2719 */ 2720 while (!done_b) { 2721 attr_tlv_p = (isns_tlv_t *)data_p; 2722 2723 switch (ntohl(attr_tlv_p->attr_id)) { 2724 /* ISNS_ISCSI_NAME_ATTR_ID - attribute name */ 2725 case ISNS_ISCSI_NAME_ATTR_ID: 2726 attr_eff_len = strlen( 2727 (char *)attr_tlv_p->attr_value) + 1; 2728 /* 2729 * The attribute length must be 4-byte aligned. 2730 * Section 5.1.3, RFC 4171. 2731 */ 2732 normalized_attr_len = (attr_eff_len % 4) == 0 ? 2733 (attr_eff_len) : 2734 (attr_eff_len + (4 - (attr_eff_len % 4))); 2735 if (normalized_attr_len != 2736 ntohl(attr_tlv_p->attr_len)) { 2737 /* This SCN is bad. */ 2738 kmem_free(src_attr, ISCSI_MAX_NAME_LEN); 2739 return (ISNS_RSP_MSG_FORMAT_ERROR); 2740 } 2741 2742 /* Check if this was the Destination Attribute */ 2743 if ((dest_attr_found_b == B_TRUE) && 2744 (scn_type_found_b == B_TRUE)) { 2745 bzero(src_attr, ISCSI_MAX_NAME_LEN); 2746 bcopy(attr_tlv_p->attr_value, 2747 (char *)src_attr, 2748 ntohl(attr_tlv_p->attr_len) < 2749 ISCSI_MAX_NAME_LEN ? 2750 ntohl(attr_tlv_p->attr_len) : 2751 ISCSI_MAX_NAME_LEN); 2752 2753 /* allocate new callback structure */ 2754 scn_args_p = 2755 (isns_scn_callback_arg_t *)kmem_zalloc( 2756 sizeof (isns_scn_callback_arg_t), 2757 KM_SLEEP); 2758 scn_args_p->scn_type = ntohl(scn_type); 2759 bcopy(src_attr, scn_args_p->source_key_attr, 2760 sizeof (scn_args_p->source_key_attr)); 2761 2762 /* Dispatch the callback to process the SCN */ 2763 mutex_enter(&scn_taskq_mutex); 2764 if (scn_taskq != NULL) { 2765 (void) ddi_taskq_dispatch(scn_taskq, 2766 scn_callback_to_use, 2767 scn_args_p, DDI_SLEEP); 2768 } 2769 mutex_exit(&scn_taskq_mutex); 2770 } else { 2771 /* Skip Destination Attribute */ 2772 dest_attr_found_b = B_TRUE; 2773 } 2774 break; 2775 2776 /* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */ 2777 case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: 2778 /* 2779 * Determine the type of action to take for this SCN. 2780 */ 2781 scn_type_found_b = B_TRUE; 2782 bcopy(&(attr_tlv_p->attr_value), &scn_type, 4); 2783 break; 2784 2785 /* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */ 2786 case ISNS_DELIMITER_ATTR_ID: 2787 done_b = B_TRUE; 2788 break; 2789 } 2790 2791 if (done_b == B_FALSE) { 2792 total_payload_len += ntohl(attr_tlv_p->attr_len) + 2793 ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN; 2794 if ((total_payload_len >= scn_pdu_p->payload_len) || 2795 (total_payload_len > ISNSP_MAX_PAYLOAD_SIZE)) { 2796 /* No more Attributes to process */ 2797 done_b = B_TRUE; 2798 } else { 2799 if (scn_pdu_p->payload_len - 2800 total_payload_len <= 2801 ISNS_TLV_ATTR_ID_LEN + 2802 ISNS_TLV_ATTR_LEN_LEN) { 2803 /* 2804 * The rest of the data in the PDU 2805 * is less than the size of a valid 2806 * iSNS TLV. This next attribute 2807 * probably spans across the PDU 2808 * boundary. For now, do not 2809 * process it further. 2810 */ 2811 done_b = B_TRUE; 2812 } else { 2813 /* Advance to the next Attribute */ 2814 data_p += (ISNS_TLV_ATTR_ID_LEN + 2815 ISNS_TLV_ATTR_LEN_LEN + 2816 ntohl(attr_tlv_p->attr_len)); 2817 } 2818 } 2819 } 2820 } 2821 2822 kmem_free(src_attr, ISCSI_MAX_NAME_LEN); 2823 return (ISNS_RSP_SUCCESSFUL); 2824 } 2825 2826 static 2827 size_t 2828 isns_create_pdu_header(uint16_t func_id, uint16_t flags, isns_pdu_t **pdu) 2829 { 2830 /* 2831 * It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough 2832 * since we are creating our own PDU which is fully under our control. 2833 */ 2834 size_t pdu_size = ISNSP_MAX_PDU_SIZE; 2835 2836 *pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_SLEEP); 2837 (void) memset((*pdu), 0, pdu_size); 2838 (*pdu)->version = htons((uint16_t)ISNSP_VERSION); 2839 (*pdu)->func_id = htons((uint16_t)func_id); 2840 (*pdu)->payload_len = htons(0); 2841 (*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT)); 2842 (*pdu)->xid = htons(create_xid()); 2843 (*pdu)->seq = htons(0); 2844 2845 return (pdu_size); 2846 } 2847 2848 static 2849 int 2850 isns_add_attr(isns_pdu_t *pdu, 2851 size_t max_pdu_size, 2852 uint32_t attr_id, 2853 uint32_t attr_len, 2854 void *attr_data, 2855 uint32_t attr_numeric_data) 2856 { 2857 isns_tlv_t *attr_tlv; 2858 uint8_t *payload_ptr; 2859 uint16_t payload_len; 2860 uint32_t normalized_attr_len; 2861 uint64_t attr_tlv_len; 2862 2863 /* The attribute length must be 4-byte aligned. Section 5.1.3. */ 2864 normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) : 2865 (attr_len + (4 - (attr_len % 4))); 2866 attr_tlv_len = ISNS_TLV_ATTR_ID_LEN 2867 + ISNS_TLV_ATTR_LEN_LEN 2868 + normalized_attr_len; 2869 /* Check if we are going to exceed the maximum PDU length. */ 2870 payload_len = ntohs(pdu->payload_len); 2871 if ((payload_len + attr_tlv_len) > max_pdu_size) { 2872 return (1); 2873 } 2874 2875 attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP); 2876 2877 attr_tlv->attr_id = htonl(attr_id); 2878 2879 switch (attr_id) { 2880 case ISNS_DELIMITER_ATTR_ID: 2881 break; 2882 2883 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 2884 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 2885 if (attr_numeric_data == sizeof (in_addr_t)) { 2886 /* IPv4 */ 2887 attr_tlv->attr_value[10] = 0xFF; 2888 attr_tlv->attr_value[11] = 0xFF; 2889 bcopy(attr_data, ((attr_tlv->attr_value) + 12), 2890 sizeof (in_addr_t)); 2891 } else if (attr_numeric_data == sizeof (in6_addr_t)) { 2892 /* IPv6 */ 2893 bcopy(attr_data, attr_tlv->attr_value, 2894 sizeof (in6_addr_t)); 2895 } else if (attr_numeric_data == 0) { 2896 /* EMPTY */ 2897 /* Do nothing */ 2898 } else { 2899 kmem_free(attr_tlv, attr_tlv_len); 2900 attr_tlv = NULL; 2901 return (1); 2902 } 2903 break; 2904 2905 case ISNS_EID_ATTR_ID: 2906 case ISNS_ISCSI_NAME_ATTR_ID: 2907 case ISNS_ISCSI_ALIAS_ATTR_ID: 2908 case ISNS_PG_ISCSI_NAME_ATTR_ID: 2909 bcopy((char *)attr_data, 2910 attr_tlv->attr_value, 2911 attr_len); 2912 break; 2913 2914 default: 2915 switch (normalized_attr_len) { 2916 case 0: 2917 break; 2918 2919 case 4: 2920 *(uint32_t *)attr_tlv->attr_value = 2921 htonl(attr_numeric_data); 2922 break; 2923 2924 case 8: 2925 *(uint64_t *)attr_tlv->attr_value = 2926 BE_64((uint64_t) 2927 attr_numeric_data); 2928 break; 2929 } 2930 } 2931 2932 attr_tlv->attr_len = htonl(normalized_attr_len); 2933 /* 2934 * Convert the network byte ordered payload length to host byte 2935 * ordered for local address calculation. 2936 */ 2937 payload_len = ntohs(pdu->payload_len); 2938 payload_ptr = pdu->payload + payload_len; 2939 bcopy(attr_tlv, payload_ptr, attr_tlv_len); 2940 payload_len += attr_tlv_len; 2941 2942 /* 2943 * Convert the host byte ordered payload length back to network 2944 * byte ordered - it's now ready to be sent on the wire. 2945 */ 2946 pdu->payload_len = htons(payload_len); 2947 2948 kmem_free(attr_tlv, attr_tlv_len); 2949 attr_tlv = NULL; 2950 2951 return (0); 2952 } 2953 2954 /* ARGSUSED */ 2955 static 2956 void 2957 isns_service_esi_scn(iscsi_thread_t *thread, void *arg) 2958 { 2959 int clnt_len; 2960 isns_async_thread_arg_t *larg; 2961 isns_pdu_t *in_pdu; 2962 size_t bytes_received, in_pdu_size = 0; 2963 uint8_t *lhba_handle; 2964 union { 2965 struct sockaddr sin; 2966 struct sockaddr_in s_in4; 2967 struct sockaddr_in6 s_in6; 2968 } clnt_addr = { 0 }; 2969 union { 2970 struct sockaddr_in soa4; 2971 struct sockaddr_in6 soa6; 2972 } local_conn_prop; 2973 void *listening_so, *connecting_so; 2974 2975 larg = (isns_async_thread_arg_t *)arg; 2976 listening_so = larg->listening_so; 2977 lhba_handle = larg->lhba_handle; 2978 2979 /* Done using the argument - free it */ 2980 kmem_free(larg, sizeof (*larg)); 2981 2982 if (((struct sonode *)listening_so)->so_laddr.soa_len <= 2983 sizeof (local_conn_prop)) { 2984 bcopy(((struct sonode *)listening_so)->so_laddr.soa_sa, 2985 &local_conn_prop, 2986 ((struct sonode *)listening_so)->so_laddr.soa_len); 2987 } 2988 2989 if (iscsi_net->listen(listening_so, 5) < 0) { 2990 iscsi_net->close(listening_so); 2991 } 2992 2993 for (;;) { 2994 int rval; 2995 isns_pdu_t *out_pdu; 2996 size_t out_pdu_size; 2997 2998 clnt_len = sizeof (clnt_addr); 2999 3000 /* Blocking call */ 3001 connecting_so = iscsi_net->accept( 3002 (struct sonode *)listening_so, 3003 &clnt_addr.sin, &clnt_len); 3004 3005 mutex_enter(&esi_scn_thr_mutex); 3006 if (esi_scn_thr_to_shutdown == B_TRUE) { 3007 /* Terminate the thread if instructed to do so. */ 3008 mutex_exit(&esi_scn_thr_mutex); 3009 return; 3010 } 3011 mutex_exit(&esi_scn_thr_mutex); 3012 3013 if (connecting_so == NULL) { 3014 iscsi_net->close(listening_so); 3015 continue; 3016 } 3017 3018 bytes_received = isns_rcv_pdu(connecting_so, &in_pdu, 3019 &in_pdu_size); 3020 if (in_pdu == NULL) { 3021 continue; 3022 } 3023 if (bytes_received == 0) { 3024 continue; 3025 } 3026 3027 switch (in_pdu->func_id) { 3028 case ISNS_ESI: 3029 case ISNS_SCN: 3030 if (in_pdu->func_id == ISNS_ESI) { 3031 rval = isns_process_esi(in_pdu); 3032 out_pdu_size = isns_create_esi_rsp_pdu( 3033 rval, 3034 in_pdu, 3035 &xid, 3036 &out_pdu); 3037 } else if (in_pdu->func_id == ISNS_SCN) { 3038 rval = isns_process_scn(in_pdu, 3039 lhba_handle); 3040 out_pdu_size = isns_create_scn_rsp_pdu( 3041 rval, 3042 in_pdu, 3043 &xid, 3044 &out_pdu); 3045 } else { 3046 /* 3047 * Ignore all traffics other than 3048 * ESI and SCN. 3049 */ 3050 kmem_free(in_pdu, in_pdu_size); 3051 in_pdu = NULL; 3052 continue; 3053 } 3054 3055 if (out_pdu_size == 0) { 3056 kmem_free(in_pdu, in_pdu_size); 3057 in_pdu = NULL; 3058 continue; 3059 } 3060 3061 (void) isns_send_pdu(connecting_so, out_pdu); 3062 3063 kmem_free(out_pdu, out_pdu_size); 3064 out_pdu = NULL; 3065 kmem_free(in_pdu, in_pdu_size); 3066 in_pdu = NULL; 3067 3068 iscsi_net->close(connecting_so); 3069 break; 3070 3071 default: 3072 kmem_free(in_pdu, in_pdu_size); 3073 in_pdu = NULL; 3074 continue; 3075 } 3076 } 3077 } 3078 3079 static 3080 boolean_t 3081 find_local_portal(iscsi_addr_t *isns_server_addr, 3082 iscsi_addr_t **local_addr, void **listening_so) 3083 { 3084 char local_addr_str[256]; 3085 union { 3086 struct sockaddr_in soa4; 3087 struct sockaddr_in6 soa6; 3088 } local_conn_prop = { 0 }; 3089 union { 3090 struct sockaddr sin; 3091 struct sockaddr_in s_in4; 3092 struct sockaddr_in6 s_in6; 3093 } serv_addr = { 0 }; 3094 void *so; 3095 3096 *local_addr = NULL; 3097 *listening_so = NULL; 3098 3099 /* 3100 * Determine the local IP address. 3101 */ 3102 so = isns_open(isns_server_addr); 3103 if (so == NULL) { 3104 return (B_FALSE); 3105 } 3106 3107 if (((struct sonode *)so)->so_laddr.soa_len > 3108 sizeof (local_conn_prop)) { 3109 iscsi_net->close(so); 3110 return (B_FALSE); 3111 } 3112 3113 bcopy(((struct sonode *)so)->so_laddr.soa_sa, 3114 &local_conn_prop, 3115 ((struct sonode *)so)->so_laddr.soa_len); 3116 3117 if (local_conn_prop.soa4.sin_family == AF_INET) { 3118 *local_addr = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), 3119 KM_SLEEP); 3120 (*local_addr)->a_addr.i_addr.in4.s_addr = 3121 local_conn_prop.soa4.sin_addr.s_addr; 3122 (*local_addr)->a_addr.i_insize = sizeof (in_addr_t); 3123 } else if (local_conn_prop.soa4.sin_family == AF_INET6) { 3124 /* EMPTY */ 3125 } else { 3126 iscsi_net->close(so); 3127 return (B_FALSE); 3128 } 3129 3130 iscsi_net->close(so); 3131 3132 /* 3133 * Determine the local IP address. (End) 3134 */ 3135 3136 serv_addr.s_in4.sin_family = AF_INET; 3137 /* 3138 * Use INADDR_ANY to accept connections from any of the connected 3139 * networks. 3140 */ 3141 serv_addr.s_in4.sin_addr.s_addr = htonl(INADDR_ANY); 3142 /* 3143 * Use port number 0 to allow the system to assign a unique unused 3144 * port. 3145 */ 3146 serv_addr.s_in4.sin_port = htons(0); 3147 3148 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0); 3149 if (so == NULL) { 3150 kmem_free((*local_addr), sizeof (iscsi_addr_t)); 3151 *local_addr = NULL; 3152 return (B_FALSE); 3153 } 3154 3155 if (iscsi_net->bind(so, &serv_addr.sin, 3156 sizeof (struct sockaddr), 0, 0) < 0) { 3157 kmem_free((*local_addr), sizeof (iscsi_addr_t)); 3158 *local_addr = NULL; 3159 iscsi_net->close(so); 3160 return (B_FALSE); 3161 } 3162 3163 if (((struct sonode *)so)->so_laddr.soa_len <= 3164 sizeof (local_conn_prop)) { 3165 bcopy(((struct sonode *)so)->so_laddr.soa_sa, 3166 &local_conn_prop, 3167 ((struct sonode *)so)->so_laddr.soa_len); 3168 (*local_addr)->a_port = ntohs(local_conn_prop.soa4.sin_port); 3169 } else { 3170 (*local_addr)->a_port = ISNS_DEFAULT_ESI_SCN_PORT; 3171 } 3172 3173 *listening_so = so; 3174 3175 (void) inet_ntop(AF_INET, (void *)&((*local_addr)->a_addr.i_addr.in4), 3176 local_addr_str, 256); 3177 3178 return (B_TRUE); 3179 } 3180 3181 /* ARGSUSED */ 3182 static 3183 void 3184 (*scn_callback_lookup(uint8_t *lhba_handle))(void *) 3185 { 3186 /* 3187 * When we support multiple HBA instance we will use lhba_handle 3188 * to look up the associated SCN callback. For now, we only support 3189 * one HBA instance therefore we always return the same SCN callback. 3190 */ 3191 return (scn_callback_p); 3192 } 3193 3194 static 3195 uint16_t 3196 create_xid() 3197 { 3198 return (xid++ % MAX_XID); 3199 } 3200 3201 static 3202 void 3203 esi_scn_thr_cleanup() 3204 { 3205 boolean_t clear_esi_scn_thr_id_b = B_FALSE; 3206 boolean_t clear_instance_listening_so_b = B_FALSE; 3207 boolean_t clear_local_addr_b = B_FALSE; 3208 iscsi_thread_t *tmp_esi_scn_thr_id = NULL; 3209 3210 mutex_enter(&esi_scn_thr_mutex); 3211 tmp_esi_scn_thr_id = esi_scn_thr_id; 3212 mutex_exit(&esi_scn_thr_mutex); 3213 if (tmp_esi_scn_thr_id != NULL) { 3214 boolean_t unblock_esi_scn_thr_b = B_TRUE; 3215 3216 /* Instruct the ESI/SCN to shut itself down. */ 3217 mutex_enter(&esi_scn_thr_mutex); 3218 esi_scn_thr_to_shutdown = B_TRUE; 3219 if (instance_listening_so != NULL && 3220 local_addr != NULL) { 3221 isns_pdu_t *out_pdu; 3222 size_t out_pdu_size; 3223 void *connecting_so; 3224 3225 /* 3226 * Open a connection to the local address and send 3227 * a dummy header to unblock the accept call so that 3228 * the ESI/SCN thread has a chance to terminate 3229 * itself. 3230 */ 3231 connecting_so = isns_open(local_addr); 3232 if (connecting_so == NULL) { 3233 unblock_esi_scn_thr_b = B_FALSE; 3234 mutex_exit(&esi_scn_thr_mutex); 3235 } else { 3236 out_pdu_size = isns_create_pdu_header(0, 3237 ISNS_FLAG_FIRST_PDU | 3238 ISNS_FLAG_LAST_PDU, 3239 &out_pdu); 3240 if (isns_send_pdu(connecting_so, 3241 out_pdu) != 0) { 3242 unblock_esi_scn_thr_b = B_FALSE; 3243 } else { 3244 unblock_esi_scn_thr_b = B_TRUE; 3245 } 3246 iscsi_net->close(connecting_so); 3247 kmem_free(out_pdu, out_pdu_size); 3248 out_pdu = NULL; 3249 mutex_exit(&esi_scn_thr_mutex); 3250 } 3251 } else { 3252 mutex_exit(&esi_scn_thr_mutex); 3253 } 3254 3255 if (unblock_esi_scn_thr_b == B_TRUE) { 3256 clear_instance_listening_so_b = B_TRUE; 3257 clear_esi_scn_thr_id_b = B_TRUE; 3258 clear_local_addr_b = B_TRUE; 3259 } 3260 } 3261 3262 if (clear_instance_listening_so_b && 3263 clear_esi_scn_thr_id_b && 3264 clear_local_addr_b) { 3265 (void) iscsi_thread_stop(esi_scn_thr_id); 3266 iscsi_thread_destroy(esi_scn_thr_id); 3267 3268 mutex_enter(&esi_scn_thr_mutex); 3269 esi_scn_thr_id = NULL; 3270 3271 /* 3272 * Shutdown and close the listening socket. 3273 */ 3274 iscsi_net->shutdown(instance_listening_so, 2); 3275 iscsi_net->close(instance_listening_so); 3276 instance_listening_so = NULL; 3277 3278 if (local_addr != NULL) { 3279 kmem_free(local_addr, sizeof (iscsi_addr_t)); 3280 local_addr = NULL; 3281 } 3282 mutex_exit(&esi_scn_thr_mutex); 3283 } 3284 } 3285