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