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