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