summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/common/modules/idm/idm.c33
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit.c7
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit.h2
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c1577
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.h15
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c28
-rw-r--r--usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c7
-rw-r--r--usr/src/uts/common/io/idm/idm_conn_sm.c47
-rw-r--r--usr/src/uts/common/io/idm/idm_so.c100
-rw-r--r--usr/src/uts/common/sys/idm/idm_conn_sm.h2
-rw-r--r--usr/src/uts/common/sys/idm/idm_so.h4
11 files changed, 1102 insertions, 720 deletions
diff --git a/usr/src/cmd/mdb/common/modules/idm/idm.c b/usr/src/cmd/mdb/common/modules/idm/idm.c
index db4ca73906..76c64b045a 100644
--- a/usr/src/cmd/mdb/common/modules/idm/idm.c
+++ b/usr/src/cmd/mdb/common/modules/idm/idm.c
@@ -167,6 +167,8 @@ static void iscsi_format_timestamp(char *ts_str, int strlen,
static char *iscsi_inet_ntop(int af, const void *addr, char *buf, int addrlen);
static void convert2ascii(char *, const in6_addr_t *);
static int sa_to_str(struct sockaddr_storage *sa, char *addr);
+static int iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data,
+ void *data);
static int iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data,
void *data);
@@ -2084,7 +2086,6 @@ iscsi_isns_help(void)
static int
iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
{
- iscsi_dcmd_ctrl_t *idc = (iscsi_dcmd_ctrl_t *)data;
isns_esi_tinfo_t tinfo;
if (mdb_vread(&tinfo, sizeof (isns_esi_tinfo_t), addr) !=
@@ -2092,24 +2093,12 @@ iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
return (WALK_ERR);
}
- mdb_printf("ESI portal : 0x%p\n", tinfo.esi_portal);
- if (idc->idc_verbose) {
- mdb_inc_indent(4);
- iscsi_isns_portal_cb((uintptr_t)tinfo.esi_portal, NULL, data);
- mdb_dec_indent(4);
- }
mdb_printf("ESI thread/thr did : 0x%p / %d\n", tinfo.esi_thread,
tinfo.esi_thread_did);
mdb_printf("ESI sonode : 0x%p\n", tinfo.esi_so);
mdb_printf("ESI port : %d\n", tinfo.esi_port);
mdb_printf("ESI thread running : %s\n",
(tinfo.esi_thread_running) ? "Yes" : "No");
- if (!tinfo.esi_thread_running) {
- mdb_printf("ESI thread failed : %s\n",
- (tinfo.esi_thread_failed) ? "Yes" : "No");
- }
- mdb_printf("ESI registered : %s\n\n",
- (tinfo.esi_registered) ? "Yes" : "No");
return (WALK_NEXT);
}
@@ -2117,21 +2106,17 @@ iscsi_isns_esi_cb(uintptr_t addr, const void *walker_data, void *data)
static int
iscsi_isns_esi(iscsi_dcmd_ctrl_t *idc)
{
- GElf_Sym sym;
- uintptr_t esi_list;
+ GElf_Sym sym;
+ uintptr_t addr;
- if (mdb_lookup_by_name("esi_list", &sym) == -1) {
+ if (mdb_lookup_by_name("esi", &sym) == -1) {
mdb_warn("failed to find symbol 'esi_list'");
return (DCMD_ERR);
}
+ addr = (uintptr_t)sym.st_value;
- esi_list = (uintptr_t)sym.st_value;
idc->idc_header = 1;
-
- if (mdb_pwalk("list", iscsi_isns_esi_cb, idc, esi_list) == -1) {
- mdb_warn("avl walk failed for esi_list");
- return (DCMD_ERR);
- }
+ (void) iscsi_isns_esi_cb(addr, NULL, idc);
return (0);
}
@@ -2144,6 +2129,7 @@ iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data)
isns_portal_list_t portal;
char portal_addr[PORTAL_STR_LEN];
struct sockaddr_storage *ss;
+ char ts_string[40];
if (mdb_vread(&portal, sizeof (isns_portal_list_t), addr) !=
sizeof (isns_portal_list_t)) {
@@ -2170,7 +2156,8 @@ iscsi_isns_portal_cb(uintptr_t addr, const void *walker_data, void *data)
iscsi_portal_impl((uintptr_t)portal.portal_iscsit, idc);
}
- mdb_printf("Portal ESI info: 0x%p\n\n", portal.portal_esi);
+ iscsi_format_timestamp(ts_string, 40, &portal.portal_esi_timestamp);
+ mdb_printf("Portal ESI timestamp: 0x%p\n\n", ts_string);
return (WALK_NEXT);
}
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c
index f0483b3b31..cdaef9d414 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c
@@ -977,7 +977,13 @@ iscsit_conn_accept(idm_conn_t *ic)
* doesn't get shutdown prior to establishing a session. This
* gets released in iscsit_conn_destroy().
*/
+ ISCSIT_GLOBAL_LOCK(RW_READER);
+ if (iscsit_global.global_svc_state != ISE_ENABLED) {
+ ISCSIT_GLOBAL_UNLOCK();
+ return (IDM_STATUS_FAIL);
+ }
iscsit_global_hold();
+ ISCSIT_GLOBAL_UNLOCK();
/*
* Allocate an associated iscsit structure to represent this
@@ -996,6 +1002,7 @@ iscsit_conn_accept(idm_conn_t *ic)
* Initialize login state machine
*/
if (iscsit_login_sm_init(ict) != IDM_STATUS_SUCCESS) {
+ iscsit_global_rele();
return (IDM_STATUS_FAIL);
}
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
index b2234e4e62..562aec035d 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h
@@ -95,6 +95,8 @@ typedef struct {
avl_node_t portal_tpg_ln;
iscsit_tpg_t *portal_tpg;
idm_svc_t *portal_svc;
+ boolean_t portal_default;
+ void *portal_isns;
} iscsit_portal_t;
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c
index 2708d10c5b..05a1492a86 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -53,7 +53,12 @@
#define VALID_NAME(NAME, LEN) \
((LEN) > 0 && (NAME)[0] != 0 && (NAME)[(LEN) - 1] == 0)
-static kmutex_t isns_mutex;
+
+boolean_t iscsit_isns_logging = 0;
+
+#define ISNST_LOG if (iscsit_isns_logging) cmn_err
+
+static kmutex_t isns_monitor_mutex;
static kthread_t *isns_monitor_thr_id;
static kt_did_t isns_monitor_thr_did;
static boolean_t isns_monitor_thr_running;
@@ -78,21 +83,16 @@ static clock_t monitor_idle_interval;
* iSNS ESI thread state
*/
-static kmutex_t isns_esi_mutex;
-static kcondvar_t isns_esi_cv;
-static list_t esi_list;
-static uint32_t isns_esi_max_interval = 0;
+static isns_esi_tinfo_t esi;
/*
* List of portals.
*/
-
+static boolean_t default_portal_online = B_FALSE;
+static boolean_t default_portal_state_change = B_FALSE;
static list_t portal_list;
static uint32_t portal_list_count = 0;
-/* How many of our portals are not "default"? */
-static uint32_t nondefault_portals = 0;
-
/*
* Our entity identifier (fully-qualified hostname)
*/
@@ -103,6 +103,12 @@ static char *isns_eid = NULL;
*/
static avl_tree_t isns_target_list;
+/*
+ * in6addr_any is currently all zeroes, but use the macro in case this
+ * ever changes.
+ */
+static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+
static void
isnst_start();
@@ -142,7 +148,8 @@ static size_t
isnst_make_dereg_pdu(isns_pdu_t **pdu, char *node);
static int
-isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp);
+isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
+ isns_pdu_t *rsp, size_t rsp_size);
static uint16_t
isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp);
@@ -151,6 +158,23 @@ static size_t
isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
boolean_t svr_registered, isns_reg_type_t regtype);
+static int
+isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size,
+ idm_addr_list_t *default_portal_list);
+
+static int
+isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, iscsit_tgt_t *target,
+ idm_addr_list_t *default_portal_list);
+
+static int
+isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
+ iscsit_tgt_t *tgt, idm_addr_list_t *default_portal_list);
+
+static int
+isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
+ uint32_t ip_attr_id, uint32_t port_attr_id,
+ struct sockaddr_storage *ss, boolean_t esi_info);
+
static size_t
isnst_create_pdu_header(uint16_t func_id, isns_pdu_t **pdu, uint16_t flags);
@@ -177,24 +201,25 @@ isnst_close_so(void *);
static void
isnst_esi_thread(void *arg);
-static boolean_t
+static void
isnst_handle_esi_req(ksocket_t so, isns_pdu_t *pdu, size_t pl_size);
-static void isnst_esi_start(isns_portal_list_t *portal);
-static void isnst_esi_stop();
-static void isnst_esi_stop_thread(isns_esi_tinfo_t *tinfop);
-static void isnst_esi_check();
-static void isnst_esi_start_thread(isns_esi_tinfo_t *tinfop);
+static void isnst_esi_start(void);
+static void isnst_esi_stop(void);
static isns_target_t *isnst_add_to_target_list(iscsit_tgt_t *target);
int isnst_tgt_avl_compare(const void *t1, const void *t2);
static void isnst_get_target_list(void);
static void isnst_set_server_status(iscsit_isns_svr_t *svr,
boolean_t registered);
+static void isnst_monitor_start(void);
static void isnst_monitor_stop(void);
-static void isns_remove_portal(isns_portal_list_t *p);
-static void isnst_add_default_portals();
-static int isnst_add_default_portal_attrs(isns_pdu_t *pdu, size_t pdu_size);
-static void isnst_remove_default_portals();
+static void isnst_add_portal(iscsit_portal_t *portal);
+static void isnst_remove_portal(iscsit_portal_t *portal);
+static isns_portal_list_t *isnst_lookup_portal(struct sockaddr_storage *p,
+ isns_portal_list_t *last_portal);
+static boolean_t isnst_portal_exists(struct sockaddr_storage *p);
+static boolean_t isnst_lookup_default_portal();
+
static boolean_t isnst_retry_registration(int rsp_status_code);
it_cfg_status_t
@@ -264,8 +289,6 @@ iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
sizeof (iscsit_isns_svr_t), offsetof(iscsit_isns_svr_t, svr_ln));
list_create(&portal_list, sizeof (isns_portal_list_t),
offsetof(isns_portal_list_t, portal_ln));
- list_create(&esi_list, sizeof (isns_esi_tinfo_t),
- offsetof(isns_esi_tinfo_t, esi_ln));
portal_list_count = 0;
isns_eid = kmem_alloc(hostinfo->length, KM_SLEEP);
if (hostinfo->length > ISCSIT_MAX_HOSTNAME_LEN)
@@ -283,76 +306,27 @@ iscsit_isns_init(iscsit_hostinfo_t *hostinfo)
ISCSIT_GLOBAL_UNLOCK();
/* initialize isns client */
- mutex_init(&isns_mutex, NULL, MUTEX_DEFAULT, NULL);
- mutex_init(&isns_esi_mutex, NULL, MUTEX_DEFAULT, NULL);
+ mutex_init(&isns_monitor_mutex, NULL, MUTEX_DEFAULT, NULL);
+ mutex_init(&esi.esi_mutex, NULL, MUTEX_DEFAULT, NULL);
isns_monitor_thr_id = NULL;
monitor_idle_interval = ISNS_IDLE_TIME * drv_usectohz(1000000);
cv_init(&isns_idle_cv, NULL, CV_DEFAULT, NULL);
- cv_init(&isns_esi_cv, NULL, CV_DEFAULT, NULL);
+ cv_init(&esi.esi_cv, NULL, CV_DEFAULT, NULL);
xid = 0;
ISNS_GLOBAL_UNLOCK();
return (0);
}
-static void
-isnst_esi_stop_thread(isns_esi_tinfo_t *tinfop)
-{
- ASSERT(ISNS_GLOBAL_LOCK_HELD());
- ASSERT(mutex_owned(&isns_esi_mutex));
-
- list_remove(&esi_list, tinfop);
-
- /*
- * The only way to break a thread waiting in ksocket_accept() is to call
- * ksocket_close.
- */
- mutex_exit(&isns_esi_mutex);
- ISNS_GLOBAL_UNLOCK();
- idm_soshutdown(tinfop->esi_so);
- idm_sodestroy(tinfop->esi_so);
- thread_join(tinfop->esi_thread_did);
- ISNS_GLOBAL_LOCK();
- mutex_enter(&isns_esi_mutex);
-
- tinfop->esi_thread_running = B_FALSE;
- tinfop->esi_so = NULL;
- tinfop->esi_port = 0;
- tinfop->esi_registered = B_FALSE;
- cv_signal(&isns_esi_cv);
- tinfop->esi_portal->portal_esi = NULL;
- kmem_free(tinfop, sizeof (isns_esi_tinfo_t));
-}
-
-static void
-isnst_esi_stop()
-{
- /*
- * Basically, we just wait for all the threads to stop. They
- * should already be in the process of shutting down.
- */
-
- ASSERT(ISNS_GLOBAL_LOCK_HELD());
-
- ISNS_GLOBAL_UNLOCK();
- mutex_enter(&isns_esi_mutex);
- while (!list_is_empty(&esi_list)) {
- cv_wait(&isns_esi_cv, &isns_esi_mutex);
- }
- mutex_exit(&isns_esi_mutex);
- ISNS_GLOBAL_LOCK();
-}
-
void
iscsit_isns_fini()
{
ISNS_GLOBAL_LOCK();
iscsit_set_isns(B_FALSE);
- mutex_destroy(&isns_mutex);
+ mutex_destroy(&isns_monitor_mutex);
cv_destroy(&isns_idle_cv);
- list_destroy(&esi_list);
- mutex_destroy(&isns_esi_mutex);
- cv_destroy(&isns_esi_cv);
+ mutex_destroy(&esi.esi_mutex);
+ cv_destroy(&esi.esi_cv);
/*
* Free our EID and target list.
@@ -380,22 +354,25 @@ iscsit_set_isns(boolean_t state)
ASSERT(ISNS_GLOBAL_LOCK_HELD());
- /* reset retry count for all servers */
- for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
- svr != NULL;
- svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs, svr)) {
- svr->svr_retry_count = 0;
- }
-
/*
* Update state and isns stop flag
*/
- iscsit_global.global_isns_cfg.isns_state = state;
+ if (iscsit_global.global_isns_cfg.isns_state != state) {
+ /* reset retry count for all servers */
+ for (svr = list_head(&iscsit_global.global_isns_cfg.isns_svrs);
+ svr != NULL;
+ svr = list_next(&iscsit_global.global_isns_cfg.isns_svrs,
+ svr)) {
+ svr->svr_retry_count = 0;
+ }
- if (state) {
- isnst_start();
- } else {
- isnst_stop();
+ iscsit_global.global_isns_cfg.isns_state = state;
+
+ if (state) {
+ isnst_start();
+ } else {
+ isnst_stop();
+ }
}
}
@@ -435,13 +412,13 @@ iscsit_delete_isns(iscsit_isns_svr_t *svr)
list_remove(&iscsit_global.global_isns_cfg.isns_svrs, svr);
/* talk to this server if isns monitor is running */
- mutex_enter(&isns_mutex);
+ mutex_enter(&isns_monitor_mutex);
if (isns_monitor_thr_id != NULL) {
need_dereg = B_TRUE;
} else {
need_dereg = B_FALSE;
}
- mutex_exit(&isns_mutex);
+ mutex_exit(&isns_monitor_mutex);
if (need_dereg) {
(void) isnst_monitor_one_server(svr, B_FALSE);
@@ -571,55 +548,71 @@ iscsit_isns_target_update(iscsit_tgt_t *target)
static void
isnst_start()
{
+ ISNST_LOG(CE_NOTE, "**** isnst_start");
+
ASSERT(ISNS_GLOBAL_LOCK_HELD());
/*
- * Get target and portal lists, then start ESI threads for each portal.
+ * Get initial target list
*/
-
isnst_get_target_list();
- isnst_add_default_portals();
+
+ /*
+ * Start ESI thread(s)
+ */
+ isnst_esi_start();
/*
* Create a thread for monitoring server communications
*/
- mutex_enter(&isns_mutex);
+ isnst_monitor_start();
+}
+
+static void
+isnst_stop()
+{
+ isns_target_t *itarget;
+
+ ISNST_LOG(CE_NOTE, "**** isnst_stop");
+
+ ISNS_GLOBAL_UNLOCK();
+ isnst_esi_stop();
+ isnst_monitor_stop();
+ ISNS_GLOBAL_LOCK();
+ while ((itarget = avl_first(&isns_target_list)) != NULL) {
+ avl_remove(&isns_target_list, itarget);
+ kmem_free(itarget, sizeof (isns_target_t));
+ }
+}
+
+static void
+isnst_monitor_start(void)
+{
+ ISNST_LOG(CE_NOTE, "isnst_monitor_start");
+
+ mutex_enter(&isns_monitor_mutex);
isns_monitor_thr_id = thread_create(NULL, 0,
isnst_monitor, NULL, 0, &p0, TS_RUN, minclsyspri);
while (!isns_monitor_thr_running)
- cv_wait(&isns_idle_cv, &isns_mutex);
- mutex_exit(&isns_mutex);
+ cv_wait(&isns_idle_cv, &isns_monitor_mutex);
+ mutex_exit(&isns_monitor_mutex);
}
static void
isnst_monitor_stop(void)
{
- mutex_enter(&isns_mutex);
+ ISNST_LOG(CE_NOTE, "isnst_monitor_stop");
+
+ mutex_enter(&isns_monitor_mutex);
if (isns_monitor_thr_running) {
isns_monitor_thr_running = B_FALSE;
cv_signal(&isns_idle_cv);
- mutex_exit(&isns_mutex);
+ mutex_exit(&isns_monitor_mutex);
thread_join(isns_monitor_thr_did);
return;
}
- mutex_exit(&isns_mutex);
-}
-
-static void
-isnst_stop()
-{
- isns_target_t *itarget;
-
- isnst_remove_default_portals();
- isnst_esi_stop();
- ISNS_GLOBAL_UNLOCK();
- isnst_monitor_stop();
- ISNS_GLOBAL_LOCK();
- while ((itarget = avl_first(&isns_target_list)) != NULL) {
- avl_remove(&isns_target_list, itarget);
- kmem_free(itarget, sizeof (isns_target_t));
- }
+ mutex_exit(&isns_monitor_mutex);
}
/*
@@ -717,13 +710,13 @@ isnst_monitor_all_servers()
static void
isnst_monitor(void *arg)
{
- mutex_enter(&isns_mutex);
+ mutex_enter(&isns_monitor_mutex);
cv_signal(&isns_idle_cv);
isns_monitor_thr_did = curthread->t_did;
isns_monitor_thr_running = B_TRUE;
while (isns_monitor_thr_running) {
- mutex_exit(&isns_mutex);
+ mutex_exit(&isns_monitor_mutex);
/* Update servers */
isnst_monitor_all_servers();
@@ -732,15 +725,15 @@ isnst_monitor(void *arg)
* Keep running until isns_monitor_thr_running is set to
* B_FALSE.
*/
- mutex_enter(&isns_mutex);
+ mutex_enter(&isns_monitor_mutex);
DTRACE_PROBE(iscsit__isns__monitor__sleep);
- (void) cv_timedwait(&isns_idle_cv, &isns_mutex,
+ (void) cv_timedwait(&isns_idle_cv, &isns_monitor_mutex,
ddi_get_lbolt() + monitor_idle_interval);
DTRACE_PROBE1(iscsit__isns__monitor__wakeup,
boolean_t, isns_monitor_thr_running);
}
- mutex_exit(&isns_mutex);
+ mutex_exit(&isns_monitor_mutex);
/* Update the servers one last time for deregistration */
isnst_monitor_all_servers();
@@ -799,7 +792,7 @@ isnst_monitor_one_server(iscsit_isns_svr_t *svr, boolean_t enabled)
if (svr->svr_registered == B_TRUE) {
if (ddi_get_lbolt() < (svr->svr_last_msg +
- drv_usectohz(isns_esi_max_interval * 1000000 *
+ drv_usectohz(svr->svr_esi_interval * 1000000 *
MAX_ESI_INTERVALS))) {
return (0);
}
@@ -958,8 +951,6 @@ isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
}
}
- isnst_esi_check();
-
/* create TCP connection to the isns server */
so = isnst_open_so(&svr->svr_sa);
@@ -990,7 +981,7 @@ isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
return (-1);
}
- rc = isnst_verify_rsp(pdu, rsp);
+ rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
/*
* If we got a registration error, the server may be out of
@@ -1039,15 +1030,18 @@ isnst_register(iscsit_isns_svr_t *svr, iscsit_tgt_t *target,
}
static isns_portal_list_t *
-isns_lookup_portal(struct sockaddr_storage *p)
+isnst_lookup_portal(struct sockaddr_storage *p, isns_portal_list_t *last_portal)
{
isns_portal_list_t *portal;
- portal = list_head(&portal_list);
+ ASSERT(ISNS_GLOBAL_LOCK_HELD());
+
+ portal = (last_portal == NULL) ?
+ list_head(&portal_list) : list_next(&portal_list, last_portal);
while (portal != NULL) {
- if (bcmp(p, &portal->portal_addr,
- sizeof (struct sockaddr_storage)) == 0) {
+ if (idm_ss_compare(p, &portal->portal_addr,
+ B_TRUE /* v4_mapped_as_v4 */) == 0) {
return (portal);
}
portal = list_next(&portal_list, portal);
@@ -1056,11 +1050,37 @@ isns_lookup_portal(struct sockaddr_storage *p)
return (NULL);
}
+static boolean_t
+isnst_portal_exists(struct sockaddr_storage *p)
+{
+ return ((isnst_lookup_portal(p, NULL) != NULL) ||
+ (default_portal_online && isnst_lookup_default_portal(p)));
+}
+
static void
-isns_remove_portal(isns_portal_list_t *p)
+isnst_add_portal(iscsit_portal_t *portal)
{
- list_remove(&portal_list, p);
- kmem_free(p, sizeof (isns_portal_list_t));
+ isns_portal_list_t *new_portal;
+
+ ASSERT(ISNS_GLOBAL_LOCK_HELD());
+
+ new_portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
+ new_portal->portal_addr = portal->portal_addr;
+ new_portal->portal_iscsit = portal;
+ list_insert_tail(&portal_list, new_portal);
+ portal->portal_isns = new_portal;
+ portal_list_count++;
+
+}
+
+static void
+isnst_remove_portal(iscsit_portal_t *portal)
+{
+ ASSERT(portal->portal_isns != NULL);
+ ASSERT(ISNS_GLOBAL_LOCK_HELD());
+
+ list_remove(&portal_list, portal->portal_isns);
+ kmem_free(portal->portal_isns, sizeof (isns_portal_list_t));
portal_list_count--;
}
@@ -1079,14 +1099,7 @@ isnst_add_to_target_list(iscsit_tgt_t *target)
tmptgt.target = target;
if ((itarget = (isns_target_t *)avl_find(&isns_target_list,
&tmptgt, NULL)) == NULL) {
- itarget = kmem_zalloc(sizeof (isns_target_t), KM_NOSLEEP);
-
- /*
- * If we can't get memory, we're not going to be able to
- * register this target. This needs to be fixed up.
- */
- if (itarget == NULL)
- return (NULL);
+ itarget = kmem_zalloc(sizeof (isns_target_t), KM_SLEEP);
itarget->target = target;
avl_add(&isns_target_list, itarget);
@@ -1095,72 +1108,15 @@ isnst_add_to_target_list(iscsit_tgt_t *target)
return (itarget);
}
-static int
-isnst_add_default_portal_attrs(isns_pdu_t *pdu, size_t pdu_size)
-{
- isns_portal_list_t *portal;
- struct sockaddr_in *in;
- struct sockaddr_in6 *in6;
- int idx = 0;
- uint32_t attr_data;
- void *inaddrp;
-
- portal = list_head(&portal_list);
-
- while (portal) {
- if (idx == nondefault_portals) {
- break;
- }
-
- if (portal->portal_iscsit == NULL) {
- in = (struct sockaddr_in *)&portal->portal_addr;
-
- if (in->sin_family == AF_INET) {
- attr_data = sizeof (in_addr_t);
- inaddrp = (void *)&in->sin_addr;
- } else if (in->sin_family == AF_INET6) {
- in6 = (struct sockaddr_in6 *)
- &portal->portal_addr;
- attr_data = sizeof (in6_addr_t);
- inaddrp = (void *)&in6->sin6_addr;
- } else {
- return (-1);
- }
-
- if (isnst_add_attr(pdu, pdu_size,
- ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 16, inaddrp,
- attr_data) != 0) {
- return (-1);
- }
-
- /* Portal Group Portal Port */
- if (isnst_add_attr(pdu, pdu_size,
- ISNS_PG_PORTAL_PORT_ATTR_ID, 4, 0,
- ntohs(in->sin_port)) != 0) {
- return (-1);
- }
-
- idx++;
- }
-
- portal = list_next(&portal_list, portal);
- }
-
- return (0);
-}
-
static size_t
isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
boolean_t svr_registered, isns_reg_type_t regtype)
{
+ idm_addr_list_t *default_portal_list = NULL;
+ uint32_t default_portal_list_size;
size_t pdu_size;
- iscsit_tpgt_t *tpgt;
- iscsit_tpg_t *tpg;
- iscsit_portal_t *tp;
char *str;
int len;
- isns_portal_list_t *portal;
- isns_esi_tinfo_t *tinfop;
isns_target_t *itarget;
iscsit_tgt_t *src;
boolean_t reg_all = B_FALSE;
@@ -1169,6 +1125,22 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
ASSERT(ISNS_GLOBAL_LOCK_HELD());
/*
+ * If any targets are using the default portal then get the global
+ * list of portals.
+ */
+ if (default_portal_online) {
+ default_portal_list_size = idm_get_ipaddr(&default_portal_list);
+
+ if (default_portal_list_size == 0) {
+ /*
+ * If the default portal is online, then there should
+ * be at least one default portal.
+ */
+ return (0);
+ }
+ }
+
+ /*
* Find a source attribute for this registration.
*
* If we're already registered, registering for the first time, or
@@ -1196,9 +1168,12 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
* we're already registered.
*/
- if ((target == NULL) || (regtype == ISNS_UPDATE_TARGET)) {
+ if ((target == NULL) || (regtype == ISNS_UPDATE_TARGET) ||
+ ((regtype == ISNS_REGISTER_TARGET) &&
+ default_portal_state_change)) {
reg_all = B_TRUE;
target = src; /* This will be the 1st tgt in our list */
+ default_portal_state_change = B_FALSE;
/*
* If we're already registered, this will be a replacement
@@ -1219,6 +1194,9 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
pdu_size = isnst_create_pdu_header(ISNS_DEV_ATTR_REG, pdu, flags);
if (pdu_size == 0) {
+ if (default_portal_list)
+ kmem_free(default_portal_list,
+ default_portal_list_size);
return (0);
}
@@ -1261,55 +1239,10 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
/*
* Network entity portal information - only on the first registration.
*/
-
- if (svr_registered == B_FALSE) {
- struct sockaddr_in *sin;
- int addrsize;
-
- portal = list_head(&portal_list);
-
- while (portal != NULL) {
- sin = (struct sockaddr_in *)&portal->portal_addr;
- tinfop = portal->portal_esi;
-
- if (portal->portal_iscsit == NULL) {
- if (sin->sin_family == AF_INET) {
- addrsize = sizeof (struct in_addr);
- } else {
- addrsize = sizeof (struct in6_addr);
- }
-
- /* Portal IP Address */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_PORTAL_IP_ADDR_ATTR_ID, 16,
- &sin->sin_addr, addrsize) != 0) {
- goto pdu_error;
- }
-
- /* Portal Port */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_PORTAL_PORT_ATTR_ID, 4, 0,
- ntohs(sin->sin_port)) != 0) {
- goto pdu_error;
- }
-
- if (tinfop && tinfop->esi_port) {
- /* ESI interval and port */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_ESI_INTERVAL_ATTR_ID, 4,
- NULL, 20) != 0) {
- goto pdu_error;
- }
-
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_ESI_PORT_ATTR_ID, 4, NULL,
- tinfop->esi_port) != 0) {
- goto pdu_error;
- }
- }
- }
-
- portal = list_next(&portal_list, portal);
+ if (!svr_registered || (flags & ISNS_FLAG_REPLACE_REG)) {
+ if (isnst_reg_pdu_add_entity_portals(*pdu, pdu_size,
+ default_portal_list) != 0) {
+ goto pdu_error;
}
}
@@ -1335,12 +1268,9 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
}
/* iSCSI Alias */
-#if 0
- str = target->target_alias;
-#else
- str = "Solaris iSCSI Target";
-#endif
- if (str != NULL) {
+ if (nvlist_lookup_string(target->target_props, PROP_ALIAS,
+ &str) == 0) {
+ /* Found alias in property list */
len = strlen(str) + 1;
if (isnst_add_attr(*pdu, pdu_size,
ISNS_ISCSI_ALIAS_ATTR_ID, len, str, 0) != 0) {
@@ -1349,99 +1279,11 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
}
}
- /* for each target portal group (start)... */
- tpgt = avl_first(&target->target_tpgt_list);
- ASSERT(tpgt != NULL);
- do {
- /* no need to explicitly register default PG */
- if ((tpgt->tpgt_tag == ISCSIT_DEFAULT_TPGT) &&
- (avl_numnodes(&target->target_tpgt_list) == 1)) {
- tpgt = AVL_NEXT(&target->target_tpgt_list,
- tpgt);
- continue;
- }
-
- tpg = tpgt->tpgt_tpg;
- mutex_enter(&tpg->tpg_mutex);
-
- tp = avl_first(&tpg->tpg_portal_list);
-
- /* Portal Group Tag */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_PG_TAG_ATTR_ID, 4, 0, tpgt->tpgt_tag) != 0) {
- mutex_exit(&tpg->tpg_mutex);
- mutex_exit(&target->target_mutex);
- goto pdu_error;
- }
-
- ASSERT(tp != NULL);
- do {
- struct sockaddr_storage *ss;
- struct sockaddr_in *in;
- struct sockaddr_in6 *in6;
- uint32_t attr_numeric_data;
- void *inaddrp;
-
- ss = &tp->portal_addr;
- in = (struct sockaddr_in *)ss;
- in6 = (struct sockaddr_in6 *)ss;
-
- if (ss->ss_family == AF_INET) {
- attr_numeric_data = sizeof (in_addr_t);
- inaddrp = (void *)&in->sin_addr;
- } else if (ss->ss_family == AF_INET6) {
- attr_numeric_data = sizeof (in6_addr_t);
- inaddrp = (void *)&in6->sin6_addr;
- } else if (ss->ss_family == 0) {
- /*
- * Need to add all default portals
- */
- attr_numeric_data = 0;
- } else {
- cmn_err(CE_WARN, "Unknown address "
- "family for portal %p", (void *)tp);
- mutex_exit(&tpg->tpg_mutex);
- mutex_exit(&target->target_mutex);
- goto pdu_error;
- }
-
- if (attr_numeric_data == 0) {
- if (isnst_add_default_portal_attrs(*pdu,
- pdu_size) != 0) {
- mutex_exit(&tpg->tpg_mutex);
- mutex_exit(&target->
- target_mutex);
- goto pdu_error;
- }
- } else {
- /* Portal Group Portal IP Address */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, 16,
- inaddrp, attr_numeric_data) != 0) {
- mutex_exit(&tpg->tpg_mutex);
- mutex_exit(&target->
- target_mutex);
- goto pdu_error;
- }
-
- /* Portal Group Portal Port */
- if (isnst_add_attr(*pdu, pdu_size,
- ISNS_PG_PORTAL_PORT_ATTR_ID,
- 4, 0, ntohs(in->sin_port)) != 0) {
- mutex_exit(&tpg->tpg_mutex);
- mutex_exit(&target->
- target_mutex);
- goto pdu_error;
- }
- }
-
- tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
- } while (tp != NULL);
-
- mutex_exit(&tpg->tpg_mutex);
- tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
- } while (tpgt != NULL);
- /* for each target portal group (end)... */
+ if (isnst_reg_pdu_add_pg(*pdu, pdu_size, target,
+ default_portal_list) != 0) {
+ mutex_exit(&target->target_mutex);
+ goto pdu_error;
+ }
mutex_exit(&target->target_mutex);
@@ -1455,12 +1297,316 @@ isnst_make_reg_pdu(isns_pdu_t **pdu, iscsit_tgt_t *target,
}
} while ((reg_all == B_TRUE) && (target != NULL));
+ if (default_portal_list)
+ kmem_free(default_portal_list, default_portal_list_size);
+
return (pdu_size);
pdu_error:
/* packet too large, no memory */
kmem_free(*pdu, pdu_size);
*pdu = NULL;
+ if (default_portal_list)
+ kmem_free(default_portal_list, default_portal_list_size);
+
+ return (0);
+}
+
+
+static int
+isnst_reg_pdu_add_entity_portals(isns_pdu_t *pdu, size_t pdu_size,
+ idm_addr_list_t *default_portal_list)
+{
+ isns_portal_list_t *portal;
+ idm_addr_t *dportal;
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int idx;
+ int dp_addr_size;
+
+ if (default_portal_list != NULL) {
+ for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
+ dportal = &default_portal_list->al_addrs[idx];
+
+ /* Build sockaddr_storage for this portal */
+ bzero(&ss, sizeof (ss));
+ dp_addr_size = dportal->a_addr.i_insize;
+ if (dp_addr_size == sizeof (struct in_addr)) {
+ /* IPv4 */
+ ss.ss_family = AF_INET;
+ sin = (struct sockaddr_in *)&ss;
+ sin->sin_port = htons(ISCSI_LISTEN_PORT);
+ bcopy(&dportal->a_addr.i_addr.in4,
+ &sin->sin_addr, sizeof (struct in_addr));
+ } else if (dp_addr_size == sizeof (struct in6_addr)) {
+ ss.ss_family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
+ bcopy(&dportal->a_addr.i_addr.in6,
+ &sin6->sin6_addr, sizeof (struct in6_addr));
+ } else {
+ continue;
+ }
+
+ if (isnst_add_portal_attr(pdu, pdu_size,
+ ISNS_PORTAL_IP_ADDR_ATTR_ID,
+ ISNS_PORTAL_PORT_ATTR_ID,
+ &ss, B_TRUE /* ESI info */) != 0) {
+ return (-1);
+ }
+
+ }
+ } else {
+ portal = list_head(&portal_list);
+
+ while (portal != NULL) {
+ if (isnst_add_portal_attr(pdu, pdu_size,
+ ISNS_PORTAL_IP_ADDR_ATTR_ID,
+ ISNS_PORTAL_PORT_ATTR_ID,
+ &portal->portal_addr, B_TRUE /* ESI info */) != 0) {
+ return (-1);
+ }
+
+ portal = list_next(&portal_list, portal);
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+isnst_reg_pdu_add_pg(isns_pdu_t *pdu, size_t pdu_size, iscsit_tgt_t *target,
+ idm_addr_list_t *default_portal_list)
+{
+ iscsit_tpgt_t *tpgt;
+ iscsit_tpg_t *tpg;
+ iscsit_portal_t *tp;
+ int rval = 0;
+ boolean_t use_default = B_FALSE;
+
+
+ tpgt = avl_first(&target->target_tpgt_list);
+ ASSERT(tpgt != NULL);
+ do {
+ /*
+ * No need to explicitly register default PG. Any target
+ * should have either an explicit portal list or
+ * one and only one portal representing the default portal.
+ */
+ ASSERT((avl_numnodes(&target->target_tpgt_list) == 1) ||
+ (tpgt->tpgt_tag != ISCSIT_DEFAULT_TPGT));
+ if (tpgt->tpgt_tag == ISCSIT_DEFAULT_TPGT) {
+ use_default = B_TRUE;
+ tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
+ continue;
+ }
+
+ tpg = tpgt->tpgt_tpg;
+ mutex_enter(&tpg->tpg_mutex);
+
+ tp = avl_first(&tpg->tpg_portal_list);
+
+ /* Portal Group Tag */
+ if (isnst_add_attr(pdu, pdu_size,
+ ISNS_PG_TAG_ATTR_ID, 4, 0, tpgt->tpgt_tag) != 0) {
+ mutex_exit(&tpg->tpg_mutex);
+ rval = 1;
+ goto pg_done;
+ }
+
+ ASSERT(tp != NULL);
+ do {
+ if (isnst_add_portal_attr(pdu, pdu_size,
+ ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
+ ISNS_PG_PORTAL_PORT_ATTR_ID,
+ &tp->portal_addr, B_FALSE /* ESI */) != 0) {
+ mutex_exit(&tpg->tpg_mutex);
+ rval = 1;
+ goto pg_done;
+ }
+
+ tp = AVL_NEXT(&tpg->tpg_portal_list, tp);
+ } while (tp != NULL);
+
+ mutex_exit(&tpg->tpg_mutex);
+ tpgt = AVL_NEXT(&target->target_tpgt_list, tpgt);
+ } while (tpgt != NULL);
+
+ /*
+ * If we are not using the default portal group we need to create
+ * a NULL PG tag indicating some of the default portals should be
+ * not be used to access this target.
+ */
+ if (!use_default) {
+ if (isnst_add_null_pg(pdu, pdu_size, target,
+ default_portal_list) != 0) {
+ rval = 1;
+ goto pg_done;
+ }
+ }
+
+pg_done:
+ return (rval);
+}
+
+static int
+isnst_add_null_pg(isns_pdu_t *pdu, size_t pdu_size,
+ iscsit_tgt_t *tgt, idm_addr_list_t *default_portal_list)
+{
+ isns_portal_list_t *portal;
+ idm_addr_t *dportal;
+ iscsit_portal_t *iscsit_portal;
+ iscsit_tpgt_t *iscsit_tpgt;
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int idx;
+ int dp_addr_size;
+ boolean_t null_pg_tag = B_FALSE;
+
+ /*
+ * Register all entity portals that aren't bound to this target in the
+ * null pg.
+ */
+ if (default_portal_list != NULL) {
+ for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
+ dportal = &default_portal_list->al_addrs[idx];
+
+ /* Build sockaddr_storage for this portal */
+ bzero(&ss, sizeof (ss));
+ dp_addr_size = dportal->a_addr.i_insize;
+ if (dp_addr_size == sizeof (struct in_addr)) {
+ /* IPv4 */
+ ss.ss_family = AF_INET;
+ sin = (struct sockaddr_in *)&ss;
+ sin->sin_port = htons(ISCSI_LISTEN_PORT);
+ bcopy(&dportal->a_addr.i_addr.in4,
+ &sin->sin_addr, sizeof (struct in_addr));
+ } else if (dp_addr_size == sizeof (struct in6_addr)) {
+ ss.ss_family = AF_INET6;
+ sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
+ bcopy(&dportal->a_addr.i_addr.in6,
+ &sin6->sin6_addr, sizeof (struct in6_addr));
+ } else {
+ continue;
+ }
+
+ iscsit_portal = iscsit_tgt_lookup_portal(tgt,
+ &ss, &iscsit_tpgt);
+ if (iscsit_portal == NULL) {
+ /*
+ * If this is the first NULL PG portal, then
+ * write the NULL PG tag first.
+ */
+ if (!null_pg_tag) {
+ if (isnst_add_attr(pdu, pdu_size,
+ ISNS_PG_TAG_ATTR_ID,
+ 0, 0, 0) != 0) {
+ return (-1);
+ }
+ null_pg_tag = B_TRUE;
+ }
+ if (isnst_add_portal_attr(pdu, pdu_size,
+ ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
+ ISNS_PG_PORTAL_PORT_ATTR_ID,
+ &ss, B_FALSE) != 0) {
+ return (-1);
+ }
+ } else {
+ iscsit_tpgt_rele(iscsit_tpgt);
+ iscsit_portal_rele(iscsit_portal);
+ }
+ }
+ } else {
+ portal = list_head(&portal_list);
+
+ while (portal != NULL) {
+ iscsit_portal = iscsit_tgt_lookup_portal(tgt,
+ &portal->portal_addr, &iscsit_tpgt);
+ if (iscsit_portal == NULL) {
+ /*
+ * If this is the first NULL PG portal, then
+ * write the NULL PG tag first.
+ */
+ if (!null_pg_tag) {
+ if (isnst_add_attr(pdu, pdu_size,
+ ISNS_PG_TAG_ATTR_ID,
+ 0, 0, 0) != 0) {
+ return (-1);
+ }
+ null_pg_tag = B_TRUE;
+ }
+ if (isnst_add_portal_attr(pdu, pdu_size,
+ ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
+ ISNS_PG_PORTAL_PORT_ATTR_ID,
+ &portal->portal_addr, B_FALSE) != 0) {
+ return (-1);
+ }
+ } else {
+ iscsit_tpgt_rele(iscsit_tpgt);
+ iscsit_portal_rele(iscsit_portal);
+ }
+
+ portal = list_next(&portal_list, portal);
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+isnst_add_portal_attr(isns_pdu_t *pdu, size_t pdu_size,
+ uint32_t ip_attr_id, uint32_t port_attr_id,
+ struct sockaddr_storage *ss, boolean_t esi_info)
+{
+ struct sockaddr_in *in;
+ struct sockaddr_in6 *in6;
+ uint32_t attr_numeric_data;
+ void *inaddrp;
+
+ in = (struct sockaddr_in *)ss;
+ in6 = (struct sockaddr_in6 *)ss;
+
+ ASSERT((ss->ss_family == AF_INET) || (ss->ss_family == AF_INET6));
+
+ if (ss->ss_family == AF_INET) {
+ attr_numeric_data = sizeof (in_addr_t);
+ inaddrp = (void *)&in->sin_addr;
+ } else if (ss->ss_family == AF_INET6) {
+ attr_numeric_data = sizeof (in6_addr_t);
+ inaddrp = (void *)&in6->sin6_addr;
+ }
+
+ /* Portal Group Portal IP Address */
+ if (isnst_add_attr(pdu, pdu_size, ip_attr_id,
+ 16, inaddrp, attr_numeric_data) != 0) {
+ return (1);
+ }
+
+ /* Portal Group Portal Port */
+ if (isnst_add_attr(pdu, pdu_size, port_attr_id,
+ 4, 0, ntohs(in->sin_port)) != 0) {
+ return (1);
+ }
+
+ mutex_enter(&esi.esi_mutex);
+ if (esi_info && esi.esi_valid) {
+ /* ESI interval and port */
+ if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_INTERVAL_ATTR_ID, 4,
+ NULL, 20) != 0) {
+ return (1);
+ }
+
+ if (isnst_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4,
+ NULL, esi.esi_port) != 0) {
+ return (1);
+ }
+ }
+ mutex_exit(&esi.esi_mutex);
return (0);
}
@@ -1504,7 +1650,7 @@ isnst_deregister(iscsit_isns_svr_t *svr, char *node)
return (-1);
}
- rc = isnst_verify_rsp(pdu, rsp);
+ rc = isnst_verify_rsp(svr, pdu, rsp, rsp_size);
isnst_close_so(so);
kmem_free(pdu, pdu_size);
@@ -1582,7 +1728,8 @@ dereg_pdu_error:
}
static int
-isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
+isnst_verify_rsp(iscsit_isns_svr_t *svr, isns_pdu_t *pdu,
+ isns_pdu_t *rsp, size_t rsp_size)
{
uint16_t func_id;
uint16_t payload_len, rsp_payload_len;
@@ -1591,6 +1738,25 @@ isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
isns_tlv_t *attr;
uint32_t attr_len, attr_id, esi_interval;
+ /*
+ * Ensure we have at least a valid header (don't count the
+ * "payload" field.
+ */
+ if (rsp_size < offsetof(isns_pdu_t, payload)) {
+ ISNST_LOG(CE_WARN, "Invalid iSNS PDU header, %d of %d bytes",
+ (int)rsp_size, (int)offsetof(isns_pdu_t, payload));
+ return (-1);
+ }
+
+ /* Make sure we have the amount of data that the header specifies */
+ payload_len = ntohs(rsp->payload_len);
+ if (rsp_size < (payload_len + offsetof(isns_pdu_t, payload))) {
+ ISNST_LOG(CE_WARN, "Invalid iSNS response, %d of %d bytes",
+ (int)rsp_size,
+ (int)(payload_len + offsetof(isns_pdu_t, payload)));
+ return (-1);
+ }
+
/* validate response function id */
func_id = ntohs(rsp->func_id);
switch (ntohs(pdu->func_id)) {
@@ -1610,6 +1776,14 @@ isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
rsp_payload_len = isnst_pdu_get_op(rsp, &pp);
attr = (isns_tlv_t *)((void *)pp);
+ /*
+ * Make sure isnst_pdu_get_op didn't encounter an error
+ * in the attributes.
+ */
+ if (pp == NULL) {
+ return (-1);
+ }
+
while (rsp_payload_len) {
attr_len = ntohl(attr->attr_len);
attr_id = ntohl(attr->attr_id);
@@ -1619,8 +1793,8 @@ isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
ntohl(*((uint32_t *)
((void *)(&attr->attr_value))));
- if (esi_interval > isns_esi_max_interval)
- isns_esi_max_interval = esi_interval;
+ if (esi_interval > svr->svr_esi_interval)
+ svr->svr_esi_interval = esi_interval;
break;
}
@@ -1647,11 +1821,7 @@ isnst_verify_rsp(isns_pdu_t *pdu, isns_pdu_t *rsp)
}
/* check the error code */
- payload_len = ntohs(rsp->payload_len);
resp = (isns_resp_t *)((void *)&rsp->payload[0]);
- if (payload_len < 4) {
- return (-1);
- }
return (ntohl(resp->status));
}
@@ -1671,13 +1841,20 @@ isnst_pdu_get_op(isns_pdu_t *pdu, uint8_t **pp)
resp = (isns_resp_t *)((void *)&pdu->payload[0]);
/* find the operating attributes */
- ASSERT(payload_len >= 4);
- payload_len -= 4;
+ if (payload_len < sizeof (resp->status)) {
+ ISNST_LOG(CE_WARN, "Invalid iSNS response, %d payload bytes",
+ payload_len);
+ *pp = NULL;
+ return (0);
+ }
+
+ payload_len -= sizeof (resp->status);
payload = &resp->data[0];
- while (payload_len >= 8) {
+ while (payload_len >= (sizeof (isns_tlv_t) - 1)) {
attr = (isns_tlv_t *)((void *)payload);
- tlv_len = 8 + ntohl(attr->attr_len);
+ tlv_len = offsetof(isns_tlv_t, attr_value) +
+ ntohl(attr->attr_len);
if (payload_len >= tlv_len) {
payload += tlv_len;
payload_len -= tlv_len;
@@ -2031,7 +2208,7 @@ isnst_open_so(struct sockaddr_storage *sa)
ip = (void *)&sin6->sin6_addr.s6_addr;
(void) inet_ntop(AF_INET6, ip, s, sizeof (s));
}
- cmn_err(CE_WARN, "open iSNS Server %s:%u failed", s, port);
+ ISNST_LOG(CE_WARN, "open iSNS Server %s:%u failed", s, port);
}
return (so);
@@ -2050,82 +2227,45 @@ isnst_close_so(void *so)
*/
static void
-isnst_esi_start_thread(isns_esi_tinfo_t *tinfop)
+isnst_esi_start(void)
{
- tinfop->esi_thread_running = B_FALSE;
- tinfop->esi_thread_failed = B_FALSE;
- tinfop->esi_registered = B_FALSE;
- tinfop->esi_thread = thread_create(NULL, 0, isnst_esi_thread,
- (void *)tinfop, 0, &p0, TS_RUN, minclsyspri);
+ ASSERT(ISNS_GLOBAL_LOCK_HELD());
+
+ ISNST_LOG(CE_NOTE, "isnst_esi_start");
- mutex_enter(&isns_esi_mutex);
- list_insert_tail(&esi_list, tinfop);
+ mutex_enter(&esi.esi_mutex);
+ esi.esi_enabled = B_TRUE;
+ esi.esi_thread_running = B_FALSE;
+ esi.esi_valid = B_FALSE;
+ esi.esi_thread = thread_create(NULL, 0, isnst_esi_thread,
+ (void *)&esi, 0, &p0, TS_RUN, minclsyspri);
/*
* Wait for the thread to start
*/
-
- while (!tinfop->esi_thread_running && !tinfop->esi_thread_failed) {
- cv_wait(&isns_esi_cv, &isns_esi_mutex);
+ while (!esi.esi_thread_running) {
+ cv_wait(&esi.esi_cv, &esi.esi_mutex);
}
-
- mutex_exit(&isns_esi_mutex);
+ mutex_exit(&esi.esi_mutex);
}
static void
-isnst_esi_start(isns_portal_list_t *portal)
+isnst_esi_stop()
{
- isns_esi_tinfo_t *tinfop;
-
- ASSERT(ISNS_GLOBAL_LOCK_HELD());
-
- /*
- * Allocate our ESI thread info structure
- */
-
- tinfop = (isns_esi_tinfo_t *)
- kmem_zalloc(sizeof (isns_esi_tinfo_t), KM_NOSLEEP);
-
- if (tinfop == NULL) {
- cmn_err(CE_WARN, "isnst_esi_start: Cant alloc ESI");
- return;
+ ISNST_LOG(CE_NOTE, "isnst_esi_stop");
+
+ /* Shutdown ESI listening socket, wait for thread to terminate */
+ mutex_enter(&esi.esi_mutex);
+ esi.esi_enabled = B_FALSE;
+ if (esi.esi_valid) {
+ idm_soshutdown(esi.esi_so);
+ mutex_exit(&esi.esi_mutex);
+ idm_sodestroy(esi.esi_so);
+ } else {
+ mutex_exit(&esi.esi_mutex);
}
+ thread_join(esi.esi_thread_did);
- tinfop->esi_portal = portal;
- portal->portal_esi = tinfop;
- isnst_esi_start_thread(tinfop);
-}
-
-/*
- * isnst_esi_check
- *
- * Verify that all the ESI threads are running and try to restart any that
- * failed for any reason.
- */
-
-static void
-isnst_esi_check()
-{
- isns_portal_list_t *portal;
- isns_esi_tinfo_t *tinfop;
-
- /*
- * Now, threads for new portals or those which stopped for some other
- * reason will be started.
- */
-
- portal = list_head(&portal_list);
-
- while (portal) {
- tinfop = portal->portal_esi;
-
- if (tinfop && (!tinfop->esi_thread_running ||
- tinfop->esi_thread_failed)) {
- isnst_esi_start_thread(tinfop);
- }
-
- portal = list_next(&portal_list, portal);
- }
}
/*
@@ -2135,184 +2275,157 @@ isnst_esi_check()
* iSNS server until told to stop.
*/
+/*ARGSUSED*/
static void
isnst_esi_thread(void *arg)
{
- isns_esi_tinfo_t *tinfop;
ksocket_t newso;
- struct sockaddr_in sin;
struct sockaddr_in6 sin6;
- uint32_t on;
+ socklen_t sin_addrlen;
+ uint32_t on = 1;
int rc;
isns_pdu_t *pdu;
size_t pl_size;
- int family;
- struct sockaddr_in t_addr;
- struct sockaddr_in6 t_addr6;
- socklen_t t_addrlen;
- socklen_t t_addrlen6;
- bzero(&t_addr, sizeof (struct sockaddr_in6));
- t_addrlen = sizeof (struct sockaddr_in);
- t_addrlen6 = sizeof (struct sockaddr_in6);
+ bzero(&sin6, sizeof (struct sockaddr_in6));
+ sin_addrlen = sizeof (struct sockaddr_in6);
- tinfop = (isns_esi_tinfo_t *)arg;
- tinfop->esi_thread_did = curthread->t_did;
+ esi.esi_thread_did = curthread->t_did;
- /*
- * Create a socket to listen for requests from the iSNS server.
- */
+ mutex_enter(&esi.esi_mutex);
- if (tinfop->esi_portal->portal_addr.ss_family == AF_INET) {
- family = AF_INET;
- } else {
- family = AF_INET6;
- }
-
- if ((tinfop->esi_so =
- idm_socreate(family, SOCK_STREAM, 0)) == NULL) {
- cmn_err(CE_WARN,
- "isnst_esi_thread: Unable to create socket");
- tinfop->esi_thread_failed = B_TRUE;
- mutex_enter(&isns_esi_mutex);
- cv_signal(&isns_esi_cv);
- mutex_exit(&isns_esi_mutex);
- thread_exit();
- }
- ksocket_hold(tinfop->esi_so);
/*
- * Set options, bind, and listen until we're told to stop
+ * Mark the thread as running and the portal as no longer new.
*/
+ esi.esi_thread_running = B_TRUE;
+ cv_signal(&esi.esi_cv);
- switch (family) {
- case AF_INET:
- bzero(&sin, sizeof (sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(0);
- bcopy(((caddr_t)&tinfop->esi_portal->portal_addr +
- offsetof(struct sockaddr_in, sin_addr)),
- &sin.sin_addr.s_addr, sizeof (in_addr_t));
- on = 1;
-
- (void) ksocket_setsockopt(tinfop->esi_so, SOL_SOCKET,
- SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
-
- if (ksocket_bind(tinfop->esi_so, (struct sockaddr *)&sin,
- sizeof (sin), CRED()) != 0) {
- idm_sodestroy(tinfop->esi_so);
- tinfop->esi_so = NULL;
- tinfop->esi_thread_failed = B_TRUE;
- } else {
- (void) ksocket_getsockname(tinfop->esi_so,
- (struct sockaddr *)(&t_addr), &t_addrlen, CRED());
- tinfop->esi_port = ntohs(((struct sockaddr_in *)
- (&t_addr))->sin_port);
+ while (esi.esi_enabled) {
+ /*
+ * Create a socket to listen for requests from the iSNS server.
+ */
+ DTRACE_PROBE1(iscsit__isns__esi__socreate,
+ boolean_t, esi.esi_enabled);
+ if ((esi.esi_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) ==
+ NULL) {
+ ISNST_LOG(CE_WARN,
+ "isnst_esi_thread: Unable to create socket");
+ mutex_exit(&esi.esi_mutex);
+ delay(drv_usectohz(1000000));
+ mutex_enter(&esi.esi_mutex);
+ continue;
}
- break;
-
- case AF_INET6:
+ /*
+ * Set options, bind, and listen until we're told to stop
+ */
bzero(&sin6, sizeof (sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(0);
- bcopy(((caddr_t)&tinfop->esi_portal->portal_addr +
- offsetof(struct sockaddr_in6, sin6_addr)),
- &sin6.sin6_addr.s6_addr, sizeof (in6_addr_t));
- on = 1;
+ sin6.sin6_addr = in6addr_any;
- (void) ksocket_setsockopt(tinfop->esi_so, SOL_SOCKET,
+ (void) ksocket_setsockopt(esi.esi_so, SOL_SOCKET,
SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
- if (ksocket_bind(tinfop->esi_so, (struct sockaddr *)&sin6,
+ if (ksocket_bind(esi.esi_so, (struct sockaddr *)&sin6,
sizeof (sin6), CRED()) != 0) {
- idm_sodestroy(tinfop->esi_so);
- tinfop->esi_so = NULL;
- tinfop->esi_thread_failed = B_TRUE;
- } else {
- (void) ksocket_getsockname(tinfop->esi_so,
- (struct sockaddr *)(&t_addr6), &t_addrlen6, CRED());
- tinfop->esi_port = ntohs(((struct sockaddr_in6 *)
- (&t_addr6))->sin6_port);
+ ISNST_LOG(CE_WARN, "Unable to bind socket for ESI");
+ idm_sodestroy(esi.esi_so);
+ mutex_exit(&esi.esi_mutex);
+ delay(drv_usectohz(1000000));
+ mutex_enter(&esi.esi_mutex);
+ continue;
}
- break;
- }
-
- if (tinfop->esi_thread_failed) {
- cmn_err(CE_WARN, "Unable to bind socket for ESI");
- goto esi_thread_exit;
- }
-
- if ((rc = ksocket_listen(tinfop->esi_so, 5, CRED())) != 0) {
- cmn_err(CE_WARN, "isnst_esi_thread: listen failure 0x%x", rc);
- goto esi_thread_exit;
- }
+ /*
+ * Get the port (sin6 is meaningless at this point)
+ */
+ (void) ksocket_getsockname(esi.esi_so,
+ (struct sockaddr *)(&sin6), &sin_addrlen, CRED());
+ esi.esi_port =
+ ntohs(((struct sockaddr_in6 *)(&sin6))->sin6_port);
+
+ if ((rc = ksocket_listen(esi.esi_so, 5, CRED())) != 0) {
+ ISNST_LOG(CE_WARN, "isnst_esi_thread: listen "
+ "failure 0x%x", rc);
+ idm_sodestroy(esi.esi_so);
+ mutex_exit(&esi.esi_mutex);
+ delay(drv_usectohz(1000000));
+ mutex_enter(&esi.esi_mutex);
+ continue;
+ }
- mutex_enter(&isns_esi_mutex);
- /*
- * Mark the thread as running and the portal as no longer new.
- */
- tinfop->esi_thread_running = B_TRUE;
- cv_signal(&isns_esi_cv);
-
- while (tinfop->esi_thread_running && !tinfop->esi_thread_failed) {
- mutex_exit(&isns_esi_mutex);
-
- DTRACE_PROBE2(iscsit__isns__esi__accept__wait,
- boolean_t, tinfop->esi_thread_running,
- boolean_t, tinfop->esi_thread_failed);
- if ((rc = ksocket_accept(tinfop->esi_so, NULL, NULL,
- &newso, CRED())) != 0) {
- mutex_enter(&isns_esi_mutex);
- DTRACE_PROBE2(iscsit__isns__esi__accept__fail,
- boolean_t, tinfop->esi_thread_running,
- boolean_t, tinfop->esi_thread_failed);
- /*
- * If we were interrupted with EINTR
- * it's not really a failure.
- */
- if (rc != EINTR) {
- cmn_err(CE_WARN, "isnst_esi_thread: "
+ ksocket_hold(esi.esi_so);
+ esi.esi_valid = B_TRUE;
+ while (esi.esi_enabled) {
+ mutex_exit(&esi.esi_mutex);
+
+ DTRACE_PROBE1(iscsit__isns__esi__accept__wait,
+ boolean_t, esi.esi_enabled);
+ if ((rc = ksocket_accept(esi.esi_so, NULL, NULL,
+ &newso, CRED())) != 0) {
+ mutex_enter(&esi.esi_mutex);
+ DTRACE_PROBE2(iscsit__isns__esi__accept__fail,
+ int, rc, boolean_t, esi.esi_enabled);
+ /*
+ * If we were interrupted with EINTR
+ * it's not really a failure.
+ */
+ ISNST_LOG(CE_WARN, "isnst_esi_thread: "
"accept failure (0x%x)", rc);
- tinfop->esi_thread_failed = B_TRUE;
+
+ delay(drv_usectohz(100000));
+ if (rc == EINTR) {
+ continue;
+ } else {
+ break;
+ }
}
- tinfop->esi_thread_running = B_FALSE;
- continue;
- }
- DTRACE_PROBE3(iscsit__isns__esi__accept,
- boolean_t, tinfop->esi_thread_running,
- boolean_t, tinfop->esi_thread_failed,
- struct sonode *, newso);
+ DTRACE_PROBE2(iscsit__isns__esi__accept,
+ boolean_t, esi.esi_enabled,
+ ksocket_t, newso);
+
+ pl_size = isnst_rcv_pdu(newso, &pdu);
+ if (pl_size == 0) {
+ ISNST_LOG(CE_WARN, "isnst_esi_thread: "
+ "rcv_pdu failure");
+ (void) ksocket_close(newso, CRED());
- mutex_enter(&isns_esi_mutex);
+ mutex_enter(&esi.esi_mutex);
+ continue;
+ }
- pl_size = isnst_rcv_pdu(newso, &pdu);
+ isnst_handle_esi_req(newso, pdu, pl_size);
- if (pl_size == 0) {
- cmn_err(CE_WARN, "isnst_esi_thread: rcv_pdu failure");
- tinfop->esi_thread_failed = B_TRUE;
- continue;
- }
+ (void) ksocket_close(newso, CRED());
- if (isnst_handle_esi_req(newso, pdu, pl_size) == B_TRUE) {
- tinfop->esi_registered = B_TRUE;
+ /*
+ * Do not hold the esi mutex during server timestamp
+ * update. It requires the isns global lock, which may
+ * be held during other functions that also require
+ * the esi_mutex (potential deadlock).
+ */
+ isnst_update_server_timestamp(newso);
+ mutex_enter(&esi.esi_mutex);
}
- (void) ksocket_close(newso, CRED());
+ idm_soshutdown(esi.esi_so);
+ ksocket_rele(esi.esi_so);
+ esi.esi_valid = B_FALSE;
/*
- * Do not hold the esi mutex during server timestamp
- * update. It requires the isns global lock, which may
- * be held during other functions that also require
- * the esi_mutex (potential deadlock).
+ * If we're going to try to re-establish the listener then
+ * destroy this socket. Otherwise isnst_esi_stop already
+ * destroyed it.
*/
- mutex_exit(&isns_esi_mutex);
- isnst_update_server_timestamp(newso);
- mutex_enter(&isns_esi_mutex);
+ if (esi.esi_enabled)
+ idm_sodestroy(esi.esi_so);
}
- mutex_exit(&isns_esi_mutex);
+
+ esi.esi_thread_running = B_FALSE;
+ cv_signal(&esi.esi_cv);
+ mutex_exit(&esi.esi_mutex);
esi_thread_exit:
- ksocket_rele(tinfop->esi_so);
thread_exit();
}
@@ -2320,36 +2433,150 @@ esi_thread_exit:
* Handle an incoming ESI request
*/
-static boolean_t
-isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pl_size)
+static void
+isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pdu_size)
{
- isns_pdu_t *rsp_pdu;
- isns_resp_t *rsp;
- size_t pl_len, rsp_size;
- boolean_t esirv = B_TRUE;
+ static char log_addr_buf[INET6_ADDRSTRLEN];
+ isns_pdu_t *rsp_pdu;
+ isns_resp_t *rsp;
+ isns_tlv_t *attr;
+ uint32_t attr_len, attr_id;
+ size_t req_pl_len, rsp_size, tlv_len;
+ struct sockaddr_storage ss;
+ struct sockaddr_in6 *portal_addr6;
+ boolean_t portal_addr_valid = B_FALSE;
+ boolean_t portal_port_valid = B_FALSE;
+ uint32_t esi_response = ISNS_RSP_SUCCESSFUL;
+ isns_portal_list_t *portal;
if (ntohs(pdu->func_id) != ISNS_ESI) {
- cmn_err(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x",
+ ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Unexpected func 0x%x",
pdu->func_id);
- kmem_free(pdu, pl_size);
- return (B_FALSE);
+ kmem_free(pdu, pdu_size);
+ return;
}
- pl_len = ntohs(pdu->payload_len) + 4 /* ISNS_STATUS_SZ */;
+ req_pl_len = ntohs(pdu->payload_len);
+ if (req_pl_len + offsetof(isns_pdu_t, payload) > pdu_size) {
+ ISNST_LOG(CE_WARN, "isnst_handle_esi_req: "
+ "payload exceeds PDU size (%d > %d)",
+ (int)(req_pl_len + offsetof(isns_pdu_t, payload)),
+ (int)pdu_size);
+ /* Not all data is present -- ignore */
+ kmem_free(pdu, pdu_size);
+ return;
+ }
- if (pl_len > ISNSP_MAX_PAYLOAD_SIZE) {
- cmn_err(CE_WARN, "isnst_handle_esi_req: PDU payload too large "
- " (%ld bytes)", pl_len);
- kmem_free(pdu, pl_size);
- return (B_FALSE);
+ if (req_pl_len + sizeof (uint32_t) > ISNSP_MAX_PAYLOAD_SIZE) {
+ ISNST_LOG(CE_WARN,
+ "isnst_handle_esi_req: PDU payload exceeds max (%ld bytes)",
+ req_pl_len + sizeof (uint32_t));
+ kmem_free(pdu, pdu_size);
+ return;
}
+ /*
+ * Check portal in ESI request and make sure it is valid. Return
+ * esi_response of ISNS_RSP_SUCCESSFUL if valid, otherwise don't
+ * respond at all. Get IP addr and port. Format of ESI
+ * is:
+ *
+ * ISNS_TIMESTAMP_ATTR_ID,
+ * ISNS_EID_ATTR_ID,
+ * ISNS_PORTAL_IP_ADDR_ATTR_ID,
+ * ISNS_PORTAL_PORT_ATTR_ID
+ */
+ bzero(&ss, sizeof (struct sockaddr_storage));
+ ss.ss_family = AF_INET6;
+ portal_addr6 = (struct sockaddr_in6 *)&ss;
+ attr = (isns_tlv_t *)((void *)&pdu->payload);
+ attr_len = ntohl(attr->attr_len);
+ attr_id = ntohl(attr->attr_id);
+ tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
+ while (tlv_len <= req_pl_len) {
+ switch (attr_id) {
+ case ISNS_TIMESTAMP_ATTR_ID:
+ break;
+ case ISNS_EID_ATTR_ID:
+ break;
+ case ISNS_PORTAL_IP_ADDR_ATTR_ID:
+ if (attr_len > sizeof (struct in6_addr)) {
+ /* Bad attribute format */
+ esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
+ } else {
+ portal_addr6->sin6_family = AF_INET6;
+ attr_len = min(attr_len,
+ sizeof (portal_addr6->sin6_addr));
+ bcopy(attr->attr_value,
+ portal_addr6->sin6_addr.s6_addr, attr_len);
+ portal_addr_valid = B_TRUE;
+ }
+ break;
+ case ISNS_PORTAL_PORT_ATTR_ID:
+ if (attr_len > sizeof (uint32_t)) {
+ /* Bad attribute format */
+ esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
+ } else {
+ portal_addr6->sin6_port =
+ htons((uint16_t)BE_IN32(attr->attr_value));
+ portal_port_valid = B_TRUE;
+ }
+ break;
+ default:
+ /* Bad request format */
+ esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
+ break;
+ }
+
+ /* If we've set an error then stop processing */
+ if (esi_response != ISNS_RSP_SUCCESSFUL) {
+ break;
+ }
+
+ /* Get next attribute */
+ req_pl_len -= tlv_len;
+ attr = (isns_tlv_t *)((void *)((uint8_t *)attr + tlv_len));
+ attr_len = ntohl(attr->attr_len);
+ attr_id = ntohl(attr->attr_id);
+ tlv_len = attr_len + offsetof(isns_tlv_t, attr_value);
+ }
+
+ if (!portal_port_valid)
+ portal_addr6->sin6_port = htons(ISCSI_LISTEN_PORT);
+
+ if (portal_addr_valid) {
+ ISNST_LOG(CE_NOTE, "ESI %s:%d",
+ inet_ntop(AF_INET6, &portal_addr6->sin6_addr, log_addr_buf,
+ INET6_ADDRSTRLEN),
+ ntohs(portal_addr6->sin6_port));
+ } else {
+ esi_response = ISNS_RSP_MSG_FORMAT_ERROR;
+ }
+
+ /*
+ * If we've detected an error or if the portal does not
+ * exist then drop the request. The server will eventually
+ * timeout the portal and eliminate it from the list.
+ */
+
+ ISNS_GLOBAL_LOCK();
+ if ((esi_response != ISNS_RSP_SUCCESSFUL) ||
+ !isnst_portal_exists(&ss)) {
+ ISNS_GLOBAL_UNLOCK();
+ kmem_free(pdu, pdu_size);
+ return;
+ }
+ ISNS_GLOBAL_UNLOCK();
+
+ /*
+ * Build response validating the portal
+ */
rsp_size = isnst_create_pdu_header(ISNS_ESI_RSP, &rsp_pdu, 0);
if (rsp_size == 0) {
- cmn_err(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu");
- kmem_free(pdu, pl_size);
- return (B_FALSE);
+ ISNST_LOG(CE_WARN, "isnst_handle_esi_req: Can't get rsp pdu");
+ kmem_free(pdu, pdu_size);
+ return;
}
rsp = (isns_resp_t *)((void *)(&rsp_pdu->payload[0]));
@@ -2359,18 +2586,31 @@ isnst_handle_esi_req(ksocket_t ks, isns_pdu_t *pdu, size_t pl_size)
rsp->status = htonl(ISNS_RSP_SUCCESSFUL);
/* Copy original data */
- bcopy(pdu->payload, rsp->data, pl_len - 4);
- rsp_pdu->payload_len = htons(pl_len);
+ req_pl_len = ntohs(pdu->payload_len);
+ bcopy(pdu->payload, rsp->data, req_pl_len);
+ rsp_pdu->payload_len = htons(req_pl_len + sizeof (uint32_t));
if (isnst_send_pdu(ks, rsp_pdu) != 0) {
- cmn_err(CE_WARN, "isnst_handle_esi_req: Send response failed");
- esirv = B_FALSE;
+ ISNST_LOG(CE_WARN,
+ "isnst_handle_esi_req: Send response failed");
}
kmem_free(rsp_pdu, rsp_size);
- kmem_free(pdu, pl_size);
+ kmem_free(pdu, pdu_size);
- return (esirv);
+ /*
+ * Update ESI timestamps for all matching portals. Iscsit may or
+ * may not allow portals to belong to multiple portal groups depending
+ * on the policy it implements. The iSNS client does not know or
+ * care so we allow for multiple hits in the list.
+ */
+ ISNS_GLOBAL_LOCK();
+ for (portal = isnst_lookup_portal(&ss, NULL);
+ portal != NULL;
+ portal = isnst_lookup_portal(&ss, portal)) {
+ gethrestime(&portal->portal_esi_timestamp);
+ }
+ ISNS_GLOBAL_UNLOCK();
}
int
@@ -2424,76 +2664,77 @@ isnst_set_server_status(iscsit_isns_svr_t *svr, boolean_t registered)
}
}
-static void
-isnst_add_default_portals()
+static boolean_t
+isnst_lookup_default_portal(struct sockaddr_storage *p)
{
idm_addr_list_t *default_portal_list;
+ uint32_t default_portal_list_size;
idm_addr_t *dportal;
- isns_portal_list_t *portal;
- struct sockaddr_in *sin;
- struct sockaddr_in6 *sin6;
- uint32_t dpl_size, idx;
+ struct sockaddr_storage dportal_ss;
+ int idx;
+ boolean_t result = B_FALSE;
- ASSERT(ISNS_GLOBAL_LOCK_HELD());
+ /*
+ * If the address we're looking up is not using the well known
+ * port then it's inherently not a match for a default portal
+ */
+ if (((struct sockaddr_in *)p)->sin_port != htons(ISCSI_LISTEN_PORT)) {
+ return (B_FALSE);
+ }
- dpl_size = idm_get_ipaddr(&default_portal_list);
+ /*
+ * Get the global list of default portals
+ */
+ default_portal_list_size = idm_get_ipaddr(&default_portal_list);
- if (dpl_size == 0) {
- cmn_err(CE_WARN, "isnst_add_default_portals: "
+ if (default_portal_list_size == 0) {
+ ISNST_LOG(CE_WARN, "isnst_lookup_default_portal: "
"No default portals");
- return;
+ return (B_FALSE);
}
+ /*
+ * Scan the through the current default portal list (this should
+ * be refreshed just before lookup since the contents can change)
+ */
for (idx = 0; idx < default_portal_list->al_out_cnt; idx++) {
dportal = &default_portal_list->al_addrs[idx];
- if (dportal->a_addr.i_insize == 0) {
- continue;
- }
-
- portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
- portal->portal_iscsit = NULL; /* Default portal */
-
+ /*
+ * Translate the address idm_get_ipaddr returned into
+ * sockaddr_storage format
+ */
+ bzero(&dportal_ss, sizeof (dportal_ss));
+ ((struct sockaddr_in *)&dportal_ss)->sin_port =
+ htons(ISCSI_LISTEN_PORT);
if (dportal->a_addr.i_insize == sizeof (struct in_addr)) {
- sin = (struct sockaddr_in *)&portal->portal_addr;
- sin->sin_family = AF_INET;
- sin->sin_port = htons(ISCSI_LISTEN_PORT);
- sin->sin_addr = dportal->a_addr.i_addr.in4;
+ dportal_ss.ss_family = AF_INET;
+ bcopy(&dportal->a_addr.i_addr.in4,
+ &((struct sockaddr_in *)&dportal_ss)->sin_addr,
+ sizeof (struct in_addr));
+ } else if (dportal->a_addr.i_insize ==
+ sizeof (struct in6_addr)) {
+ dportal_ss.ss_family = AF_INET6;
+ bcopy(&dportal->a_addr.i_addr.in6,
+ &((struct sockaddr_in6 *)&dportal_ss)->sin6_addr,
+ sizeof (struct in6_addr));
} else {
- sin6 = (struct sockaddr_in6 *)&portal->portal_addr;
- sin->sin_family = AF_INET6;
- sin6->sin6_port = htons(ISCSI_LISTEN_PORT);
- sin6->sin6_addr = dportal->a_addr.i_addr.in6;
+ continue;
}
- list_insert_tail(&portal_list, portal);
- isnst_esi_start(portal);
- }
-
- kmem_free(default_portal_list, dpl_size);
-}
-
-static void
-isnst_remove_default_portals()
-{
- isns_portal_list_t *portal, *next;
-
- ASSERT(ISNS_GLOBAL_LOCK_HELD());
-
- portal = list_head(&portal_list);
-
- while (portal) {
- next = list_next(&portal_list, portal);
-
- if (portal->portal_iscsit == NULL) {
- mutex_enter(&isns_esi_mutex);
- isnst_esi_stop_thread(portal->portal_esi);
- mutex_exit(&isns_esi_mutex);
- isns_remove_portal(portal);
+ /*
+ * Now we can compare to the address we were passed
+ */
+ if (idm_ss_compare(p, &dportal_ss,
+ B_TRUE /* v4_mapped_as_v4 */) == 0) {
+ result = B_TRUE;
+ goto lookup_default_portal_done;
}
-
- portal = next;
}
+
+lookup_default_portal_done:
+ kmem_free(default_portal_list, default_portal_list_size);
+ return (result);
}
/*
@@ -2504,35 +2745,18 @@ isnst_remove_default_portals()
void
iscsit_isns_portal_online(iscsit_portal_t *portal)
{
- isns_portal_list_t *iportal, *new_portal;
- struct sockaddr_in *sin;
-
ISNS_GLOBAL_LOCK();
- iportal = isns_lookup_portal(&portal->portal_addr);
- sin = (struct sockaddr_in *)&portal->portal_addr;
-
- /*
- * If sin_family is 0, it's a "default" portal. It's possible
- * sin_family may be non-zero, so check portal_iscsit. If it's NULL,
- * it's a default portal as well.
- */
-
- if ((sin->sin_family == 0) ||
- (iportal && (iportal->portal_iscsit == NULL))) {
+ if (portal->portal_default) {
+ /* Portals should only be onlined once */
+ ASSERT(!default_portal_online);
+ default_portal_online = B_TRUE;
+ default_portal_state_change = B_TRUE;
ISNS_GLOBAL_UNLOCK();
return;
}
- ASSERT(iportal == NULL);
-
- new_portal = kmem_zalloc(sizeof (isns_portal_list_t), KM_SLEEP);
- new_portal->portal_addr = portal->portal_addr;
- sin = (struct sockaddr_in *)&new_portal->portal_addr;
- new_portal->portal_iscsit = portal;
- list_insert_tail(&portal_list, new_portal);
- portal_list_count++;
- nondefault_portals++;
+ isnst_add_portal(portal);
ISNS_GLOBAL_UNLOCK();
}
@@ -2540,31 +2764,18 @@ iscsit_isns_portal_online(iscsit_portal_t *portal)
void
iscsit_isns_portal_offline(iscsit_portal_t *portal)
{
- isns_portal_list_t *iportal = NULL;
- struct sockaddr_in *sin;
- boolean_t default_portals = B_FALSE;
-
ISNS_GLOBAL_LOCK();
- /*
- * Stop the ESI thread for this portal
- */
-
- iportal = isns_lookup_portal(&portal->portal_addr);
- sin = (struct sockaddr_in *)&portal->portal_addr;
-
- if ((sin->sin_family == 0) ||
- (iportal && (iportal->portal_iscsit == NULL))) {
- default_portals = B_TRUE;
- } else {
- iportal = isns_lookup_portal(&portal->portal_addr);
- ASSERT(iportal);
+ if (portal->portal_default) {
+ /* Portals should only be offlined once */
+ ASSERT(default_portal_online);
+ default_portal_online = B_FALSE;
+ default_portal_state_change = B_TRUE;
+ ISNS_GLOBAL_UNLOCK();
+ return;
}
- if (!default_portals) {
- isns_remove_portal(iportal);
- nondefault_portals--;
- }
+ isnst_remove_portal(portal);
ISNS_GLOBAL_UNLOCK();
}
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.h b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.h
index af0d8982bb..d0104dfc9c 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.h
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_isns.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ISNS_CLIENT_H_
@@ -37,6 +37,7 @@ typedef struct {
clock_t svr_last_msg;
list_node_t svr_ln;
boolean_t svr_registered;
+ uint32_t svr_esi_interval;
} iscsit_isns_svr_t;
/*
@@ -59,18 +60,18 @@ typedef enum {
struct isns_portal_list_s;
typedef struct {
- struct isns_portal_list_s *esi_portal;
kthread_t *esi_thread;
kt_did_t esi_thread_did;
ksocket_t esi_so;
+ kmutex_t esi_mutex;
+ kcondvar_t esi_cv;
uint16_t esi_port;
+ boolean_t esi_enabled;
+ boolean_t esi_valid;
boolean_t esi_thread_running;
- boolean_t esi_thread_failed;
- boolean_t esi_registered;
- boolean_t esi_not_available;
- list_node_t esi_ln;
} isns_esi_tinfo_t;
+
/*
* Portal list - comprised of "default" portals (i.e. idm_get_ipaddr) and
* portals that are part of target portal groups.
@@ -78,9 +79,9 @@ typedef struct {
typedef struct isns_portal_list_s {
struct sockaddr_storage portal_addr;
- isns_esi_tinfo_t *portal_esi;
iscsit_portal_t *portal_iscsit;
list_node_t portal_ln;
+ timespec_t portal_esi_timestamp;
} isns_portal_list_t;
typedef struct isns_target_s {
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c
index 1774531e1d..e61dda1735 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_sess.c
@@ -116,6 +116,7 @@ iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict,
{
iscsit_sess_t *result;
+ *error_class = ISCSI_STATUS_CLASS_SUCCESS;
/*
* Even if this session create "fails" for some reason we still need
@@ -169,10 +170,30 @@ iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict,
/* Login code will fill in ist_stmf_sess if necessary */
- /* Kick session state machine (also binds connection to session) */
- iscsit_sess_sm_event(result, SE_CONN_IN_LOGIN, ict);
+ if (*error_class == ISCSI_STATUS_CLASS_SUCCESS) {
+ /*
+ * Make sure the service is still enabled and if so get a global
+ * hold to represent this session.
+ */
+ ISCSIT_GLOBAL_LOCK(RW_READER);
+ if (iscsit_global.global_svc_state == ISE_ENABLED) {
+ iscsit_global_hold();
+ ISCSIT_GLOBAL_UNLOCK();
+
+ /*
+ * Kick session state machine (also binds connection
+ * to session)
+ */
+ iscsit_sess_sm_event(result, SE_CONN_IN_LOGIN, ict);
+
+ *error_class = ISCSI_STATUS_CLASS_SUCCESS;
+ } else {
+ ISCSIT_GLOBAL_UNLOCK();
+ *error_class = ISCSI_STATUS_CLASS_TARGET_ERR;
+ *error_detail = ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE;
+ }
+ }
- *error_class = ISCSI_STATUS_CLASS_SUCCESS;
/*
* As noted above we must return a session pointer even if something
* failed. The resources will get freed later.
@@ -207,6 +228,7 @@ iscsit_sess_unref(void *ist_void)
mutex_exit(&ist->ist_mutex);
iscsit_sess_destroy(ist);
+ iscsit_global_rele();
}
void
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c
index d640dc6a67..c875839bb3 100644
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c
@@ -1139,7 +1139,6 @@ iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
} else {
/* Discovery session */
sess->ist_lport = NULL;
- iscsit_global_hold();
ISCSIT_GLOBAL_LOCK(RW_WRITER);
avl_add(&iscsit_global.global_discovery_sessions, sess);
ISCSIT_GLOBAL_UNLOCK();
@@ -1161,7 +1160,6 @@ iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
ISCSIT_GLOBAL_LOCK(RW_WRITER);
avl_remove(&iscsit_global.global_discovery_sessions, sess);
ISCSIT_GLOBAL_UNLOCK();
- iscsit_global_rele();
}
}
@@ -1808,7 +1806,10 @@ iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa)
* portal -- targets will use this portal when no portals are
* explicitly configured.
*/
- if (sa != NULL) {
+ if (sa == NULL) {
+ portal->portal_default = B_TRUE;
+ } else {
+ portal->portal_default = B_FALSE;
bcopy(sa, &portal->portal_addr, sizeof (*sa));
}
diff --git a/usr/src/uts/common/io/idm/idm_conn_sm.c b/usr/src/uts/common/io/idm/idm_conn_sm.c
index 1fc131b79a..4d583c51ad 100644
--- a/usr/src/uts/common/io/idm/idm_conn_sm.c
+++ b/usr/src/uts/common/io/idm/idm_conn_sm.c
@@ -75,6 +75,9 @@ static void
idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
static void
+idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
+
+static void
idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx);
static void
@@ -90,6 +93,9 @@ idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
static void
idm_conn_unref(void *ic_void);
+static void
+idm_conn_reject_unref(void *ic_void);
+
static idm_pdu_event_action_t
idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
idm_pdu_t *pdu);
@@ -229,6 +235,7 @@ idm_conn_event_locked(idm_conn_t *ic, idm_conn_event_t event,
* the connection otherwise it might disappear.
*/
if ((ic->ic_state == CS_S9_INIT_ERROR) ||
+ (ic->ic_state == CS_S9A_REJECTED) ||
(ic->ic_state == CS_S11_COMPLETE)) {
if ((pdu_event_type == CT_TX_PDU) ||
(pdu_event_type == CT_RX_PDU)) {
@@ -354,6 +361,9 @@ idm_conn_event_handler(void *event_ctx_opaque)
case CS_S8_CLEANUP:
idm_state_s8_cleanup(ic, event_ctx);
break;
+ case CS_S9A_REJECTED:
+ idm_state_s9a_rejected(ic, event_ctx);
+ break;
case CS_S9_INIT_ERROR:
idm_state_s9_init_error(ic, event_ctx);
break;
@@ -488,6 +498,15 @@ idm_state_s3_xpt_up(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
idm_update_state(ic, CS_S9_INIT_ERROR, event_ctx);
break;
case CE_CONNECT_REJECT:
+ /*
+ * Iscsit doesn't want to hear from us again in this case.
+ * Since it rejected the connection it doesn't have a
+ * connection context to handle additional notifications.
+ * IDM needs to just clean things up on its own.
+ */
+ (void) untimeout(ic->ic_state_timeout);
+ idm_update_state(ic, CS_S9A_REJECTED, event_ctx);
+ break;
case CE_CONNECT_FAIL:
case CE_TRANSPORT_FAIL:
case CE_LOGOUT_OTHER_CONN_SND:
@@ -926,6 +945,13 @@ idm_state_s9_init_error(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
}
}
+/* ARGSUSED */
+static void
+idm_state_s9a_rejected(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
+{
+ /* Ignore events */
+}
+
static void
idm_state_s10_in_cleanup(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx)
{
@@ -1146,6 +1172,15 @@ idm_update_state(idm_conn_t *ic, idm_conn_state_t new_state,
break;
case CS_S10_IN_CLEANUP:
break;
+ case CS_S9A_REJECTED:
+ /*
+ * We never finished establishing the connection so no
+ * disconnect. No client notificatiosn because the client
+ * rejected the connection.
+ */
+ idm_refcnt_async_wait_ref(&ic->ic_refcnt,
+ &idm_conn_reject_unref);
+ break;
case CS_S9_INIT_ERROR:
if (IDM_CONN_ISTGT(ic)) {
ic->ic_transport_ops->it_tgt_conn_disconnect(ic);
@@ -1235,6 +1270,18 @@ idm_conn_unref(void *ic_void)
}
}
+static void
+idm_conn_reject_unref(void *ic_void)
+{
+ idm_conn_t *ic = ic_void;
+
+ ASSERT(IDM_CONN_ISTGT(ic));
+
+ /* Don't notify the client since it rejected the connection */
+ idm_svc_conn_destroy(ic);
+}
+
+
static idm_pdu_event_action_t
idm_conn_sm_validate_pdu(idm_conn_t *ic, idm_conn_event_ctx_t *event_ctx,
diff --git a/usr/src/uts/common/io/idm/idm_so.c b/usr/src/uts/common/io/idm/idm_so.c
index 04353496b2..f9b6056968 100644
--- a/usr/src/uts/common/io/idm/idm_so.c
+++ b/usr/src/uts/common/io/idm/idm_so.c
@@ -54,7 +54,7 @@
* in6addr_any is currently all zeroes, but use the macro in case this
* ever changes.
*/
-const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
@@ -226,6 +226,104 @@ idm_sodestroy(ksocket_t ks)
}
/*
+ * Function to compare two addresses in sockaddr_storage format
+ */
+
+int
+idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
+ const struct sockaddr_storage *cmp_ss2,
+ boolean_t v4_mapped_as_v4)
+{
+ struct sockaddr_storage mapped_v4_ss1, mapped_v4_ss2;
+ const struct sockaddr_storage *ss1, *ss2;
+ struct in_addr *in1, *in2;
+ struct in6_addr *in61, *in62;
+ int i;
+
+ /*
+ * Normalize V4-mapped IPv6 addresses into V4 format if
+ * v4_mapped_as_v4 is B_TRUE.
+ */
+ ss1 = cmp_ss1;
+ ss2 = cmp_ss2;
+ if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) {
+ in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
+ if (IN6_IS_ADDR_V4MAPPED(in61)) {
+ bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1));
+ mapped_v4_ss1.ss_family = AF_INET;
+ ((struct sockaddr_in *)&mapped_v4_ss1)->sin_port =
+ ((struct sockaddr_in *)ss1)->sin_port;
+ IN6_V4MAPPED_TO_INADDR(in61,
+ &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr);
+ ss1 = &mapped_v4_ss1;
+ }
+ }
+ ss2 = cmp_ss2;
+ if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) {
+ in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
+ if (IN6_IS_ADDR_V4MAPPED(in62)) {
+ bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2));
+ mapped_v4_ss2.ss_family = AF_INET;
+ ((struct sockaddr_in *)&mapped_v4_ss2)->sin_port =
+ ((struct sockaddr_in *)ss2)->sin_port;
+ IN6_V4MAPPED_TO_INADDR(in62,
+ &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr);
+ ss2 = &mapped_v4_ss2;
+ }
+ }
+
+ /*
+ * Compare ports, then address family, then ip address
+ */
+ if (((struct sockaddr_in *)ss1)->sin_port !=
+ ((struct sockaddr_in *)ss2)->sin_port) {
+ if (((struct sockaddr_in *)ss1)->sin_port >
+ ((struct sockaddr_in *)ss2)->sin_port)
+ return (1);
+ else
+ return (-1);
+ }
+
+ /*
+ * ports are the same
+ */
+ if (ss1->ss_family != ss2->ss_family) {
+ if (ss1->ss_family == AF_INET)
+ return (1);
+ else
+ return (-1);
+ }
+
+ /*
+ * address families are the same
+ */
+ if (ss1->ss_family == AF_INET) {
+ in1 = &((struct sockaddr_in *)ss1)->sin_addr;
+ in2 = &((struct sockaddr_in *)ss2)->sin_addr;
+
+ if (in1->s_addr > in2->s_addr)
+ return (1);
+ else if (in1->s_addr < in2->s_addr)
+ return (-1);
+ else
+ return (0);
+ } else if (ss1->ss_family == AF_INET6) {
+ in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
+ in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
+
+ for (i = 0; i < 4; i++) {
+ if (in61->s6_addr32[i] > in62->s6_addr32[i])
+ return (1);
+ else if (in61->s6_addr32[i] < in62->s6_addr32[i])
+ return (-1);
+ }
+ return (0);
+ }
+
+ return (1);
+}
+
+/*
* IP address filter functions to flag addresses that should not
* go out to initiators through discovery.
*/
diff --git a/usr/src/uts/common/sys/idm/idm_conn_sm.h b/usr/src/uts/common/sys/idm/idm_conn_sm.h
index 97e181ca54..e53750017f 100644
--- a/usr/src/uts/common/sys/idm/idm_conn_sm.h
+++ b/usr/src/uts/common/sys/idm/idm_conn_sm.h
@@ -187,6 +187,7 @@ typedef enum {
CS_S7_LOGOUT_REQ,
CS_S8_CLEANUP,
CS_S9_INIT_ERROR,
+ CS_S9A_REJECTED,
CS_S10_IN_CLEANUP,
CS_S11_COMPLETE,
CS_S12_ENABLE_DM,
@@ -208,6 +209,7 @@ static const char *idm_cs_name[CS_MAX_STATE+1] = {
"CS_S7_LOGOUT_REQ",
"CS_S8_CLEANUP",
"CS_S9_INIT_ERROR",
+ "CS_S9A_REJECTED",
"CS_S10_IN_CLEANUP",
"CS_S11_COMPLETE",
"CS_S12_ENABLE_DM",
diff --git a/usr/src/uts/common/sys/idm/idm_so.h b/usr/src/uts/common/sys/idm/idm_so.h
index c5d9a8b0b0..93163c62d6 100644
--- a/usr/src/uts/common/sys/idm/idm_so.h
+++ b/usr/src/uts/common/sys/idm/idm_so.h
@@ -86,6 +86,10 @@ void idm_soshutdown(ksocket_t so);
void idm_sodestroy(ksocket_t so);
+int idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
+ const struct sockaddr_storage *cmp_ss2,
+ boolean_t v4_mapped_as_v4);
+
int idm_get_ipaddr(idm_addr_list_t **);
int idm_sorecv(ksocket_t so, void *msg, size_t len);