xref: /illumos-gate/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c (revision e44e85a7f9935f0428e188393e3da61b17e83884)
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 
26 #include <sys/cpuvar.h>
27 #include <sys/types.h>
28 #include <sys/conf.h>
29 #include <sys/file.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/socket.h>
33 #include <inet/tcp.h>
34 #include <sys/sdt.h>
35 
36 #include <sys/stmf.h>
37 #include <sys/stmf_ioctl.h>
38 #include <sys/portif.h>
39 #include <sys/idm/idm.h>
40 #include <sys/idm/idm_so.h>
41 #include <sys/iscsit/iscsit_common.h>
42 #include <sys/iscsit/isns_protocol.h>
43 #include <iscsit.h>
44 #include <iscsit_isns.h>
45 #include <sys/ksocket.h>
46 
47 /* local defines */
48 #define	MAX_XID			(2^16)
49 #define	ISNS_IDLE_TIME		60
50 #define	MAX_RETRY		(3)
51 #define	ISNS_RCV_TIMER_SECONDS	5
52 
53 #define	VALID_NAME(NAME, LEN)	\
54 ((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0)
55 
56 
57 boolean_t iscsit_isns_logging = 0;
58 
59 #define	ISNST_LOG if (iscsit_isns_logging) cmn_err
60 
61 static kmutex_t		isns_monitor_mutex;
62 static kthread_t	*isns_monitor_thr_id;
63 static kt_did_t		isns_monitor_thr_did;
64 static boolean_t	isns_monitor_thr_running;
65 
66 static kcondvar_t	isns_idle_cv;
67 
68 static uint16_t		xid;
69 #define	GET_XID()	atomic_inc_16_nv(&xid)
70 
71 static clock_t		monitor_idle_interval;
72 
73 #define	ISNS_GLOBAL_LOCK() \
74 	mutex_enter(&iscsit_global.global_isns_cfg.isns_mutex)
75 
76 #define	ISNS_GLOBAL_LOCK_HELD() \
77 	MUTEX_HELD(&iscsit_global.global_isns_cfg.isns_mutex)
78 
79 #define	ISNS_GLOBAL_UNLOCK() \
80 	mutex_exit(&iscsit_global.global_isns_cfg.isns_mutex)
81 
82 /*
83  * iSNS ESI thread state
84  */
85 
86 static isns_esi_tinfo_t	esi;
87 
88 /*
89  * List of portals.
90  */
91 static boolean_t	default_portal_online = B_FALSE;
92 static boolean_t	default_portal_state_change = B_FALSE;
93 static list_t		portal_list;
94 static uint32_t		portal_list_count = 0;
95 
96 /*
97  * Our entity identifier (fully-qualified hostname)
98  */
99 static char		*isns_eid = NULL;
100 
101 /*
102  * Our list of targets
103  */
104 static avl_tree_t	isns_target_list;
105 
106 /*
107  * in6addr_any is currently all zeroes, but use the macro in case this
108  * ever changes.
109  */
110 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
111 
112 static void
113 isnst_start();
114 
115 static void
116 isnst_stop();
117 
118 static void
119 iscsit_set_isns(boolean_t state);
120 
121 static int
122 iscsit_add_isns(it_portal_t *cfg_svr);
123 
124 static void
125 iscsit_delete_isns(iscsit_isns_svr_t *svr);
126 
127 static iscsit_isns_svr_t *
128 iscsit_isns_svr_lookup(struct sockaddr_storage *sa);
129 
130 static void
131 isnst_monitor(void *arg);
132 
133 static int
134 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled);
135 
136 static int
137 isnst_update_target(iscsit_tgt_t *target, isns_reg_type_t reg);
138 
139 static  int
140 isnst_update_one_server(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
141     isns_reg_type_t reg);
142 
143 static int isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
144     isns_reg_type_t regtype);
145 static int isnst_deregister(iscsit_isns_svr_t *svr, char *node);
146 
147 static size_t
148 isnst_make_dereg_pdu(isns_pdu_t **pdu, char *node);
149 
150 static int
151 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
152     isns_pdu_t *rsp, size_t rsp_size);
153 
154 static uint16_t
155 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp);
156 
157 static size_t
158 isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
159     boolean_t svr_registered, isns_reg_type_t regtype);
160 
161 static int
162 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size,
163     idm_addr_list_t *default_portal_list);
164 
165 static int
166 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, iscsit_tgt_t *target,
167     idm_addr_list_t *default_portal_list);
168 
169 static int
170 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
171     iscsit_tgt_t *tgt, idm_addr_list_t *default_portal_list);
172 
173 static int
174 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
175     uint32_t ip_attr_id, uint32_t port_attr_id,
176     struct sockaddr_storage *ss, boolean_t esi_info);
177 
178 static size_t
179 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags);
180 
181 static int
182 isnst_add_attr(isns_pdu_t *pdu,
183     size_t max_pdu_size,
184     uint32_t attr_id,
185     uint32_t attr_len,
186     void *attr_data,
187     uint32_t attr_numeric_data);
188 
189 static int
190 isnst_send_pdu(void *so, isns_pdu_t *pdu);
191 
192 static size_t
193 isnst_rcv_pdu(void *so, isns_pdu_t **pdu);
194 
195 static void *
196 isnst_open_so(struct sockaddr_storage *sa);
197 
198 static void
199 isnst_close_so(void *);
200 
201 static void
202 isnst_esi_thread(void *arg);
203 
204 static void
205 isnst_handle_esi_req(ksocket_t so, isns_pdu_t *pdu, size_t pl_size);
206 
207 static void isnst_esi_start(void);
208 static void isnst_esi_stop(void);
209 static isns_target_t *isnst_add_to_target_list(iscsit_tgt_t *target);
210 int isnst_tgt_avl_compare(const void *t1, const void *t2);
211 static void isnst_get_target_list(void);
212 static void isnst_set_server_status(iscsit_isns_svr_t *svr,
213     boolean_t registered);
214 static void isnst_monitor_start(void);
215 static void isnst_monitor_stop(void);
216 static void isnst_add_portal(iscsit_portal_t *portal);
217 static void isnst_remove_portal(iscsit_portal_t *portal);
218 static isns_portal_list_t *isnst_lookup_portal(struct sockaddr_storage *p,
219 	isns_portal_list_t *last_portal);
220 static boolean_t isnst_portal_exists(struct sockaddr_storage *p);
221 static boolean_t isnst_lookup_default_portal();
222 
223 static boolean_t isnst_retry_registration(int rsp_status_code);
224 
225 it_cfg_status_t
226 isnst_config_merge(it_config_t *cfg)
227 {
228 	boolean_t		new_isns_state = B_FALSE;
229 	iscsit_isns_svr_t	*isns_svr, *next_isns_svr;
230 	it_portal_t		*cfg_isns_svr;
231 
232 	/*
233 	 * Determine whether iSNS is enabled in the new config.
234 	 * Isns property may not be set up yet.
235 	 */
236 	(void) nvlist_lookup_boolean_value(cfg->config_global_properties,
237 	    PROP_ISNS_ENABLED, &new_isns_state);
238 
239 	ISNS_GLOBAL_LOCK();
240 
241 	/* Delete iSNS servers that are no longer part of the config */
242 	for (isns_svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
243 	    isns_svr != NULL;
244 	    isns_svr = next_isns_svr) {
245 		next_isns_svr = list_next(
246 		    &iscsit_global.global_isns_cfg.isns_svrs, isns_svr);
247 		if (it_sns_svr_lookup(cfg, &isns_svr->svr_sa) == NULL)
248 			iscsit_delete_isns(isns_svr);
249 	}
250 
251 	/* Add new iSNS servers */
252 	for (cfg_isns_svr = cfg->config_isns_svr_list;
253 	    cfg_isns_svr != NULL;
254 	    cfg_isns_svr = cfg_isns_svr->next) {
255 		isns_svr = iscsit_isns_svr_lookup(&cfg_isns_svr->portal_addr);
256 		if (isns_svr == NULL) {
257 			if (iscsit_add_isns(cfg_isns_svr) != 0) {
258 				/* Shouldn't happen */
259 				ISNS_GLOBAL_UNLOCK();
260 				return (ITCFG_MISC_ERR);
261 			}
262 		}
263 	}
264 
265 	/* Start/Stop iSNS if necessary */
266 	if (iscsit_global.global_isns_cfg.isns_state != new_isns_state) {
267 		iscsit_set_isns(new_isns_state);
268 	}
269 
270 	ISNS_GLOBAL_UNLOCK();
271 
272 	/*
273 	 * There is no "modify case" since the user specifies a complete
274 	 * server list each time.  A modify is the same as a remove+add.
275 	 */
276 
277 	return (0);
278 }
279 
280 int
281 iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
282 {
283 	mutex_init(&iscsit_global.global_isns_cfg.isns_mutex, NULL,
284 	    MUTEX_DEFAULT, NULL);
285 
286 	ISNS_GLOBAL_LOCK();
287 	iscsit_global.global_isns_cfg.isns_state = B_FALSE;
288 	list_create(&iscsit_global.global_isns_cfg.isns_svrs,
289 	    sizeof (iscsit_isns_svr_t), offsetof(iscsit_isns_svr_t, svr_ln));
290 	list_create(&portal_list, sizeof (isns_portal_list_t),
291 	    offsetof(isns_portal_list_t, portal_ln));
292 	portal_list_count = 0;
293 	isns_eid = kmem_alloc(hostinfo->length, KM_SLEEP);
294 	if (hostinfo->length > ISCSIT_MAX_HOSTNAME_LEN)
295 		hostinfo->length = ISCSIT_MAX_HOSTNAME_LEN;
296 	(void) strlcpy(isns_eid, hostinfo->fqhn, hostinfo->length);
297 	avl_create(&isns_target_list, isnst_tgt_avl_compare,
298 	    sizeof (isns_target_t), offsetof(isns_target_t, target_node));
299 	/*
300 	 * The iscsi global lock is not held here, but it is held when
301 	 * isnst_start is called, so we need to acquire it only in this
302 	 * case.
303 	 */
304 	ISCSIT_GLOBAL_LOCK(RW_READER);
305 	isnst_get_target_list();
306 	ISCSIT_GLOBAL_UNLOCK();
307 
308 	/* initialize isns client */
309 	mutex_init(&isns_monitor_mutex, NULL, MUTEX_DEFAULT, NULL);
310 	mutex_init(&esi.esi_mutex, NULL, MUTEX_DEFAULT, NULL);
311 	isns_monitor_thr_id = NULL;
312 	monitor_idle_interval = ISNS_IDLE_TIME * drv_usectohz(1000000);
313 	cv_init(&isns_idle_cv, NULL, CV_DEFAULT, NULL);
314 	cv_init(&esi.esi_cv, NULL, CV_DEFAULT, NULL);
315 	xid = 0;
316 	ISNS_GLOBAL_UNLOCK();
317 
318 	return (0);
319 }
320 
321 void
322 iscsit_isns_fini()
323 {
324 	ISNS_GLOBAL_LOCK();
325 	iscsit_set_isns(B_FALSE);
326 	mutex_destroy(&isns_monitor_mutex);
327 	cv_destroy(&isns_idle_cv);
328 	mutex_destroy(&esi.esi_mutex);
329 	cv_destroy(&esi.esi_cv);
330 
331 	/*
332 	 * Free our EID and target list.
333 	 */
334 
335 	if (isns_eid) {
336 		kmem_free(isns_eid, strlen(isns_eid) + 1);
337 		isns_eid = NULL;
338 	}
339 
340 	iscsit_global.global_isns_cfg.isns_state = B_FALSE;
341 	avl_destroy(&isns_target_list);
342 	list_destroy(&iscsit_global.global_isns_cfg.isns_svrs);
343 	list_destroy(&portal_list);
344 	portal_list_count = 0;
345 	ISNS_GLOBAL_UNLOCK();
346 
347 	mutex_destroy(&iscsit_global.global_isns_cfg.isns_mutex);
348 }
349 
350 static void
351 iscsit_set_isns(boolean_t state)
352 {
353 	iscsit_isns_svr_t	*svr;
354 
355 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
356 
357 	/*
358 	 * Update state and isns stop flag
359 	 */
360 	if (iscsit_global.global_isns_cfg.isns_state != state) {
361 		/* reset retry count for all servers */
362 		for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
363 		    svr != NULL;
364 		    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs,
365 		    svr)) {
366 			svr->svr_retry_count = 0;
367 		}
368 
369 		iscsit_global.global_isns_cfg.isns_state = state;
370 
371 		if (state) {
372 			isnst_start();
373 		} else {
374 			isnst_stop();
375 		}
376 	}
377 }
378 
379 int
380 iscsit_add_isns(it_portal_t *cfg_svr)
381 {
382 	iscsit_isns_svr_t *svr;
383 
384 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
385 
386 	svr = kmem_zalloc(sizeof (iscsit_isns_svr_t), KM_SLEEP);
387 	bcopy(&cfg_svr->portal_addr, &svr->svr_sa,
388 	    sizeof (struct sockaddr_storage));
389 
390 	/* put it on the global isns server list */
391 	list_insert_tail(&iscsit_global.global_isns_cfg.isns_svrs, svr);
392 
393 	/*
394 	 * Register targets with this server if iSNS is enabled.
395 	 */
396 
397 	if (iscsit_global.global_isns_cfg.isns_state &&
398 	    (isnst_update_one_server(svr, NULL, ISNS_REGISTER_ALL) == 0)) {
399 		isnst_set_server_status(svr, B_TRUE);
400 	}
401 
402 	return (0);
403 }
404 
405 void
406 iscsit_delete_isns(iscsit_isns_svr_t *svr)
407 {
408 	boolean_t	need_dereg;
409 
410 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
411 
412 	list_remove(&iscsit_global.global_isns_cfg.isns_svrs, svr);
413 
414 	/* talk to this server if isns monitor is running */
415 	mutex_enter(&isns_monitor_mutex);
416 	if (isns_monitor_thr_id != NULL) {
417 		need_dereg = B_TRUE;
418 	} else {
419 		need_dereg = B_FALSE;
420 	}
421 	mutex_exit(&isns_monitor_mutex);
422 
423 	if (need_dereg) {
424 		(void) isnst_monitor_one_server(svr, B_FALSE);
425 	}
426 
427 	/* free the memory */
428 	kmem_free(svr, sizeof (*svr));
429 }
430 
431 static iscsit_isns_svr_t *
432 iscsit_isns_svr_lookup(struct sockaddr_storage *sa)
433 {
434 	iscsit_isns_svr_t	*svr;
435 	it_portal_t		portal1;
436 
437 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
438 
439 	bcopy(sa, &portal1.portal_addr, sizeof (struct sockaddr_storage));
440 
441 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
442 	    svr != NULL;
443 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
444 		if (it_sa_compare(&svr->svr_sa, sa) == 0)
445 			return (svr);
446 	}
447 
448 	return (NULL);
449 }
450 
451 int
452 iscsit_isns_register(iscsit_tgt_t *target)
453 {
454 	int rc = 0;
455 
456 	ISNS_GLOBAL_LOCK();
457 
458 	(void) isnst_add_to_target_list(target);
459 
460 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
461 		ISNS_GLOBAL_UNLOCK();
462 		return (rc);
463 	}
464 
465 	rc = isnst_update_target(target, ISNS_REGISTER_TARGET);
466 
467 	ISNS_GLOBAL_UNLOCK();
468 
469 	return (rc);
470 }
471 
472 int
473 iscsit_isns_deregister(iscsit_tgt_t *target)
474 {
475 	void				*itarget;
476 	isns_target_t			tmptgt;
477 	iscsit_isns_svr_t		*svr;
478 	list_t				*global;
479 
480 	ISNS_GLOBAL_LOCK();
481 
482 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
483 		tmptgt.target = target;
484 
485 		if ((itarget = avl_find(&isns_target_list, &tmptgt, NULL))
486 		    != NULL) {
487 			avl_remove(&isns_target_list, itarget);
488 			kmem_free(itarget, sizeof (isns_target_t));
489 		}
490 
491 		ISNS_GLOBAL_UNLOCK();
492 		return (0);
493 	}
494 
495 	/*
496 	 * Don't worry about dereg failures.
497 	 */
498 	(void) isnst_update_target(target, ISNS_DEREGISTER_TARGET);
499 
500 	/*
501 	 * Remove the target from the list regardless of the status.
502 	 */
503 
504 	tmptgt.target = target;
505 	if ((itarget = avl_find(&isns_target_list, &tmptgt, NULL)) != NULL) {
506 		avl_remove(&isns_target_list, itarget);
507 		kmem_free(itarget, sizeof (isns_target_t));
508 	}
509 
510 	/*
511 	 * If there are no more targets, mark the server as
512 	 * unregistered.
513 	 */
514 
515 	if (avl_numnodes(&isns_target_list) == 0) {
516 		global = &iscsit_global.global_isns_cfg.isns_svrs;
517 		for (svr = list_head(global); svr != NULL;
518 		    svr = list_next(global, svr)) {
519 			isnst_set_server_status(svr, B_FALSE);
520 		}
521 	}
522 
523 	ISNS_GLOBAL_UNLOCK();
524 
525 	return (0);
526 }
527 
528 /*
529  * This function is called by iscsit when a target's configuration
530  * has changed.
531  */
532 
533 void
534 iscsit_isns_target_update(iscsit_tgt_t *target)
535 {
536 	ISNS_GLOBAL_LOCK();
537 
538 	if (iscsit_global.global_isns_cfg.isns_state == B_FALSE) {
539 		ISNS_GLOBAL_UNLOCK();
540 		return;
541 	}
542 
543 	(void) isnst_update_target(target, ISNS_UPDATE_TARGET);
544 
545 	ISNS_GLOBAL_UNLOCK();
546 }
547 
548 static void
549 isnst_start()
550 {
551 	ISNST_LOG(CE_NOTE, "**** isnst_start");
552 
553 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
554 
555 	/*
556 	 * Get initial target list
557 	 */
558 	isnst_get_target_list();
559 
560 	/*
561 	 * Start ESI thread(s)
562 	 */
563 	isnst_esi_start();
564 
565 	/*
566 	 * Create a thread for monitoring server communications
567 	 */
568 	isnst_monitor_start();
569 }
570 
571 static void
572 isnst_stop()
573 {
574 	isns_target_t *itarget;
575 
576 	ISNST_LOG(CE_NOTE, "**** isnst_stop");
577 
578 	ISNS_GLOBAL_UNLOCK();
579 	isnst_esi_stop();
580 	isnst_monitor_stop();
581 	ISNS_GLOBAL_LOCK();
582 	while ((itarget = avl_first(&isns_target_list)) != NULL) {
583 		avl_remove(&isns_target_list, itarget);
584 		kmem_free(itarget, sizeof (isns_target_t));
585 	}
586 }
587 
588 static void
589 isnst_monitor_start(void)
590 {
591 	ISNST_LOG(CE_NOTE, "isnst_monitor_start");
592 
593 	mutex_enter(&isns_monitor_mutex);
594 	isns_monitor_thr_id = thread_create(NULL, 0,
595 	    isnst_monitor, NULL, 0, &p0, TS_RUN, minclsyspri);
596 	while (!isns_monitor_thr_running)
597 		cv_wait(&isns_idle_cv, &isns_monitor_mutex);
598 	mutex_exit(&isns_monitor_mutex);
599 }
600 
601 static void
602 isnst_monitor_stop(void)
603 {
604 	ISNST_LOG(CE_NOTE, "isnst_monitor_stop");
605 
606 	mutex_enter(&isns_monitor_mutex);
607 	if (isns_monitor_thr_running) {
608 		isns_monitor_thr_running = B_FALSE;
609 		cv_signal(&isns_idle_cv);
610 		mutex_exit(&isns_monitor_mutex);
611 
612 		thread_join(isns_monitor_thr_did);
613 		return;
614 	}
615 	mutex_exit(&isns_monitor_mutex);
616 }
617 
618 /*
619  * isnst_update_server_timestamp
620  *
621  * When we receive an ESI request, update the timestamp for the server.
622  * If we don't receive one for the specified period of time, we'll attempt
623  * to re-register.
624  */
625 
626 static void
627 isnst_update_server_timestamp(ksocket_t so)
628 {
629 	iscsit_isns_svr_t	*svr;
630 	struct in_addr		*sin = NULL, *svr_in;
631 	struct in6_addr		*sin6 = NULL, *svr_in6;
632 	struct sockaddr_in6	t_addr;
633 	socklen_t		t_addrlen;
634 
635 	bzero(&t_addr, sizeof (struct sockaddr_in6));
636 	t_addrlen = sizeof (struct sockaddr_in6);
637 	(void) ksocket_getpeername(so, (struct sockaddr *)&t_addr, &t_addrlen,
638 	    CRED());
639 	if (((struct sockaddr *)(&t_addr))->sa_family == AF_INET) {
640 		sin = &((struct sockaddr_in *)((void *)(&t_addr)))->sin_addr;
641 	} else {
642 		sin6 = &(&t_addr)->sin6_addr;
643 	}
644 
645 	/*
646 	 * Find the server and update the timestamp
647 	 */
648 
649 	ISNS_GLOBAL_LOCK();
650 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
651 	    svr != NULL;
652 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
653 		if (sin6 == NULL) {
654 			if (svr->svr_sa.ss_family == AF_INET) {
655 				svr_in = &((struct sockaddr_in *)&svr->svr_sa)->
656 				    sin_addr;
657 				if (bcmp(svr_in, sin, sizeof (in_addr_t))
658 				    == 0) {
659 					break;
660 				}
661 			}
662 		} else {
663 			if (svr->svr_sa.ss_family == AF_INET6) {
664 				svr_in6 = &((struct sockaddr_in6 *)
665 				    &svr->svr_sa)->sin6_addr;
666 				if (bcmp(svr_in6, sin6,
667 				    sizeof (in6_addr_t)) == 0) {
668 					break;
669 				}
670 			}
671 		}
672 	}
673 
674 	if (svr != NULL) {
675 		svr->svr_last_msg = ddi_get_lbolt();
676 	}
677 	ISNS_GLOBAL_UNLOCK();
678 }
679 
680 /*
681  * isnst_monitor
682  *
683  * This function monitors registration status for each server.
684  */
685 
686 
687 static void
688 isnst_monitor_all_servers()
689 {
690 	iscsit_isns_svr_t	*svr;
691 	boolean_t		enabled;
692 	list_t			*svr_list;
693 
694 	svr_list = &iscsit_global.global_isns_cfg.isns_svrs;
695 
696 	ISNS_GLOBAL_LOCK();
697 	enabled = iscsit_global.global_isns_cfg.isns_state;
698 	for (svr = list_head(svr_list); svr != NULL;
699 	    svr = list_next(svr_list, svr)) {
700 		if (isnst_monitor_one_server(svr, enabled) != 0) {
701 			svr->svr_retry_count++;
702 		} else {
703 			svr->svr_retry_count = 0;
704 		}
705 	}
706 	ISNS_GLOBAL_UNLOCK();
707 }
708 
709 /*ARGSUSED*/
710 static void
711 isnst_monitor(void *arg)
712 {
713 	mutex_enter(&isns_monitor_mutex);
714 	cv_signal(&isns_idle_cv);
715 	isns_monitor_thr_did = curthread->t_did;
716 	isns_monitor_thr_running = B_TRUE;
717 
718 	while (isns_monitor_thr_running) {
719 		mutex_exit(&isns_monitor_mutex);
720 
721 		/* Update servers */
722 		isnst_monitor_all_servers();
723 
724 		/*
725 		 * Keep running until isns_monitor_thr_running is set to
726 		 * B_FALSE.
727 		 */
728 		mutex_enter(&isns_monitor_mutex);
729 		DTRACE_PROBE(iscsit__isns__monitor__sleep);
730 		(void) cv_timedwait(&isns_idle_cv, &isns_monitor_mutex,
731 		    ddi_get_lbolt() + monitor_idle_interval);
732 		DTRACE_PROBE1(iscsit__isns__monitor__wakeup,
733 		    boolean_t, isns_monitor_thr_running);
734 	}
735 
736 	mutex_exit(&isns_monitor_mutex);
737 
738 	/* Update the servers one last time for deregistration */
739 	isnst_monitor_all_servers();
740 
741 	/* terminate the thread at the last */
742 	thread_exit();
743 }
744 
745 static int
746 isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled)
747 {
748 	int		rc = 0;
749 	struct sonode	*so;
750 
751 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
752 
753 	/*
754 	 * First, take care of the case where iSNS is no longer enabled.
755 	 *
756 	 * If we're still registered, deregister.  Regardless, mark the
757 	 * server as not registered.
758 	 */
759 
760 	if (enabled == B_FALSE) {
761 		if (svr->svr_registered == B_TRUE) {
762 			/*
763 			 * Doesn't matter if this fails.  We're disabled.
764 			 */
765 			so = isnst_open_so(&svr->svr_sa);
766 			if (so != NULL) {
767 				(void) isnst_update_one_server(svr, NULL,
768 				    ISNS_DEREGISTER_ALL);
769 				isnst_close_so(so);
770 			}
771 		}
772 
773 		isnst_set_server_status(svr, B_FALSE);
774 		return (0);
775 	}
776 
777 	/*
778 	 * If there are no targets, we're done.
779 	 */
780 
781 	if (avl_numnodes(&isns_target_list) == 0) {
782 		return (0);
783 	}
784 
785 	/*
786 	 * At this point, we know iSNS is enabled.
787 	 *
788 	 * If we've received an ESI request from the server recently
789 	 * (within MAX_ESI_INTERVALS * the max interval length),
790 	 * no need to continue.
791 	 */
792 
793 	if (svr->svr_registered == B_TRUE) {
794 		if (ddi_get_lbolt() < (svr->svr_last_msg +
795 		    drv_usectohz(svr->svr_esi_interval * 1000000 *
796 		    MAX_ESI_INTERVALS))) {
797 			return (0);
798 		}
799 	} else {
800 		/*
801 		 * We're not registered... Try to register now.
802 		 */
803 		if ((rc = isnst_update_one_server(svr, NULL,
804 		    ISNS_REGISTER_ALL)) == 0) {
805 			isnst_set_server_status(svr, B_TRUE);
806 		}
807 	}
808 
809 	return (rc);
810 }
811 
812 static int
813 isnst_update_target(iscsit_tgt_t *target, isns_reg_type_t reg)
814 {
815 	iscsit_isns_svr_t	*svr;
816 	int			rc = 0, curr_rc;
817 
818 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
819 	ASSERT(iscsit_global.global_isns_cfg.isns_state == B_TRUE);
820 
821 	for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
822 	    svr != NULL;
823 	    svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
824 		/*
825 		 * Only return success if they all succeed.  Let the caller
826 		 * deal with any failure.
827 		 */
828 
829 		curr_rc = isnst_update_one_server(svr, target, reg);
830 
831 		if (curr_rc == 0) {
832 			if (reg == ISNS_REGISTER_TARGET) {
833 				isnst_set_server_status(svr, B_TRUE);
834 			}
835 		} else if (rc == 0) {
836 			rc = curr_rc;
837 		}
838 	}
839 
840 	return (rc);
841 }
842 
843 static int
844 isnst_update_one_server(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
845     isns_reg_type_t reg)
846 {
847 	int rc = 0;
848 
849 	switch (reg) {
850 	case ISNS_DEREGISTER_TARGET:
851 		rc = isnst_deregister(svr, target->target_name);
852 		break;
853 
854 	case ISNS_DEREGISTER_ALL:
855 		rc = isnst_deregister(svr, NULL);
856 		break;
857 
858 	case ISNS_UPDATE_TARGET:
859 	case ISNS_REGISTER_TARGET:
860 		rc = isnst_register(svr, target, reg);
861 		break;
862 
863 	case ISNS_REGISTER_ALL:
864 		rc = isnst_register(svr, NULL, reg);
865 		break;
866 
867 	default:
868 		ASSERT(0);
869 		/* NOTREACHED */
870 	}
871 
872 	return (rc);
873 }
874 
875 /*
876  * isnst_retry_registration
877  *
878  * This function checks the return value from a registration pdu and
879  * determines whether or not we should retry this request.  If the
880  * request is retried, it will do so as an "update", which means we
881  * re-register everything.
882  */
883 
884 static boolean_t
885 isnst_retry_registration(int rsp_status_code)
886 {
887 	boolean_t retry;
888 
889 	/*
890 	 * Currently, we will attempt to retry for "Invalid Registration",
891 	 * "Source Unauthorized", or "Busy" errors.  Any other errors should
892 	 * be handled by the caller if necessary.
893 	 */
894 
895 	switch (rsp_status_code) {
896 	case ISNS_RSP_INVALID_REGIS:
897 	case ISNS_RSP_SRC_UNAUTHORIZED:
898 	case ISNS_RSP_BUSY:
899 		retry = B_TRUE;
900 		break;
901 	default:
902 		retry = B_FALSE;
903 		break;
904 	}
905 
906 	return (retry);
907 }
908 
909 static int
910 isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
911     isns_reg_type_t regtype)
912 {
913 	struct sonode	*so;
914 	int		rc = 0;
915 	isns_pdu_t	*pdu, *rsp;
916 	size_t		pdu_size, rsp_size;
917 	isns_target_t	*itarget, tmptgt;
918 	boolean_t	retry_reg = B_TRUE;
919 
920 	/*
921 	 * Registration is a tricky thing.  In order to keep things simple,
922 	 * we don't want to keep track of which targets are registered to
923 	 * which server.  We rely on the target state machine to tell us
924 	 * when a target is online or offline, which prompts us to either
925 	 * register or deregister that target.
926 	 *
927 	 * When iscsit_isns_init is called, get a list of targets.  Those that
928 	 * are online will need to be registered.  In this case, target
929 	 * will be NULL.
930 	 *
931 	 * What this means is that if svr_registered == B_FALSE, that's
932 	 * when we'll register the network entity as well.
933 	 */
934 
935 	if ((avl_numnodes(&isns_target_list) == 0) && (target == NULL)) {
936 		return (0);
937 	}
938 
939 	/*
940 	 * If the target is already registered and we're not doing an
941 	 * update registration, just return.
942 	 */
943 
944 	if (target != NULL) {
945 		tmptgt.target = target;
946 		itarget = avl_find(&isns_target_list, &tmptgt, NULL);
947 		ASSERT(itarget);
948 		if ((itarget->target_registered == B_TRUE) &&
949 		    (regtype != ISNS_UPDATE_TARGET)) {
950 			return (0);
951 		}
952 	}
953 
954 	/* create TCP connection to the isns server */
955 	so = isnst_open_so(&svr->svr_sa);
956 
957 	if (so == NULL) {
958 		isnst_set_server_status(svr, B_FALSE);
959 		return (-1);
960 	}
961 
962 	while (retry_reg) {
963 		pdu_size = isnst_make_reg_pdu(&pdu, target, svr->svr_registered,
964 		    regtype);
965 		if (pdu_size == 0) {
966 			isnst_close_so(so);
967 			return (-1);
968 		}
969 
970 		rc = isnst_send_pdu(so, pdu);
971 		if (rc != 0) {
972 			kmem_free(pdu, pdu_size);
973 			isnst_close_so(so);
974 			return (rc);
975 		}
976 
977 		rsp_size = isnst_rcv_pdu(so, &rsp);
978 		if (rsp_size == 0) {
979 			kmem_free(pdu, pdu_size);
980 			isnst_close_so(so);
981 			return (-1);
982 		}
983 
984 		rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
985 
986 		/*
987 		 * If we got a registration error, the server may be out of
988 		 * sync.  In this case, we may re-try the registration as
989 		 * a "target update", which causes us to re-register everything.
990 		 */
991 
992 		if ((retry_reg = isnst_retry_registration(rc)) == B_TRUE) {
993 			if (regtype == ISNS_UPDATE_TARGET) {
994 				/*
995 				 * If registration failed on an update, there
996 				 * is something terribly wrong, possibly with
997 				 * the server.
998 				 */
999 				rc = -1;
1000 				retry_reg = B_FALSE;
1001 				isnst_set_server_status(svr, B_FALSE);
1002 			} else {
1003 				regtype = ISNS_UPDATE_TARGET;
1004 			}
1005 		}
1006 
1007 		kmem_free(pdu, pdu_size);
1008 		kmem_free(rsp, rsp_size);
1009 	}
1010 
1011 	isnst_close_so(so);
1012 
1013 	/*
1014 	 * If it succeeded, mark all registered targets as such
1015 	 */
1016 	if (rc == 0) {
1017 		if ((target != NULL) && (regtype != ISNS_UPDATE_TARGET)) {
1018 			/* itarget initialized above */
1019 			itarget->target_registered = B_TRUE;
1020 		} else {
1021 			itarget = avl_first(&isns_target_list);
1022 			while (itarget) {
1023 				itarget->target_registered = B_TRUE;
1024 				itarget = AVL_NEXT(&isns_target_list, itarget);
1025 			}
1026 		}
1027 	}
1028 
1029 	return (rc);
1030 }
1031 
1032 static isns_portal_list_t *
1033 isnst_lookup_portal(struct sockaddr_storage *p, isns_portal_list_t *last_portal)
1034 {
1035 	isns_portal_list_t *portal;
1036 
1037 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1038 
1039 	portal = (last_portal == NULL) ?
1040 	    list_head(&portal_list) : list_next(&portal_list, last_portal);
1041 
1042 	while (portal != NULL) {
1043 		if (idm_ss_compare(p, &portal->portal_addr,
1044 		    B_TRUE /* v4_mapped_as_v4 */) == 0) {
1045 			return (portal);
1046 		}
1047 		portal = list_next(&portal_list, portal);
1048 	}
1049 
1050 	return (NULL);
1051 }
1052 
1053 static boolean_t
1054 isnst_portal_exists(struct sockaddr_storage *p)
1055 {
1056 	return ((isnst_lookup_portal(p, NULL) != NULL) ||
1057 	    (default_portal_online && isnst_lookup_default_portal(p)));
1058 }
1059 
1060 static void
1061 isnst_add_portal(iscsit_portal_t *portal)
1062 {
1063 	isns_portal_list_t	*new_portal;
1064 
1065 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1066 
1067 	new_portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
1068 	new_portal->portal_addr = portal->portal_addr;
1069 	new_portal->portal_iscsit = portal;
1070 	list_insert_tail(&portal_list, new_portal);
1071 	portal->portal_isns = new_portal;
1072 	portal_list_count++;
1073 
1074 }
1075 
1076 static void
1077 isnst_remove_portal(iscsit_portal_t *portal)
1078 {
1079 	ASSERT(portal->portal_isns != NULL);
1080 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1081 
1082 	list_remove(&portal_list, portal->portal_isns);
1083 	kmem_free(portal->portal_isns, sizeof (isns_portal_list_t));
1084 	portal_list_count--;
1085 }
1086 
1087 static isns_target_t *
1088 isnst_add_to_target_list(iscsit_tgt_t *target)
1089 {
1090 	isns_target_t *itarget, tmptgt;
1091 
1092 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1093 
1094 	/*
1095 	 * Make sure this target isn't already in our list.  If it is,
1096 	 * perhaps it has just moved from offline to online.
1097 	 */
1098 
1099 	tmptgt.target = target;
1100 	if ((itarget = (isns_target_t *)avl_find(&isns_target_list,
1101 	    &tmptgt, NULL)) == NULL) {
1102 		itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP);
1103 
1104 		itarget->target = target;
1105 		avl_add(&isns_target_list, itarget);
1106 	}
1107 
1108 	return (itarget);
1109 }
1110 
1111 static size_t
1112 isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
1113     boolean_t svr_registered, isns_reg_type_t regtype)
1114 {
1115 	idm_addr_list_t		*default_portal_list = NULL;
1116 	uint32_t		default_portal_list_size;
1117 	size_t			pdu_size;
1118 	char			*str;
1119 	int			len;
1120 	isns_target_t		*itarget;
1121 	iscsit_tgt_t		*src;
1122 	boolean_t		reg_all = B_FALSE;
1123 	uint16_t		flags = 0;
1124 
1125 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
1126 
1127 	/*
1128 	 * If any targets are using the default portal then get the global
1129 	 * list of portals.
1130 	 */
1131 	if (default_portal_online) {
1132 		default_portal_list_size = idm_get_ipaddr(&default_portal_list);
1133 
1134 		if (default_portal_list_size == 0) {
1135 			/*
1136 			 * If the default portal is online, then there should
1137 			 * be at least one default portal.
1138 			 */
1139 			return (0);
1140 		}
1141 	}
1142 
1143 	/*
1144 	 * Find a source attribute for this registration.
1145 	 *
1146 	 * If we're already registered, registering for the first time, or
1147 	 * updating a target, we'll use the target_name of the first target
1148 	 * in our list.
1149 	 *
1150 	 * The alternate case is that we're registering for the first time,
1151 	 * but target is non-NULL.  In that case, we have no targets in our
1152 	 * list yet, so we use the passed in target's name.
1153 	 */
1154 
1155 	if (svr_registered || (target == NULL) ||
1156 	    (regtype == ISNS_UPDATE_TARGET)) {
1157 		ASSERT(avl_numnodes(&isns_target_list) != 0);
1158 		itarget = (isns_target_t *)avl_first(&isns_target_list);
1159 		src = itarget->target;
1160 	} else {
1161 		src = target;
1162 	}
1163 
1164 	/*
1165 	 * No target means we're registering everything.  A regtype of
1166 	 * ISNS_UPDATE_TARGET means we're re-registering everything.
1167 	 * Whether we're registering or re-registering depends on if
1168 	 * we're already registered.
1169 	 */
1170 
1171 	if ((target == NULL) || (regtype == ISNS_UPDATE_TARGET) ||
1172 	    ((regtype == ISNS_REGISTER_TARGET) &&
1173 	    default_portal_state_change)) {
1174 		reg_all = B_TRUE;
1175 		target = src;	/* This will be the 1st tgt in our list */
1176 		default_portal_state_change = B_FALSE;
1177 
1178 		/*
1179 		 * If we're already registered, this will be a replacement
1180 		 * registration.  In this case, we need to make sure our
1181 		 * source attribute is an already registered target.
1182 		 */
1183 		if (svr_registered) {
1184 			flags = ISNS_FLAG_REPLACE_REG;
1185 			while (itarget->target_registered == B_FALSE) {
1186 				itarget = AVL_NEXT(&isns_target_list,
1187 				    itarget);
1188 			}
1189 			src = itarget->target;
1190 			/* Reset itarget to the beginning of our list */
1191 			itarget = (isns_target_t *)avl_first(&isns_target_list);
1192 		}
1193 	}
1194 
1195 	pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_REG, pdu, flags);
1196 	if (pdu_size == 0) {
1197 		if (default_portal_list)
1198 			kmem_free(default_portal_list,
1199 			    default_portal_list_size);
1200 		return (0);
1201 	}
1202 
1203 	len = strlen(src->target_name) + 1;
1204 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1205 	    len, src->target_name, 0) != 0) {
1206 		goto pdu_error;
1207 	}
1208 
1209 	/*
1210 	 * Message Key Attributes - EID
1211 	 */
1212 	len = strlen(isns_eid) + 1;
1213 
1214 	if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1215 	    len, isns_eid, 0) != 0) {
1216 		goto pdu_error;
1217 	}
1218 
1219 	/* Delimiter */
1220 	if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1221 	    0, 0, 0) != 0) {
1222 		goto pdu_error;
1223 	}
1224 
1225 	/*
1226 	 * Operating Attributes
1227 	 */
1228 	if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID, len,
1229 	    isns_eid, 0) != 0) {
1230 		goto pdu_error;
1231 	}
1232 
1233 	/* ENTITY Protocol - Section 6.2.2 */
1234 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID,
1235 	    4, 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1236 		goto pdu_error;
1237 	}
1238 
1239 	/*
1240 	 * Network entity portal information - only on the first registration.
1241 	 */
1242 	if (!svr_registered || (flags & ISNS_FLAG_REPLACE_REG)) {
1243 		if (isnst_reg_pdu_add_entity_portals(*pdu, pdu_size,
1244 		    default_portal_list) != 0) {
1245 			goto pdu_error;
1246 		}
1247 	}
1248 
1249 	do {
1250 		/* Hold the target mutex */
1251 		mutex_enter(&target->target_mutex);
1252 
1253 		/* iSCSI Name - Section 6.4.1 */
1254 		str = target->target_name;
1255 		len = strlen(str) + 1;
1256 		if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1257 		    len, str, 0) != 0) {
1258 			mutex_exit(&target->target_mutex);
1259 			goto pdu_error;
1260 		}
1261 
1262 		/* iSCSI Node Type */
1263 		if (isnst_add_attr(*pdu, pdu_size,
1264 		    ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 0,
1265 		    ISNS_TARGET_NODE_TYPE) != 0) {
1266 			mutex_exit(&target->target_mutex);
1267 			goto pdu_error;
1268 		}
1269 
1270 		/* iSCSI Alias */
1271 		if (nvlist_lookup_string(target->target_props, PROP_ALIAS,
1272 		    &str) == 0) {
1273 			/* Found alias in property list */
1274 			len = strlen(str) + 1;
1275 			if (isnst_add_attr(*pdu, pdu_size,
1276 			    ISNS_ISCSI_ALIAS_ATTR_ID, len, str, 0) != 0) {
1277 				mutex_exit(&target->target_mutex);
1278 				goto pdu_error;
1279 			}
1280 		}
1281 
1282 		if (isnst_reg_pdu_add_pg(*pdu, pdu_size, target,
1283 		    default_portal_list) != 0) {
1284 			mutex_exit(&target->target_mutex);
1285 			goto pdu_error;
1286 		}
1287 
1288 		mutex_exit(&target->target_mutex);
1289 
1290 		if (reg_all) {
1291 			itarget = AVL_NEXT(&isns_target_list, itarget);
1292 			if (itarget) {
1293 				target = itarget->target;
1294 			} else {
1295 				target = NULL;
1296 			}
1297 		}
1298 	} while ((reg_all == B_TRUE) && (target != NULL));
1299 
1300 	if (default_portal_list)
1301 		kmem_free(default_portal_list, default_portal_list_size);
1302 
1303 	return (pdu_size);
1304 
1305 pdu_error:
1306 	/* packet too large, no memory */
1307 	kmem_free(*pdu, pdu_size);
1308 	*pdu = NULL;
1309 	if (default_portal_list)
1310 		kmem_free(default_portal_list, default_portal_list_size);
1311 
1312 	return (0);
1313 }
1314 
1315 
1316 static int
1317 isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size,
1318     idm_addr_list_t *default_portal_list)
1319 {
1320 	isns_portal_list_t	*portal;
1321 	idm_addr_t		*dportal;
1322 	struct sockaddr_storage	ss;
1323 	struct sockaddr_in	*sin;
1324 	struct sockaddr_in6	*sin6;
1325 	int			idx;
1326 	int			dp_addr_size;
1327 
1328 	if (default_portal_list != NULL) {
1329 		for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
1330 			dportal = &default_portal_list->al_addrs[idx];
1331 
1332 			/* Build sockaddr_storage for this portal */
1333 			bzero(&ss, sizeof (ss));
1334 			dp_addr_size = dportal->a_addr.i_insize;
1335 			if (dp_addr_size == sizeof (struct in_addr)) {
1336 				/* IPv4 */
1337 				ss.ss_family = AF_INET;
1338 				sin = (struct sockaddr_in *)&ss;
1339 				sin->sin_port = htons(ISCSI_LISTEN_PORT);
1340 				bcopy(&dportal->a_addr.i_addr.in4,
1341 				    &sin->sin_addr, sizeof (struct in_addr));
1342 			} else if (dp_addr_size == sizeof (struct in6_addr)) {
1343 				ss.ss_family = AF_INET6;
1344 				sin6 = (struct sockaddr_in6 *)&ss;
1345 				sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
1346 				bcopy(&dportal->a_addr.i_addr.in6,
1347 				    &sin6->sin6_addr, sizeof (struct in6_addr));
1348 			} else {
1349 				continue;
1350 			}
1351 
1352 			if (isnst_add_portal_attr(pdu, pdu_size,
1353 			    ISNS_PORTAL_IP_ADDR_ATTR_ID,
1354 			    ISNS_PORTAL_PORT_ATTR_ID,
1355 			    &ss, B_TRUE /* ESI info */) != 0) {
1356 				return (-1);
1357 			}
1358 
1359 		}
1360 	} else {
1361 		portal = list_head(&portal_list);
1362 
1363 		while (portal != NULL) {
1364 			if (isnst_add_portal_attr(pdu, pdu_size,
1365 			    ISNS_PORTAL_IP_ADDR_ATTR_ID,
1366 			    ISNS_PORTAL_PORT_ATTR_ID,
1367 			    &portal->portal_addr, B_TRUE /* ESI info */) != 0) {
1368 				return (-1);
1369 			}
1370 
1371 			portal = list_next(&portal_list, portal);
1372 		}
1373 	}
1374 
1375 	return (0);
1376 }
1377 
1378 
1379 static int
1380 isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, iscsit_tgt_t *target,
1381     idm_addr_list_t *default_portal_list)
1382 {
1383 	iscsit_tpgt_t		*tpgt;
1384 	iscsit_tpg_t		*tpg;
1385 	iscsit_portal_t		*tp;
1386 	int			rval = 0;
1387 	boolean_t		use_default = B_FALSE;
1388 
1389 
1390 	tpgt = avl_first(&target->target_tpgt_list);
1391 	ASSERT(tpgt != NULL);
1392 	do {
1393 		/*
1394 		 * No need to explicitly register default PG.  Any target
1395 		 * should have either an explicit portal list or
1396 		 * one and only one portal representing the default portal.
1397 		 */
1398 		ASSERT((avl_numnodes(&target->target_tpgt_list) == 1) ||
1399 		    (tpgt->tpgt_tag != ISCSIT_DEFAULT_TPGT));
1400 		if (tpgt->tpgt_tag == ISCSIT_DEFAULT_TPGT) {
1401 			use_default = B_TRUE;
1402 			tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
1403 			continue;
1404 		}
1405 
1406 		tpg = tpgt->tpgt_tpg;
1407 		mutex_enter(&tpg->tpg_mutex);
1408 
1409 		tp = avl_first(&tpg->tpg_portal_list);
1410 
1411 		/* Portal Group Tag */
1412 		if (isnst_add_attr(pdu, pdu_size,
1413 		    ISNS_PG_TAG_ATTR_ID, 4, 0, tpgt->tpgt_tag) != 0) {
1414 			mutex_exit(&tpg->tpg_mutex);
1415 			rval = 1;
1416 			goto pg_done;
1417 		}
1418 
1419 		ASSERT(tp != NULL);
1420 		do {
1421 			if (isnst_add_portal_attr(pdu, pdu_size,
1422 			    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
1423 			    ISNS_PG_PORTAL_PORT_ATTR_ID,
1424 			    &tp->portal_addr, B_FALSE /* ESI */) != 0) {
1425 				mutex_exit(&tpg->tpg_mutex);
1426 				rval = 1;
1427 				goto pg_done;
1428 			}
1429 
1430 			tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
1431 		} while (tp != NULL);
1432 
1433 		mutex_exit(&tpg->tpg_mutex);
1434 		tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
1435 	} while (tpgt != NULL);
1436 
1437 	/*
1438 	 * If we are not using the default portal group we need to create
1439 	 * a NULL PG tag indicating some of the default portals should be
1440 	 * not be used to access this target.
1441 	 */
1442 	if (!use_default) {
1443 		if (isnst_add_null_pg(pdu, pdu_size, target,
1444 		    default_portal_list) != 0) {
1445 			rval = 1;
1446 			goto pg_done;
1447 		}
1448 	}
1449 
1450 pg_done:
1451 	return (rval);
1452 }
1453 
1454 static int
1455 isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
1456     iscsit_tgt_t *tgt, idm_addr_list_t *default_portal_list)
1457 {
1458 	isns_portal_list_t	*portal;
1459 	idm_addr_t		*dportal;
1460 	iscsit_portal_t		*iscsit_portal;
1461 	iscsit_tpgt_t		*iscsit_tpgt;
1462 	struct sockaddr_storage	ss;
1463 	struct sockaddr_in	*sin;
1464 	struct sockaddr_in6	*sin6;
1465 	int			idx;
1466 	int			dp_addr_size;
1467 	boolean_t		null_pg_tag = B_FALSE;
1468 
1469 	/*
1470 	 * Register all entity portals that aren't bound to this target in the
1471 	 * null pg.
1472 	 */
1473 	if (default_portal_list != NULL) {
1474 		for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
1475 			dportal = &default_portal_list->al_addrs[idx];
1476 
1477 			/* Build sockaddr_storage for this portal */
1478 			bzero(&ss, sizeof (ss));
1479 			dp_addr_size = dportal->a_addr.i_insize;
1480 			if (dp_addr_size == sizeof (struct in_addr)) {
1481 				/* IPv4 */
1482 				ss.ss_family = AF_INET;
1483 				sin = (struct sockaddr_in *)&ss;
1484 				sin->sin_port = htons(ISCSI_LISTEN_PORT);
1485 				bcopy(&dportal->a_addr.i_addr.in4,
1486 				    &sin->sin_addr, sizeof (struct in_addr));
1487 			} else if (dp_addr_size == sizeof (struct in6_addr)) {
1488 				ss.ss_family = AF_INET6;
1489 				sin6 = (struct sockaddr_in6 *)&ss;
1490 				sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
1491 				bcopy(&dportal->a_addr.i_addr.in6,
1492 				    &sin6->sin6_addr, sizeof (struct in6_addr));
1493 			} else {
1494 				continue;
1495 			}
1496 
1497 			iscsit_portal = iscsit_tgt_lookup_portal(tgt,
1498 			    &ss, &iscsit_tpgt);
1499 			if (iscsit_portal == NULL) {
1500 				/*
1501 				 * If this is the first NULL PG portal, then
1502 				 * write the NULL PG tag first.
1503 				 */
1504 				if (!null_pg_tag) {
1505 					if (isnst_add_attr(pdu, pdu_size,
1506 					    ISNS_PG_TAG_ATTR_ID,
1507 					    0, 0, 0) != 0) {
1508 						return (-1);
1509 					}
1510 					null_pg_tag = B_TRUE;
1511 				}
1512 				if (isnst_add_portal_attr(pdu, pdu_size,
1513 				    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
1514 				    ISNS_PG_PORTAL_PORT_ATTR_ID,
1515 				    &ss, B_FALSE) != 0) {
1516 					return (-1);
1517 				}
1518 			} else {
1519 				iscsit_tpgt_rele(iscsit_tpgt);
1520 				iscsit_portal_rele(iscsit_portal);
1521 			}
1522 		}
1523 	} else {
1524 		portal = list_head(&portal_list);
1525 
1526 		while (portal != NULL) {
1527 			iscsit_portal = iscsit_tgt_lookup_portal(tgt,
1528 			    &portal->portal_addr, &iscsit_tpgt);
1529 			if (iscsit_portal == NULL) {
1530 				/*
1531 				 * If this is the first NULL PG portal, then
1532 				 * write the NULL PG tag first.
1533 				 */
1534 				if (!null_pg_tag) {
1535 					if (isnst_add_attr(pdu, pdu_size,
1536 					    ISNS_PG_TAG_ATTR_ID,
1537 					    0, 0, 0) != 0) {
1538 						return (-1);
1539 					}
1540 					null_pg_tag = B_TRUE;
1541 				}
1542 				if (isnst_add_portal_attr(pdu, pdu_size,
1543 				    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
1544 				    ISNS_PG_PORTAL_PORT_ATTR_ID,
1545 				    &portal->portal_addr, B_FALSE) != 0) {
1546 					return (-1);
1547 				}
1548 			} else {
1549 				iscsit_tpgt_rele(iscsit_tpgt);
1550 				iscsit_portal_rele(iscsit_portal);
1551 			}
1552 
1553 			portal = list_next(&portal_list, portal);
1554 		}
1555 	}
1556 
1557 	return (0);
1558 }
1559 
1560 
1561 static int
1562 isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
1563     uint32_t ip_attr_id, uint32_t port_attr_id,
1564     struct sockaddr_storage *ss, boolean_t esi_info)
1565 {
1566 	struct sockaddr_in	*in;
1567 	struct sockaddr_in6	*in6;
1568 	uint32_t		attr_numeric_data;
1569 	void			*inaddrp;
1570 
1571 	in = (struct sockaddr_in *)ss;
1572 	in6 = (struct sockaddr_in6 *)ss;
1573 
1574 	ASSERT((ss->ss_family == AF_INET) || (ss->ss_family == AF_INET6));
1575 
1576 	if (ss->ss_family == AF_INET) {
1577 		attr_numeric_data = sizeof (in_addr_t);
1578 		inaddrp = (void *)&in->sin_addr;
1579 	} else if (ss->ss_family == AF_INET6) {
1580 		attr_numeric_data = sizeof (in6_addr_t);
1581 		inaddrp = (void *)&in6->sin6_addr;
1582 	}
1583 
1584 	/* Portal Group Portal IP Address */
1585 	if (isnst_add_attr(pdu, pdu_size, ip_attr_id,
1586 	    16, inaddrp, attr_numeric_data) != 0) {
1587 		return (1);
1588 	}
1589 
1590 	/* Portal Group Portal Port */
1591 	if (isnst_add_attr(pdu, pdu_size, port_attr_id,
1592 	    4, 0, ntohs(in->sin_port)) != 0) {
1593 		return (1);
1594 	}
1595 
1596 	mutex_enter(&esi.esi_mutex);
1597 	if (esi_info && esi.esi_valid) {
1598 		/* ESI interval and port */
1599 		if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_INTERVAL_ATTR_ID, 4,
1600 		    NULL, 20) != 0) {
1601 			return (1);
1602 		}
1603 
1604 		if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4,
1605 		    NULL, esi.esi_port) != 0) {
1606 			return (1);
1607 		}
1608 	}
1609 	mutex_exit(&esi.esi_mutex);
1610 
1611 	return (0);
1612 }
1613 
1614 static int
1615 isnst_deregister(iscsit_isns_svr_t *svr, char *node)
1616 {
1617 	int		rc;
1618 	isns_pdu_t	*pdu, *rsp;
1619 	size_t		pdu_size, rsp_size;
1620 	struct sonode	*so;
1621 
1622 	if ((svr->svr_registered == B_FALSE) ||
1623 	    (avl_numnodes(&isns_target_list) == 0)) {
1624 		return (0);
1625 	}
1626 
1627 	so = isnst_open_so(&svr->svr_sa);
1628 
1629 	if (so == NULL) {
1630 		return (-1);
1631 	}
1632 
1633 	pdu_size = isnst_make_dereg_pdu(&pdu, node);
1634 	if (pdu_size == 0) {
1635 		isnst_close_so(so);
1636 		return (-1);
1637 	}
1638 
1639 	rc = isnst_send_pdu(so, pdu);
1640 	if (rc != 0) {
1641 		isnst_close_so(so);
1642 		kmem_free(pdu, pdu_size);
1643 		return (rc);
1644 	}
1645 
1646 	rsp_size = isnst_rcv_pdu(so, &rsp);
1647 	if (rsp_size == 0) {
1648 		isnst_close_so(so);
1649 		kmem_free(pdu, pdu_size);
1650 		return (-1);
1651 	}
1652 
1653 	rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
1654 
1655 	isnst_close_so(so);
1656 	kmem_free(pdu, pdu_size);
1657 	kmem_free(rsp, rsp_size);
1658 
1659 	return (rc);
1660 }
1661 
1662 static size_t
1663 isnst_make_dereg_pdu(isns_pdu_t **pdu, char *node)
1664 {
1665 	size_t		pdu_size;
1666 	int		len;
1667 	isns_target_t	*itarget;
1668 	iscsit_tgt_t	*target;
1669 	int		num_targets;
1670 
1671 	/*
1672 	 * create DevDereg Message with all of target nodes
1673 	 */
1674 	pdu_size = isnst_create_pdu_header(ISNS_DEV_DEREG, pdu, 0);
1675 	if (pdu_size == 0) {
1676 		return (0);
1677 	}
1678 
1679 	/*
1680 	 * Source attribute - Must be a storage node in the same
1681 	 * network entity.  We'll just grab the first one in the list.
1682 	 * If it's the only online target, we turn this into a total
1683 	 * deregistration regardless of the value of "node".
1684 	 */
1685 
1686 	num_targets = avl_numnodes(&isns_target_list);
1687 	itarget = avl_first(&isns_target_list);
1688 	target = itarget->target;
1689 
1690 	len = strlen(target->target_name) + 1;
1691 	if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1692 	    len, target->target_name, 0) != 0) {
1693 		goto dereg_pdu_error;
1694 	}
1695 
1696 	/* Delimiter */
1697 	if (isnst_add_attr(*pdu, pdu_size, ISNS_DELIMITER_ATTR_ID,
1698 	    0, 0, 0) != 0) {
1699 		goto dereg_pdu_error;
1700 	}
1701 
1702 	/*
1703 	 * Operating attributes
1704 	 */
1705 	if ((node == NULL) || (num_targets == 1)) {
1706 		/* dereg everything */
1707 		len = strlen(isns_eid) + 1;
1708 		if (isnst_add_attr(*pdu, pdu_size, ISNS_EID_ATTR_ID,
1709 		    len, isns_eid, 0) != 0) {
1710 			goto dereg_pdu_error;
1711 		}
1712 	} else {
1713 		/* dereg one target only */
1714 		len = strlen(node) + 1;
1715 		if (isnst_add_attr(*pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1716 		    len, node, 0) != 0) {
1717 			goto dereg_pdu_error;
1718 		}
1719 	}
1720 
1721 	return (pdu_size);
1722 
1723 dereg_pdu_error:
1724 	kmem_free(*pdu, pdu_size);
1725 	*pdu = NULL;
1726 
1727 	return (0);
1728 }
1729 
1730 static int
1731 isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
1732     isns_pdu_t *rsp, size_t rsp_size)
1733 {
1734 	uint16_t	func_id;
1735 	uint16_t	payload_len, rsp_payload_len;
1736 	isns_resp_t	*resp;
1737 	uint8_t		*pp;
1738 	isns_tlv_t	*attr;
1739 	uint32_t	attr_len, attr_id, esi_interval;
1740 
1741 	/*
1742 	 * Ensure we have at least a valid header (don't count the
1743 	 * "payload" field.
1744 	 */
1745 	if (rsp_size < offsetof(isns_pdu_t, payload)) {
1746 		ISNST_LOG(CE_WARN, "Invalid iSNS PDU header, %d of %d bytes",
1747 		    (int)rsp_size, (int)offsetof(isns_pdu_t, payload));
1748 		return (-1);
1749 	}
1750 
1751 	/* Make sure we have the amount of data that the header specifies */
1752 	payload_len = ntohs(rsp->payload_len);
1753 	if (rsp_size < (payload_len + offsetof(isns_pdu_t, payload))) {
1754 		ISNST_LOG(CE_WARN, "Invalid iSNS response, %d of %d bytes",
1755 		    (int)rsp_size,
1756 		    (int)(payload_len + offsetof(isns_pdu_t, payload)));
1757 		return (-1);
1758 	}
1759 
1760 	/* validate response function id */
1761 	func_id = ntohs(rsp->func_id);
1762 	switch (ntohs(pdu->func_id)) {
1763 	case ISNS_DEV_ATTR_REG:
1764 		if (func_id != ISNS_DEV_ATTR_REG_RSP) {
1765 			return (-1);
1766 		}
1767 
1768 		/*
1769 		 * Get the ESI interval returned by the server.  It could
1770 		 * be different than what we asked for.  We never know which
1771 		 * portal a request may come in on, and any server could demand
1772 		 * any interval. We'll simply keep track of the largest interval
1773 		 * for use in monitoring.
1774 		 */
1775 
1776 		rsp_payload_len = isnst_pdu_get_op(rsp, &pp);
1777 		attr = (isns_tlv_t *)((void *)pp);
1778 
1779 		/*
1780 		 * Make sure isnst_pdu_get_op didn't encounter an error
1781 		 * in the attributes.
1782 		 */
1783 		if (pp == NULL) {
1784 			return (-1);
1785 		}
1786 
1787 		while (rsp_payload_len) {
1788 			attr_len = ntohl(attr->attr_len);
1789 			attr_id = ntohl(attr->attr_id);
1790 
1791 			if (attr_id == ISNS_ESI_INTERVAL_ATTR_ID) {
1792 				esi_interval =
1793 				    ntohl(*((uint32_t *)
1794 				    ((void *)(&attr->attr_value))));
1795 
1796 				if (esi_interval > svr->svr_esi_interval)
1797 					svr->svr_esi_interval = esi_interval;
1798 
1799 				break;
1800 			}
1801 
1802 			rsp_payload_len -= (8 + attr_len);
1803 			attr = (isns_tlv_t *)
1804 			    ((void *)((uint8_t *)attr + attr_len + 8));
1805 		}
1806 
1807 		break;
1808 	case ISNS_DEV_DEREG:
1809 		if (func_id != ISNS_DEV_DEREG_RSP) {
1810 			return (-1);
1811 		}
1812 		break;
1813 	default:
1814 		ASSERT(0);
1815 		break;
1816 	}
1817 
1818 	/* verify response transaction id */
1819 	if (ntohs(rsp->xid) != ntohs(pdu->xid)) {
1820 		return (-1);
1821 	}
1822 
1823 	/* check the error code */
1824 	resp = (isns_resp_t *)((void *)&rsp->payload[0]);
1825 
1826 	return (ntohl(resp->status));
1827 }
1828 
1829 static uint16_t
1830 isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp)
1831 {
1832 	uint8_t		*payload;
1833 	uint16_t	payload_len;
1834 	isns_resp_t	*resp;
1835 	isns_tlv_t	*attr;
1836 	uint32_t	attr_id;
1837 	uint32_t	tlv_len;
1838 
1839 	/* get payload */
1840 	payload_len = ntohs(pdu->payload_len);
1841 	resp = (isns_resp_t *)((void *)&pdu->payload[0]);
1842 
1843 	/* find the operating attributes */
1844 	if (payload_len < sizeof (resp->status)) {
1845 		ISNST_LOG(CE_WARN, "Invalid iSNS response, %d payload bytes",
1846 		    payload_len);
1847 		*pp = NULL;
1848 		return (0);
1849 	}
1850 
1851 	payload_len -= sizeof (resp->status);
1852 	payload = &resp->data[0];
1853 
1854 	while (payload_len >= (sizeof (isns_tlv_t) - 1)) {
1855 		attr = (isns_tlv_t *)((void *)payload);
1856 		tlv_len = offsetof(isns_tlv_t, attr_value) +
1857 		    ntohl(attr->attr_len);
1858 		if (payload_len >= tlv_len) {
1859 			payload += tlv_len;
1860 			payload_len -= tlv_len;
1861 			attr_id = ntohl(attr->attr_id);
1862 			if (attr_id == ISNS_DELIMITER_ATTR_ID) {
1863 				break;
1864 			}
1865 		} else {
1866 			/* mal-formed packet */
1867 			payload = NULL;
1868 			payload_len = 0;
1869 		}
1870 	}
1871 
1872 	*pp = payload;
1873 
1874 	return (payload_len);
1875 }
1876 
1877 static size_t
1878 isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags)
1879 {
1880 	size_t	pdu_size = ISNSP_MAX_PDU_SIZE;
1881 
1882 	*pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_NOSLEEP);
1883 	if (*pdu != NULL) {
1884 		(*pdu)->version = htons((uint16_t)ISNSP_VERSION);
1885 		(*pdu)->func_id = htons((uint16_t)func_id);
1886 		(*pdu)->payload_len = htons(0);
1887 		(*pdu)->flags = htons(flags);
1888 
1889 		(*pdu)->xid = htons(GET_XID());
1890 		(*pdu)->seq = htons(0);
1891 	} else {
1892 		pdu_size = 0;
1893 	}
1894 
1895 	return (pdu_size);
1896 }
1897 
1898 static int
1899 isnst_add_attr(isns_pdu_t *pdu,
1900     size_t max_pdu_size,
1901     uint32_t attr_id,
1902     uint32_t attr_len,
1903     void *attr_data,
1904     uint32_t attr_numeric_data)
1905 {
1906 	isns_tlv_t	*attr_tlv;
1907 	uint8_t		*payload_ptr;
1908 	uint16_t	payload_len;
1909 	uint32_t	normalized_attr_len;
1910 	uint64_t	attr_tlv_len;
1911 
1912 	/* The attribute length must be 4-byte aligned. Section 5.1.3. */
1913 	normalized_attr_len = (attr_len % 4) == 0 ?
1914 	    (attr_len) : (attr_len + (4 - (attr_len % 4)));
1915 	attr_tlv_len = ISNS_TLV_ATTR_ID_LEN +
1916 	    ISNS_TLV_ATTR_LEN_LEN + normalized_attr_len;
1917 
1918 	/* Check if we are going to exceed the maximum PDU length. */
1919 	payload_len = ntohs(pdu->payload_len);
1920 	if ((payload_len + attr_tlv_len) > max_pdu_size) {
1921 		return (1);
1922 	}
1923 
1924 	attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
1925 
1926 	attr_tlv->attr_id = htonl(attr_id);
1927 
1928 	switch (attr_id) {
1929 	case ISNS_DELIMITER_ATTR_ID:
1930 		break;
1931 
1932 	case ISNS_PORTAL_IP_ADDR_ATTR_ID:
1933 	case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
1934 		if (attr_numeric_data == sizeof (in_addr_t)) {
1935 			/* IPv4 */
1936 			attr_tlv->attr_value[10] = 0xFF;
1937 			attr_tlv->attr_value[11] = 0xFF;
1938 			bcopy(attr_data, ((attr_tlv->attr_value) + 12),
1939 			    sizeof (in_addr_t));
1940 		} else if (attr_numeric_data == sizeof (in6_addr_t)) {
1941 			/* IPv6 */
1942 			bcopy(attr_data, attr_tlv->attr_value,
1943 			    sizeof (in6_addr_t));
1944 		} else if (attr_numeric_data == 0) {
1945 			/* EMPTY */
1946 			/* Do nothing */
1947 		} else {
1948 			kmem_free(attr_tlv, attr_tlv_len);
1949 			attr_tlv = NULL;
1950 			return (1);
1951 		}
1952 		break;
1953 
1954 	case ISNS_EID_ATTR_ID:
1955 	case ISNS_ISCSI_NAME_ATTR_ID:
1956 	case ISNS_ISCSI_ALIAS_ATTR_ID:
1957 	case ISNS_PG_ISCSI_NAME_ATTR_ID:
1958 		if (attr_len && attr_data) {
1959 			bcopy((char *)attr_data,
1960 			    attr_tlv->attr_value, attr_len);
1961 		}
1962 		break;
1963 
1964 	default:
1965 		if (attr_len == 8) {
1966 			*(uint64_t *)((void *)attr_tlv->attr_value) =
1967 			    BE_64((uint64_t)attr_numeric_data);
1968 		} else if (attr_len == 4) {
1969 			*(uint32_t *)((void *)attr_tlv->attr_value) =
1970 			    htonl((uint32_t)attr_numeric_data);
1971 		}
1972 		break;
1973 	}
1974 
1975 	attr_tlv->attr_len = htonl(normalized_attr_len);
1976 	/*
1977 	 * Convert the network byte ordered payload length to host byte
1978 	 * ordered for local address calculation.
1979 	 */
1980 	payload_len = ntohs(pdu->payload_len);
1981 	payload_ptr = pdu->payload + payload_len;
1982 	bcopy(attr_tlv, payload_ptr, attr_tlv_len);
1983 	payload_len += attr_tlv_len;
1984 
1985 	/*
1986 	 * Convert the host byte ordered payload length back to network
1987 	 * byte ordered - it's now ready to be sent on the wire.
1988 	 */
1989 	pdu->payload_len = htons(payload_len);
1990 
1991 	kmem_free(attr_tlv, attr_tlv_len);
1992 	attr_tlv = NULL;
1993 
1994 	return (0);
1995 }
1996 
1997 static void
1998 isnst_so_timeout(void *so)
1999 {
2000 	/* Wake up any sosend or sorecv blocked on this socket */
2001 	idm_soshutdown(so);
2002 }
2003 
2004 static int
2005 isnst_send_pdu(void *so, isns_pdu_t *pdu)
2006 {
2007 	size_t		total_len, payload_len, send_len;
2008 	uint8_t		*payload;
2009 	uint16_t	flags, seq;
2010 	timeout_id_t	send_timer;
2011 	iovec_t		iov[2];
2012 	int		rc;
2013 
2014 	/* update pdu flags */
2015 	flags  = ntohs(pdu->flags);
2016 	flags |= ISNS_FLAG_CLIENT;
2017 	flags |= ISNS_FLAG_FIRST_PDU;
2018 
2019 	/* initalize sequence number */
2020 	seq = 0;
2021 
2022 	payload = pdu->payload;
2023 
2024 	/* total payload length */
2025 	total_len = ntohs(pdu->payload_len);
2026 
2027 	/* fill in the pdu header */
2028 	iov[0].iov_base = (void *)pdu;
2029 	iov[0].iov_len = ISNSP_HEADER_SIZE;
2030 
2031 	do {
2032 		/* split the payload accordingly */
2033 		if (total_len > ISNSP_MAX_PAYLOAD_SIZE) {
2034 			payload_len = ISNSP_MAX_PAYLOAD_SIZE;
2035 		} else {
2036 			payload_len = total_len;
2037 			/* set the last pdu flag */
2038 			flags |= ISNS_FLAG_LAST_PDU;
2039 		}
2040 
2041 		/* set back the pdu flags */
2042 		pdu->flags = htons(flags);
2043 		/* set the sequence number */
2044 		pdu->seq = htons(seq);
2045 		/* set the payload length */
2046 		pdu->payload_len = htons(payload_len);
2047 
2048 		/* fill in the payload */
2049 		iov[1].iov_base = (void *)payload;
2050 		iov[1].iov_len = payload_len;
2051 
2052 		DTRACE_PROBE3(isnst__pdu__send, uint16_t, ntohs(pdu->func_id),
2053 		    uint16_t, ntohs(pdu->payload_len), caddr_t, pdu);
2054 
2055 		/* send the pdu */
2056 		send_len = ISNSP_HEADER_SIZE + payload_len;
2057 		send_timer = timeout(isnst_so_timeout, so,
2058 		    drv_usectohz(ISNS_RCV_TIMER_SECONDS * 1000000));
2059 		rc = idm_iov_sosend(so, &iov[0], 2, send_len);
2060 		(void) untimeout(send_timer);
2061 
2062 		flags &= ~ISNS_FLAG_FIRST_PDU;
2063 		payload += payload_len;
2064 		total_len -= payload_len;
2065 
2066 		/* increase the sequence number */
2067 		seq ++;
2068 
2069 	} while (rc == 0 && total_len > 0);
2070 
2071 	return (rc);
2072 }
2073 
2074 static size_t
2075 isnst_rcv_pdu(void *so, isns_pdu_t **pdu)
2076 {
2077 	size_t		total_pdu_len;
2078 	size_t		total_payload_len;
2079 	size_t		payload_len;
2080 	size_t		combined_len;
2081 	isns_pdu_t	tmp_pdu_hdr;
2082 	isns_pdu_t	*combined_pdu;
2083 	uint8_t		*payload;
2084 	uint8_t		*combined_payload;
2085 	timeout_id_t	rcv_timer;
2086 	uint16_t	flags;
2087 	uint16_t	seq;
2088 
2089 	*pdu = NULL;
2090 	total_pdu_len = total_payload_len = 0;
2091 	payload = NULL;
2092 	seq = 0;
2093 
2094 	do {
2095 		/* receive the pdu header */
2096 		rcv_timer = timeout(isnst_so_timeout, so,
2097 		    drv_usectohz(ISNS_RCV_TIMER_SECONDS * 1000000));
2098 		if (idm_sorecv(so, &tmp_pdu_hdr, ISNSP_HEADER_SIZE) != 0 ||
2099 		    ntohs(tmp_pdu_hdr.seq) != seq) {
2100 			(void) untimeout(rcv_timer);
2101 			goto rcv_error;
2102 		}
2103 		(void) untimeout(rcv_timer);
2104 
2105 		/* receive the payload */
2106 		payload_len = ntohs(tmp_pdu_hdr.payload_len);
2107 		payload = kmem_alloc(payload_len, KM_SLEEP);
2108 		rcv_timer = timeout(isnst_so_timeout, so,
2109 		    drv_usectohz(ISNS_RCV_TIMER_SECONDS * 1000000));
2110 		if (idm_sorecv(so, payload, payload_len) != 0) {
2111 			(void) untimeout(rcv_timer);
2112 			goto rcv_error;
2113 		}
2114 		(void) untimeout(rcv_timer);
2115 
2116 		/* combine the pdu if it is not the first one */
2117 		if (total_pdu_len > 0) {
2118 			combined_len = total_pdu_len + payload_len;
2119 			combined_pdu = kmem_alloc(combined_len, KM_SLEEP);
2120 			bcopy(*pdu, combined_pdu, total_pdu_len);
2121 			combined_payload =
2122 			    &combined_pdu->payload[total_payload_len];
2123 			bcopy(payload, combined_payload, payload_len);
2124 			kmem_free(*pdu, total_pdu_len);
2125 			kmem_free(payload, payload_len);
2126 			*pdu = combined_pdu;
2127 			total_payload_len += payload_len;
2128 			total_pdu_len += payload_len;
2129 			(*pdu)->payload_len = htons(total_payload_len);
2130 		} else {
2131 			total_payload_len = payload_len;
2132 			total_pdu_len = ISNSP_HEADER_SIZE + payload_len;
2133 			*pdu = kmem_alloc(total_pdu_len, KM_SLEEP);
2134 			bcopy(&tmp_pdu_hdr, *pdu, ISNSP_HEADER_SIZE);
2135 			bcopy(payload, &(*pdu)->payload[0], payload_len);
2136 			kmem_free(payload, payload_len);
2137 		}
2138 		payload = NULL;
2139 
2140 		/* the flags of pdu which is just received */
2141 		flags = ntohs(tmp_pdu_hdr.flags);
2142 
2143 		/* increase sequence number by one */
2144 		seq ++;
2145 	} while ((flags & ISNS_FLAG_LAST_PDU) == 0);
2146 
2147 	DTRACE_PROBE3(isnst__pdu__recv, uint16_t, ntohs((*pdu)->func_id),
2148 	    size_t, total_payload_len, caddr_t, *pdu);
2149 
2150 	return (total_pdu_len);
2151 
2152 rcv_error:
2153 	if (*pdu != NULL) {
2154 		kmem_free(*pdu, total_pdu_len);
2155 		*pdu = NULL;
2156 	}
2157 	if (payload != NULL) {
2158 		kmem_free(payload, payload_len);
2159 	}
2160 	return (0);
2161 }
2162 
2163 static void *
2164 isnst_open_so(struct sockaddr_storage *sa)
2165 {
2166 	int sa_sz;
2167 	ksocket_t so;
2168 
2169 	/* determin local IP address */
2170 	if (sa->ss_family == AF_INET) {
2171 		/* IPv4 */
2172 		sa_sz = sizeof (struct sockaddr_in);
2173 
2174 		/* Create socket */
2175 		so = idm_socreate(AF_INET, SOCK_STREAM, 0);
2176 	} else {
2177 		/* IPv6 */
2178 		sa_sz = sizeof (struct sockaddr_in6);
2179 
2180 		/* Create socket */
2181 		so = idm_socreate(AF_INET6, SOCK_STREAM, 0);
2182 	}
2183 
2184 	if (so != NULL) {
2185 		if (ksocket_connect(so, (struct sockaddr *)sa, sa_sz, CRED())
2186 		    != 0) {
2187 			/* not calling isnst_close_so() to */
2188 			/* make dtrace output look clear */
2189 			idm_soshutdown(so);
2190 			idm_sodestroy(so);
2191 			so = NULL;
2192 		}
2193 	}
2194 
2195 	if (so == NULL) {
2196 		struct sockaddr_in *sin;
2197 		struct sockaddr_in6 *sin6;
2198 		char s[INET6_ADDRSTRLEN];
2199 		void *ip;
2200 		uint16_t port;
2201 		sin = (struct sockaddr_in *)sa;
2202 		port = ntohs(sin->sin_port);
2203 		if (sa->ss_family == AF_INET) {
2204 			ip = (void *)&sin->sin_addr.s_addr;
2205 			(void) inet_ntop(AF_INET, ip, s, sizeof (s));
2206 		} else {
2207 			sin6 = (struct sockaddr_in6 *)sa;
2208 			ip = (void *)&sin6->sin6_addr.s6_addr;
2209 			(void) inet_ntop(AF_INET6, ip, s, sizeof (s));
2210 		}
2211 		ISNST_LOG(CE_WARN, "open iSNS Server %s:%u failed", s, port);
2212 	}
2213 
2214 	return (so);
2215 }
2216 
2217 static void
2218 isnst_close_so(void *so)
2219 {
2220 	idm_soshutdown(so);
2221 	idm_sodestroy(so);
2222 }
2223 
2224 
2225 /*
2226  * ESI handling
2227  */
2228 
2229 static void
2230 isnst_esi_start(void)
2231 {
2232 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2233 
2234 	ISNST_LOG(CE_NOTE, "isnst_esi_start");
2235 
2236 	mutex_enter(&esi.esi_mutex);
2237 	esi.esi_enabled = B_TRUE;
2238 	esi.esi_thread_running = B_FALSE;
2239 	esi.esi_valid = B_FALSE;
2240 	esi.esi_thread = thread_create(NULL, 0, isnst_esi_thread,
2241 	    (void *)&esi, 0, &p0, TS_RUN, minclsyspri);
2242 
2243 	/*
2244 	 * Wait for the thread to start
2245 	 */
2246 	while (!esi.esi_thread_running) {
2247 		cv_wait(&esi.esi_cv, &esi.esi_mutex);
2248 	}
2249 	mutex_exit(&esi.esi_mutex);
2250 }
2251 
2252 static void
2253 isnst_esi_stop()
2254 {
2255 	ISNST_LOG(CE_NOTE, "isnst_esi_stop");
2256 
2257 	/* Shutdown ESI listening socket, wait for thread to terminate */
2258 	mutex_enter(&esi.esi_mutex);
2259 	esi.esi_enabled = B_FALSE;
2260 	if (esi.esi_valid) {
2261 		idm_soshutdown(esi.esi_so);
2262 		mutex_exit(&esi.esi_mutex);
2263 		idm_sodestroy(esi.esi_so);
2264 	} else {
2265 		mutex_exit(&esi.esi_mutex);
2266 	}
2267 	thread_join(esi.esi_thread_did);
2268 
2269 }
2270 
2271 /*
2272  * isnst_esi_thread
2273  *
2274  * This function listens on a socket for incoming connections from an
2275  * iSNS server until told to stop.
2276  */
2277 
2278 /*ARGSUSED*/
2279 static void
2280 isnst_esi_thread(void *arg)
2281 {
2282 	ksocket_t		newso;
2283 	struct sockaddr_in6	sin6;
2284 	socklen_t		sin_addrlen;
2285 	uint32_t		on = 1;
2286 	int			rc;
2287 	isns_pdu_t		*pdu;
2288 	size_t			pl_size;
2289 
2290 	bzero(&sin6, sizeof (struct sockaddr_in6));
2291 	sin_addrlen = sizeof (struct sockaddr_in6);
2292 
2293 	esi.esi_thread_did = curthread->t_did;
2294 
2295 	mutex_enter(&esi.esi_mutex);
2296 
2297 	/*
2298 	 * Mark the thread as running and the portal as no longer new.
2299 	 */
2300 	esi.esi_thread_running = B_TRUE;
2301 	cv_signal(&esi.esi_cv);
2302 
2303 	while (esi.esi_enabled) {
2304 		/*
2305 		 * Create a socket to listen for requests from the iSNS server.
2306 		 */
2307 		DTRACE_PROBE1(iscsit__isns__esi__socreate,
2308 		    boolean_t, esi.esi_enabled);
2309 		if ((esi.esi_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) ==
2310 		    NULL) {
2311 			ISNST_LOG(CE_WARN,
2312 			    "isnst_esi_thread: Unable to create socket");
2313 			mutex_exit(&esi.esi_mutex);
2314 			delay(drv_usectohz(1000000));
2315 			mutex_enter(&esi.esi_mutex);
2316 			continue;
2317 		}
2318 
2319 		/*
2320 		 * Set options, bind, and listen until we're told to stop
2321 		 */
2322 		bzero(&sin6, sizeof (sin6));
2323 		sin6.sin6_family = AF_INET6;
2324 		sin6.sin6_port = htons(0);
2325 		sin6.sin6_addr = in6addr_any;
2326 
2327 		(void) ksocket_setsockopt(esi.esi_so, SOL_SOCKET,
2328 		    SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
2329 
2330 		if (ksocket_bind(esi.esi_so, (struct sockaddr *)&sin6,
2331 		    sizeof (sin6), CRED()) != 0) {
2332 			ISNST_LOG(CE_WARN, "Unable to bind socket for ESI");
2333 			idm_sodestroy(esi.esi_so);
2334 			mutex_exit(&esi.esi_mutex);
2335 			delay(drv_usectohz(1000000));
2336 			mutex_enter(&esi.esi_mutex);
2337 			continue;
2338 		}
2339 
2340 		/*
2341 		 * Get the port (sin6 is meaningless at this point)
2342 		 */
2343 		(void) ksocket_getsockname(esi.esi_so,
2344 		    (struct sockaddr *)(&sin6), &sin_addrlen, CRED());
2345 		esi.esi_port =
2346 		    ntohs(((struct sockaddr_in6 *)(&sin6))->sin6_port);
2347 
2348 		if ((rc = ksocket_listen(esi.esi_so, 5, CRED())) != 0) {
2349 			ISNST_LOG(CE_WARN, "isnst_esi_thread: listen "
2350 			    "failure 0x%x", rc);
2351 			idm_sodestroy(esi.esi_so);
2352 			mutex_exit(&esi.esi_mutex);
2353 			delay(drv_usectohz(1000000));
2354 			mutex_enter(&esi.esi_mutex);
2355 			continue;
2356 		}
2357 
2358 		ksocket_hold(esi.esi_so);
2359 		esi.esi_valid = B_TRUE;
2360 		while (esi.esi_enabled) {
2361 			mutex_exit(&esi.esi_mutex);
2362 
2363 			DTRACE_PROBE1(iscsit__isns__esi__accept__wait,
2364 			    boolean_t, esi.esi_enabled);
2365 			if ((rc = ksocket_accept(esi.esi_so, NULL, NULL,
2366 			    &newso, CRED())) != 0) {
2367 				mutex_enter(&esi.esi_mutex);
2368 				DTRACE_PROBE2(iscsit__isns__esi__accept__fail,
2369 				    int, rc, boolean_t, esi.esi_enabled);
2370 				/*
2371 				 * If we were interrupted with EINTR
2372 				 * it's not really a failure.
2373 				 */
2374 				ISNST_LOG(CE_WARN, "isnst_esi_thread: "
2375 				    "accept failure (0x%x)", rc);
2376 
2377 				delay(drv_usectohz(100000));
2378 				if (rc == EINTR) {
2379 					continue;
2380 				} else {
2381 					break;
2382 				}
2383 			}
2384 			DTRACE_PROBE2(iscsit__isns__esi__accept,
2385 			    boolean_t, esi.esi_enabled,
2386 			    ksocket_t, newso);
2387 
2388 			pl_size = isnst_rcv_pdu(newso, &pdu);
2389 			if (pl_size == 0) {
2390 				ISNST_LOG(CE_WARN, "isnst_esi_thread: "
2391 				    "rcv_pdu failure");
2392 				(void) ksocket_close(newso, CRED());
2393 
2394 				mutex_enter(&esi.esi_mutex);
2395 				continue;
2396 			}
2397 
2398 			isnst_handle_esi_req(newso, pdu, pl_size);
2399 
2400 			(void) ksocket_close(newso, CRED());
2401 
2402 			/*
2403 			 * Do not hold the esi mutex during server timestamp
2404 			 * update.  It requires the isns global lock, which may
2405 			 * be held during other functions that also require
2406 			 * the esi_mutex (potential deadlock).
2407 			 */
2408 			isnst_update_server_timestamp(newso);
2409 			mutex_enter(&esi.esi_mutex);
2410 		}
2411 
2412 		idm_soshutdown(esi.esi_so);
2413 		ksocket_rele(esi.esi_so);
2414 		esi.esi_valid = B_FALSE;
2415 
2416 		/*
2417 		 * If we're going to try to re-establish the listener then
2418 		 * destroy this socket.  Otherwise isnst_esi_stop already
2419 		 * destroyed it.
2420 		 */
2421 		if (esi.esi_enabled)
2422 			idm_sodestroy(esi.esi_so);
2423 	}
2424 
2425 	esi.esi_thread_running = B_FALSE;
2426 	cv_signal(&esi.esi_cv);
2427 	mutex_exit(&esi.esi_mutex);
2428 esi_thread_exit:
2429 	thread_exit();
2430 }
2431 
2432 /*
2433  * Handle an incoming ESI request
2434  */
2435 
2436 static void
2437 isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pdu_size)
2438 {
2439 	static char		log_addr_buf[INET6_ADDRSTRLEN];
2440 	isns_pdu_t		*rsp_pdu;
2441 	isns_resp_t		*rsp;
2442 	isns_tlv_t		*attr;
2443 	uint32_t		attr_len, attr_id;
2444 	size_t			req_pl_len, rsp_size, tlv_len;
2445 	struct sockaddr_storage	ss;
2446 	struct sockaddr_in6	*portal_addr6;
2447 	boolean_t		portal_addr_valid = B_FALSE;
2448 	boolean_t		portal_port_valid = B_FALSE;
2449 	uint32_t		esi_response = ISNS_RSP_SUCCESSFUL;
2450 	isns_portal_list_t	*portal;
2451 
2452 	if (ntohs(pdu->func_id) != ISNS_ESI) {
2453 		ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x",
2454 		    pdu->func_id);
2455 		kmem_free(pdu, pdu_size);
2456 		return;
2457 	}
2458 
2459 	req_pl_len = ntohs(pdu->payload_len);
2460 	if (req_pl_len + offsetof(isns_pdu_t, payload) > pdu_size) {
2461 		ISNST_LOG(CE_WARN, "isnst_handle_esi_req: "
2462 		    "payload exceeds PDU size (%d > %d)",
2463 		    (int)(req_pl_len + offsetof(isns_pdu_t, payload)),
2464 		    (int)pdu_size);
2465 		/* Not all data is present -- ignore */
2466 		kmem_free(pdu, pdu_size);
2467 		return;
2468 	}
2469 
2470 	if (req_pl_len + sizeof (uint32_t) > ISNSP_MAX_PAYLOAD_SIZE) {
2471 		ISNST_LOG(CE_WARN,
2472 		    "isnst_handle_esi_req: PDU payload exceeds max (%ld bytes)",
2473 		    req_pl_len + sizeof (uint32_t));
2474 		kmem_free(pdu, pdu_size);
2475 		return;
2476 	}
2477 
2478 	/*
2479 	 * Check portal in ESI request and make sure it is valid.  Return
2480 	 * esi_response of ISNS_RSP_SUCCESSFUL if valid, otherwise don't
2481 	 * respond at all.  Get IP addr and port.  Format of ESI
2482 	 * is:
2483 	 *
2484 	 * ISNS_TIMESTAMP_ATTR_ID,
2485 	 * ISNS_EID_ATTR_ID,
2486 	 * ISNS_PORTAL_IP_ADDR_ATTR_ID,
2487 	 * ISNS_PORTAL_PORT_ATTR_ID
2488 	 */
2489 	bzero(&ss, sizeof (struct sockaddr_storage));
2490 	ss.ss_family = AF_INET6;
2491 	portal_addr6 = (struct sockaddr_in6 *)&ss;
2492 	attr = (isns_tlv_t *)((void *)&pdu->payload);
2493 	attr_len = ntohl(attr->attr_len);
2494 	attr_id = ntohl(attr->attr_id);
2495 	tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
2496 	while (tlv_len <= req_pl_len) {
2497 		switch (attr_id) {
2498 		case ISNS_TIMESTAMP_ATTR_ID:
2499 			break;
2500 		case ISNS_EID_ATTR_ID:
2501 			break;
2502 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
2503 			if (attr_len > sizeof (struct in6_addr)) {
2504 				/* Bad attribute format */
2505 				esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
2506 			} else {
2507 				portal_addr6->sin6_family = AF_INET6;
2508 				attr_len = min(attr_len,
2509 				    sizeof (portal_addr6->sin6_addr));
2510 				bcopy(attr->attr_value,
2511 				    portal_addr6->sin6_addr.s6_addr, attr_len);
2512 				portal_addr_valid = B_TRUE;
2513 			}
2514 			break;
2515 		case ISNS_PORTAL_PORT_ATTR_ID:
2516 			if (attr_len > sizeof (uint32_t)) {
2517 				/* Bad attribute format */
2518 				esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
2519 			} else {
2520 				portal_addr6->sin6_port =
2521 				    htons((uint16_t)BE_IN32(attr->attr_value));
2522 				portal_port_valid = B_TRUE;
2523 			}
2524 			break;
2525 		default:
2526 			/* Bad request format */
2527 			esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
2528 			break;
2529 		}
2530 
2531 		/* If we've set an error then stop processing */
2532 		if (esi_response != ISNS_RSP_SUCCESSFUL) {
2533 			break;
2534 		}
2535 
2536 		/* Get next attribute */
2537 		req_pl_len -= tlv_len;
2538 		attr = (isns_tlv_t *)((void *)((uint8_t *)attr + tlv_len));
2539 		attr_len = ntohl(attr->attr_len);
2540 		attr_id = ntohl(attr->attr_id);
2541 		tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
2542 	}
2543 
2544 	if (!portal_port_valid)
2545 		portal_addr6->sin6_port = htons(ISCSI_LISTEN_PORT);
2546 
2547 	if (portal_addr_valid) {
2548 		ISNST_LOG(CE_NOTE, "ESI %s:%d",
2549 		    inet_ntop(AF_INET6, &portal_addr6->sin6_addr, log_addr_buf,
2550 		    INET6_ADDRSTRLEN),
2551 		    ntohs(portal_addr6->sin6_port));
2552 	} else {
2553 		esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
2554 	}
2555 
2556 	/*
2557 	 * If we've detected an error or if the portal does not
2558 	 * exist then drop the request.  The server will eventually
2559 	 * timeout the portal and eliminate it from the list.
2560 	 */
2561 
2562 	ISNS_GLOBAL_LOCK();
2563 	if ((esi_response != ISNS_RSP_SUCCESSFUL) ||
2564 	    !isnst_portal_exists(&ss)) {
2565 		ISNS_GLOBAL_UNLOCK();
2566 		kmem_free(pdu, pdu_size);
2567 		return;
2568 	}
2569 	ISNS_GLOBAL_UNLOCK();
2570 
2571 	/*
2572 	 * Build response validating the portal
2573 	 */
2574 	rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0);
2575 
2576 	if (rsp_size == 0) {
2577 		ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu");
2578 		kmem_free(pdu, pdu_size);
2579 		return;
2580 	}
2581 
2582 	rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0]));
2583 
2584 	/* Use xid from the request pdu */
2585 	rsp_pdu->xid = pdu->xid;
2586 	rsp->status = htonl(ISNS_RSP_SUCCESSFUL);
2587 
2588 	/* Copy original data */
2589 	req_pl_len = ntohs(pdu->payload_len);
2590 	bcopy(pdu->payload, rsp->data, req_pl_len);
2591 	rsp_pdu->payload_len = htons(req_pl_len + sizeof (uint32_t));
2592 
2593 	if (isnst_send_pdu(ks, rsp_pdu) != 0) {
2594 		ISNST_LOG(CE_WARN,
2595 		    "isnst_handle_esi_req: Send response failed");
2596 	}
2597 
2598 	kmem_free(rsp_pdu, rsp_size);
2599 	kmem_free(pdu, pdu_size);
2600 
2601 	/*
2602 	 * Update ESI timestamps for all matching portals.  Iscsit may or
2603 	 * may not allow portals to belong to multiple portal groups depending
2604 	 * on the policy it implements.  The iSNS client  does not know or
2605 	 * care so we allow for multiple hits in the list.
2606 	 */
2607 	ISNS_GLOBAL_LOCK();
2608 	for (portal = isnst_lookup_portal(&ss, NULL);
2609 	    portal != NULL;
2610 	    portal = isnst_lookup_portal(&ss, portal)) {
2611 		gethrestime(&portal->portal_esi_timestamp);
2612 	}
2613 	ISNS_GLOBAL_UNLOCK();
2614 }
2615 
2616 int
2617 isnst_tgt_avl_compare(const void *t1, const void *t2)
2618 {
2619 	const isns_target_t	*tgt1 = t1;
2620 	const isns_target_t	*tgt2 = t2;
2621 
2622 	/*
2623 	 * Sort by target (pointer to iscsit_tgt_t).
2624 	 */
2625 
2626 	if (tgt1->target < tgt2->target) {
2627 		return (-1);
2628 	} else if (tgt1->target > tgt2->target) {
2629 		return (1);
2630 	}
2631 
2632 	return (0);
2633 }
2634 
2635 static void
2636 isnst_get_target_list(void)
2637 {
2638 	iscsit_tgt_t	*tgt, *next_tgt;
2639 
2640 	/*
2641 	 * Initialize our list of targets with those from the global
2642 	 * list that are online.
2643 	 */
2644 
2645 	for (tgt = avl_first(&iscsit_global.global_target_list); tgt != NULL;
2646 	    tgt = next_tgt) {
2647 		next_tgt = AVL_NEXT(&iscsit_global.global_target_list, tgt);
2648 		if (tgt->target_state == TS_STMF_ONLINE) {
2649 			(void) isnst_add_to_target_list(tgt);
2650 		}
2651 	}
2652 }
2653 
2654 static void
2655 isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered)
2656 {
2657 	ASSERT(ISNS_GLOBAL_LOCK_HELD());
2658 
2659 	if (registered == B_TRUE) {
2660 		svr->svr_registered = B_TRUE;
2661 		svr->svr_last_msg = ddi_get_lbolt();
2662 	} else {
2663 		svr->svr_registered = B_FALSE;
2664 	}
2665 }
2666 
2667 static boolean_t
2668 isnst_lookup_default_portal(struct sockaddr_storage *p)
2669 {
2670 	idm_addr_list_t		*default_portal_list;
2671 	uint32_t		default_portal_list_size;
2672 	idm_addr_t		*dportal;
2673 	struct sockaddr_storage	dportal_ss;
2674 	int			idx;
2675 	boolean_t		result = B_FALSE;
2676 
2677 	/*
2678 	 * If the address we're looking up is not using the well known
2679 	 * port then it's inherently not a match for a default portal
2680 	 */
2681 	if (((struct sockaddr_in *)p)->sin_port != htons(ISCSI_LISTEN_PORT)) {
2682 		return (B_FALSE);
2683 	}
2684 
2685 	/*
2686 	 * Get the global list of default portals
2687 	 */
2688 	default_portal_list_size = idm_get_ipaddr(&default_portal_list);
2689 
2690 	if (default_portal_list_size == 0) {
2691 		ISNST_LOG(CE_WARN, "isnst_lookup_default_portal: "
2692 		    "No default portals");
2693 		return (B_FALSE);
2694 	}
2695 
2696 	/*
2697 	 * Scan the through the current default portal list (this should
2698 	 * be refreshed just before lookup since the contents can change)
2699 	 */
2700 	for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
2701 		dportal = &default_portal_list->al_addrs[idx];
2702 
2703 		/*
2704 		 * Translate the address idm_get_ipaddr returned into
2705 		 * sockaddr_storage format
2706 		 */
2707 		bzero(&dportal_ss, sizeof (dportal_ss));
2708 		((struct sockaddr_in *)&dportal_ss)->sin_port =
2709 		    htons(ISCSI_LISTEN_PORT);
2710 		if (dportal->a_addr.i_insize == sizeof (struct in_addr)) {
2711 			dportal_ss.ss_family = AF_INET;
2712 			bcopy(&dportal->a_addr.i_addr.in4,
2713 			    &((struct sockaddr_in *)&dportal_ss)->sin_addr,
2714 			    sizeof (struct in_addr));
2715 		} else if (dportal->a_addr.i_insize ==
2716 		    sizeof (struct in6_addr)) {
2717 			dportal_ss.ss_family = AF_INET6;
2718 			bcopy(&dportal->a_addr.i_addr.in6,
2719 			    &((struct sockaddr_in6 *)&dportal_ss)->sin6_addr,
2720 			    sizeof (struct in6_addr));
2721 		} else {
2722 			continue;
2723 		}
2724 
2725 		/*
2726 		 * Now we can compare to the address we were passed
2727 		 */
2728 		if (idm_ss_compare(p, &dportal_ss,
2729 		    B_TRUE /* v4_mapped_as_v4 */) == 0) {
2730 			result = B_TRUE;
2731 			goto lookup_default_portal_done;
2732 		}
2733 	}
2734 
2735 lookup_default_portal_done:
2736 	kmem_free(default_portal_list, default_portal_list_size);
2737 	return (result);
2738 }
2739 
2740 /*
2741  * These functions are called by iscsit proper when a portal comes online
2742  * or goes offline.
2743  */
2744 
2745 void
2746 iscsit_isns_portal_online(iscsit_portal_t *portal)
2747 {
2748 	ISNS_GLOBAL_LOCK();
2749 
2750 	if (portal->portal_default) {
2751 		/* Portals should only be onlined once */
2752 		ASSERT(!default_portal_online);
2753 		default_portal_online = B_TRUE;
2754 		default_portal_state_change = B_TRUE;
2755 		ISNS_GLOBAL_UNLOCK();
2756 		return;
2757 	}
2758 
2759 	isnst_add_portal(portal);
2760 
2761 	ISNS_GLOBAL_UNLOCK();
2762 }
2763 
2764 void
2765 iscsit_isns_portal_offline(iscsit_portal_t *portal)
2766 {
2767 	ISNS_GLOBAL_LOCK();
2768 
2769 	if (portal->portal_default) {
2770 		/* Portals should only be offlined once */
2771 		ASSERT(default_portal_online);
2772 		default_portal_online = B_FALSE;
2773 		default_portal_state_change = B_TRUE;
2774 		ISNS_GLOBAL_UNLOCK();
2775 		return;
2776 	}
2777 
2778 	isnst_remove_portal(portal);
2779 
2780 	ISNS_GLOBAL_UNLOCK();
2781 }
2782