iscsit_isns.c revision e42a0851889d583925aa3bd2d9bd139189031cb0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/stmf_ioctl.h>
#include <iscsit.h>
#include <iscsit_isns.h>
/* local defines */
#define ISNS_IDLE_TIME 60
#define MAX_RETRY (3)
#define ISNS_RCV_TIMER_SECONDS 5
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;
static kcondvar_t isns_idle_cv;
static clock_t monitor_idle_interval;
#define ISNS_GLOBAL_LOCK() \
#define ISNS_GLOBAL_LOCK_HELD() \
#define ISNS_GLOBAL_UNLOCK() \
/*
* iSNS ESI thread state
*/
static isns_esi_tinfo_t esi;
/*
* List of portals.
*/
static list_t portal_list;
static uint32_t portal_list_count = 0;
/*
* Our entity identifier (fully-qualified hostname)
*/
/*
* Our list of targets
*/
static avl_tree_t isns_target_list;
/*
* in6addr_any is currently all zeroes, but use the macro in case this
* ever changes.
*/
static void
isnst_start();
static void
isnst_stop();
static void
static int
static void
static iscsit_isns_svr_t *
static void
isnst_monitor(void *arg);
static int
static int
static int
static size_t
static int
static uint16_t
static size_t
static int
static int
static int
static int
static size_t
static int
void *attr_data,
static int
static size_t
static void *
static void
isnst_close_so(void *);
static void
isnst_esi_thread(void *arg);
static void
static void isnst_esi_start(void);
static void isnst_esi_stop(void);
static void isnst_get_target_list(void);
static void isnst_monitor_start(void);
static void isnst_monitor_stop(void);
static boolean_t isnst_lookup_default_portal();
{
/*
* Determine whether iSNS is enabled in the new config.
* Isns property may not be set up yet.
*/
/* Delete iSNS servers that are no longer part of the config */
isns_svr = next_isns_svr) {
}
/* Add new iSNS servers */
cfg_isns_svr != NULL;
if (iscsit_add_isns(cfg_isns_svr) != 0) {
/* Shouldn't happen */
return (ITCFG_MISC_ERR);
}
}
}
}
/*
* There is no "modify case" since the user specifies a complete
* server list each time. A modify is the same as a remove+add.
*/
return (0);
}
int
{
portal_list_count = 0;
/*
* The iscsi global lock is not held here, but it is held when
* isnst_start is called, so we need to acquire it only in this
* case.
*/
/* initialize isns client */
xid = 0;
return (0);
}
void
{
/*
* Free our EID and target list.
*/
if (isns_eid) {
}
portal_list_count = 0;
}
static void
{
/*
* Update state and isns stop flag
*/
/* reset retry count for all servers */
svr)) {
svr->svr_retry_count = 0;
}
if (state) {
isnst_start();
} else {
isnst_stop();
}
}
}
int
{
sizeof (struct sockaddr_storage));
/* put it on the global isns server list */
/*
* Register targets with this server if iSNS is enabled.
*/
}
return (0);
}
void
{
/* talk to this server if isns monitor is running */
if (isns_monitor_thr_id != NULL) {
need_dereg = B_TRUE;
} else {
}
if (need_dereg) {
}
/* free the memory */
}
static iscsit_isns_svr_t *
{
return (svr);
}
return (NULL);
}
int
{
int rc = 0;
(void) isnst_add_to_target_list(target);
return (rc);
}
return (rc);
}
int
{
void *itarget;
!= NULL) {
}
return (0);
}
/*
* Don't worry about dereg failures.
*/
/*
* Remove the target from the list regardless of the status.
*/
}
/*
* If there are no more targets, mark the server as
* unregistered.
*/
if (avl_numnodes(&isns_target_list) == 0) {
}
}
return (0);
}
/*
* This function is called by iscsit when a target's configuration
* has changed.
*/
void
{
return;
}
}
static void
{
/*
* Get initial target list
*/
/*
* Start ESI thread(s)
*/
/*
* Create a thread for monitoring server communications
*/
}
static void
{
}
}
static void
isnst_monitor_start(void)
{
while (!isns_monitor_thr_running)
}
static void
isnst_monitor_stop(void)
{
if (isns_monitor_thr_running) {
return;
}
}
/*
* isnst_update_server_timestamp
*
* When we receive an ESI request, update the timestamp for the server.
* If we don't receive one for the specified period of time, we'll attempt
* to re-register.
*/
static void
{
struct sockaddr_in6 t_addr;
t_addrlen = sizeof (struct sockaddr_in6);
CRED());
} else {
}
/*
* Find the server and update the timestamp
*/
== 0) {
break;
}
}
} else {
svr_in6 = &((struct sockaddr_in6 *)
sizeof (in6_addr_t)) == 0) {
break;
}
}
}
}
}
}
/*
* isnst_monitor
*
* This function monitors registration status for each server.
*/
static void
{
svr->svr_retry_count++;
} else {
svr->svr_retry_count = 0;
}
}
}
/*ARGSUSED*/
static void
isnst_monitor(void *arg)
{
while (isns_monitor_thr_running) {
/* Update servers */
/*
* Keep running until isns_monitor_thr_running is set to
* B_FALSE.
*/
}
/* Update the servers one last time for deregistration */
/* terminate the thread at the last */
thread_exit();
}
static int
{
int rc = 0;
/*
* First, take care of the case where iSNS is no longer enabled.
*
* If we're still registered, deregister. Regardless, mark the
* server as not registered.
*/
/*
* Doesn't matter if this fails. We're disabled.
*/
}
}
return (0);
}
/*
* If there are no targets, we're done.
*/
if (avl_numnodes(&isns_target_list) == 0) {
return (0);
}
/*
* At this point, we know iSNS is enabled.
*
* If we've received an ESI request from the server recently
* (within MAX_ESI_INTERVALS * the max interval length),
* no need to continue.
*/
MAX_ESI_INTERVALS))) {
return (0);
}
} else {
/*
* We're not registered... Try to register now.
*/
ISNS_REGISTER_ALL)) == 0) {
}
}
return (rc);
}
static int
{
/*
* Only return success if they all succeed. Let the caller
* deal with any failure.
*/
if (curr_rc == 0) {
if (reg == ISNS_REGISTER_TARGET) {
}
} else if (rc == 0) {
}
}
return (rc);
}
static int
{
int rc = 0;
switch (reg) {
case ISNS_DEREGISTER_TARGET:
break;
case ISNS_DEREGISTER_ALL:
break;
case ISNS_UPDATE_TARGET:
case ISNS_REGISTER_TARGET:
break;
case ISNS_REGISTER_ALL:
break;
default:
ASSERT(0);
/* NOTREACHED */
}
return (rc);
}
/*
* isnst_retry_registration
*
* This function checks the return value from a registration pdu and
* determines whether or not we should retry this request. If the
* request is retried, it will do so as an "update", which means we
* re-register everything.
*/
static boolean_t
{
/*
* Currently, we will attempt to retry for "Invalid Registration",
* "Source Unauthorized", or "Busy" errors. Any other errors should
* be handled by the caller if necessary.
*/
switch (rsp_status_code) {
case ISNS_RSP_INVALID_REGIS:
case ISNS_RSP_BUSY:
break;
default:
break;
}
return (retry);
}
static int
{
int rc = 0;
/*
* Registration is a tricky thing. In order to keep things simple,
* we don't want to keep track of which targets are registered to
* which server. We rely on the target state machine to tell us
* when a target is online or offline, which prompts us to either
* register or deregister that target.
*
* When iscsit_isns_init is called, get a list of targets. Those that
* are online will need to be registered. In this case, target
* will be NULL.
*
* What this means is that if svr_registered == B_FALSE, that's
* when we'll register the network entity as well.
*/
return (0);
}
/*
* If the target is already registered and we're not doing an
* update registration, just return.
*/
(regtype != ISNS_UPDATE_TARGET)) {
return (0);
}
}
/* create TCP connection to the isns server */
return (-1);
}
while (retry_reg) {
regtype);
if (pdu_size == 0) {
return (-1);
}
if (rc != 0) {
return (rc);
}
if (rsp_size == 0) {
return (-1);
}
/*
* If we got a registration error, the server may be out of
* sync. In this case, we may re-try the registration as
* a "target update", which causes us to re-register everything.
*/
if (regtype == ISNS_UPDATE_TARGET) {
/*
* If registration failed on an update, there
* is something terribly wrong, possibly with
* the server.
*/
rc = -1;
} else {
}
}
}
/*
* If it succeeded, mark all registered targets as such
*/
if (rc == 0) {
/* itarget initialized above */
} else {
while (itarget) {
}
}
}
return (rc);
}
static isns_portal_list_t *
{
B_TRUE /* v4_mapped_as_v4 */) == 0) {
return (portal);
}
}
return (NULL);
}
static boolean_t
isnst_portal_exists(struct sockaddr_storage *p)
{
}
static void
{
}
static void
{
}
static isns_target_t *
{
/*
* Make sure this target isn't already in our list. If it is,
* perhaps it has just moved from offline to online.
*/
}
return (itarget);
}
static size_t
{
char *str;
int len;
/*
* If any targets are using the default portal then get the global
* list of portals.
*/
if (default_portal_online) {
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
* updating a target, we'll use the target_name of the first target
* in our list.
*
* The alternate case is that we're registering for the first time,
* but target is non-NULL. In that case, we have no targets in our
* list yet, so we use the passed in target's name.
*/
(regtype == ISNS_UPDATE_TARGET)) {
} else {
}
/*
* No target means we're registering everything. A regtype of
* ISNS_UPDATE_TARGET means we're re-registering everything.
* Whether we're registering or re-registering depends on if
* we're already registered.
*/
((regtype == ISNS_REGISTER_TARGET) &&
/*
* If we're already registered, this will be a replacement
* registration. In this case, we need to make sure our
* source attribute is an already registered target.
*/
if (svr_registered) {
itarget);
}
/* Reset itarget to the beginning of our list */
}
}
if (pdu_size == 0) {
if (default_portal_list)
return (0);
}
goto pdu_error;
}
/*
* Message Key Attributes - EID
*/
goto pdu_error;
}
/* Delimiter */
0, 0, 0) != 0) {
goto pdu_error;
}
/*
* Operating Attributes
*/
isns_eid, 0) != 0) {
goto pdu_error;
}
/* ENTITY Protocol - Section 6.2.2 */
4, 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
goto pdu_error;
}
/*
* Network entity portal information - only on the first registration.
*/
default_portal_list) != 0) {
goto pdu_error;
}
}
do {
/* Hold the target mutex */
/* iSCSI Name - Section 6.4.1 */
goto pdu_error;
}
/* iSCSI Node Type */
ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, 0,
ISNS_TARGET_NODE_TYPE) != 0) {
goto pdu_error;
}
/* iSCSI Alias */
&str) == 0) {
/* Found alias in property list */
goto pdu_error;
}
}
default_portal_list) != 0) {
goto pdu_error;
}
if (reg_all) {
if (itarget) {
} else {
}
}
if (default_portal_list)
return (pdu_size);
/* packet too large, no memory */
if (default_portal_list)
return (0);
}
static int
{
struct sockaddr_storage ss;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int idx;
int dp_addr_size;
if (default_portal_list != NULL) {
/* Build sockaddr_storage for this portal */
if (dp_addr_size == sizeof (struct in_addr)) {
/* IPv4 */
} else if (dp_addr_size == sizeof (struct in6_addr)) {
} else {
continue;
}
return (-1);
}
}
} else {
return (-1);
}
}
}
return (0);
}
static int
{
int rval = 0;
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.
*/
continue;
}
/* Portal Group Tag */
rval = 1;
goto pg_done;
}
do {
rval = 1;
goto pg_done;
}
/*
* 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) {
default_portal_list) != 0) {
rval = 1;
goto pg_done;
}
}
return (rval);
}
static int
{
struct sockaddr_storage ss;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int idx;
int dp_addr_size;
/*
* Register all entity portals that aren't bound to this target in the
* null pg.
*/
if (default_portal_list != NULL) {
/* Build sockaddr_storage for this portal */
if (dp_addr_size == sizeof (struct in_addr)) {
/* IPv4 */
} else if (dp_addr_size == sizeof (struct in6_addr)) {
} else {
continue;
}
&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) {
0, 0, 0) != 0) {
return (-1);
}
}
return (-1);
}
} else {
}
}
} else {
if (iscsit_portal == NULL) {
/*
* If this is the first NULL PG portal, then
* write the NULL PG tag first.
*/
if (!null_pg_tag) {
0, 0, 0) != 0) {
return (-1);
}
}
return (-1);
}
} else {
}
}
}
return (0);
}
static int
{
struct sockaddr_in *in;
struct sockaddr_in6 *in6;
void *inaddrp;
attr_numeric_data = sizeof (in_addr_t);
attr_numeric_data = sizeof (in6_addr_t);
}
/* Portal Group Portal IP Address */
return (1);
}
/* Portal Group Portal Port */
return (1);
}
/* ESI interval and port */
NULL, 20) != 0) {
return (1);
}
return (1);
}
}
return (0);
}
static int
{
int rc;
(avl_numnodes(&isns_target_list) == 0)) {
return (0);
}
return (-1);
}
if (pdu_size == 0) {
return (-1);
}
if (rc != 0) {
return (rc);
}
if (rsp_size == 0) {
return (-1);
}
return (rc);
}
static size_t
{
int len;
int num_targets;
/*
* create DevDereg Message with all of target nodes
*/
if (pdu_size == 0) {
return (0);
}
/*
* Source attribute - Must be a storage node in the same
* network entity. We'll just grab the first one in the list.
* If it's the only online target, we turn this into a total
* deregistration regardless of the value of "node".
*/
goto dereg_pdu_error;
}
/* Delimiter */
0, 0, 0) != 0) {
goto dereg_pdu_error;
}
/*
* Operating attributes
*/
/* dereg everything */
goto dereg_pdu_error;
}
} else {
/* dereg one target only */
goto dereg_pdu_error;
}
}
return (pdu_size);
return (0);
}
static int
{
/*
* Ensure we have at least a valid header (don't count the
* "payload" field.
*/
return (-1);
}
/* Make sure we have the amount of data that the header specifies */
(int)rsp_size,
return (-1);
}
/* validate response function id */
case ISNS_DEV_ATTR_REG:
if (func_id != ISNS_DEV_ATTR_REG_RSP) {
return (-1);
}
/*
* Get the ESI interval returned by the server. It could
* be different than what we asked for. We never know which
* portal a request may come in on, and any server could demand
* any interval. We'll simply keep track of the largest interval
* for use in monitoring.
*/
/*
* Make sure isnst_pdu_get_op didn't encounter an error
* in the attributes.
*/
return (-1);
}
while (rsp_payload_len) {
if (attr_id == ISNS_ESI_INTERVAL_ATTR_ID) {
((void *)(&attr->attr_value))));
break;
}
attr = (isns_tlv_t *)
}
break;
case ISNS_DEV_DEREG:
if (func_id != ISNS_DEV_DEREG_RSP) {
return (-1);
}
break;
default:
ASSERT(0);
break;
}
/* verify response transaction id */
return (-1);
}
/* check the error code */
}
static uint16_t
{
/* get payload */
/* find the operating attributes */
return (0);
}
if (payload_len >= tlv_len) {
payload_len -= tlv_len;
if (attr_id == ISNS_DELIMITER_ATTR_ID) {
break;
}
} else {
/* mal-formed packet */
payload_len = 0;
}
}
return (payload_len);
}
static size_t
{
} else {
pdu_size = 0;
}
return (pdu_size);
}
static int
void *attr_data,
{
/* The attribute length must be 4-byte aligned. Section 5.1.3. */
/* Check if we are going to exceed the maximum PDU length. */
return (1);
}
switch (attr_id) {
case ISNS_DELIMITER_ATTR_ID:
break;
if (attr_numeric_data == sizeof (in_addr_t)) {
/* IPv4 */
sizeof (in_addr_t));
} else if (attr_numeric_data == sizeof (in6_addr_t)) {
/* IPv6 */
sizeof (in6_addr_t));
} else if (attr_numeric_data == 0) {
/* EMPTY */
/* Do nothing */
} else {
return (1);
}
break;
case ISNS_EID_ATTR_ID:
case ISNS_ISCSI_NAME_ATTR_ID:
case ISNS_ISCSI_ALIAS_ATTR_ID:
}
break;
default:
if (attr_len == 8) {
} else if (attr_len == 4) {
}
break;
}
/*
* Convert the network byte ordered payload length to host byte
* ordered for local address calculation.
*/
/*
* Convert the host byte ordered payload length back to network
* byte ordered - it's now ready to be sent on the wire.
*/
return (0);
}
static void
isnst_so_timeout(void *so)
{
/* Wake up any sosend or sorecv blocked on this socket */
}
static int
{
int rc;
/* update pdu flags */
/* initalize sequence number */
seq = 0;
/* total payload length */
/* fill in the pdu header */
do {
/* split the payload accordingly */
if (total_len > ISNSP_MAX_PAYLOAD_SIZE) {
} else {
/* set the last pdu flag */
}
/* set back the pdu flags */
/* set the sequence number */
/* set the payload length */
/* fill in the payload */
/* send the pdu */
(void) untimeout(send_timer);
flags &= ~ISNS_FLAG_FIRST_PDU;
payload += payload_len;
total_len -= payload_len;
/* increase the sequence number */
seq ++;
return (rc);
}
static size_t
{
total_pdu_len = total_payload_len = 0;
seq = 0;
do {
/* receive the pdu header */
goto rcv_error;
}
/* receive the payload */
goto rcv_error;
}
/* combine the pdu if it is not the first one */
if (total_pdu_len > 0) {
*pdu = combined_pdu;
} else {
}
/* the flags of pdu which is just received */
/* increase sequence number by one */
seq ++;
} while ((flags & ISNS_FLAG_LAST_PDU) == 0);
return (total_pdu_len);
}
}
return (0);
}
static void *
{
int sa_sz;
/* determin local IP address */
/* IPv4 */
sa_sz = sizeof (struct sockaddr_in);
/* Create socket */
} else {
/* IPv6 */
sa_sz = sizeof (struct sockaddr_in6);
/* Create socket */
}
!= 0) {
/* not calling isnst_close_so() to */
/* make dtrace output look clear */
}
}
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
char s[INET6_ADDRSTRLEN];
void *ip;
} else {
}
}
return (so);
}
static void
isnst_close_so(void *so)
{
}
/*
* ESI handling
*/
static void
isnst_esi_start(void)
{
/*
* Wait for the thread to start
*/
while (!esi.esi_thread_running) {
}
}
static void
{
/* Shutdown ESI listening socket, wait for thread to terminate */
} else {
}
}
/*
* isnst_esi_thread
*
* This function listens on a socket for incoming connections from an
* iSNS server until told to stop.
*/
/*ARGSUSED*/
static void
isnst_esi_thread(void *arg)
{
struct sockaddr_in6 sin6;
int rc;
sin_addrlen = sizeof (struct sockaddr_in6);
/*
* Mark the thread as running and the portal as no longer new.
*/
while (esi.esi_enabled) {
/*
* Create a socket to listen for requests from the iSNS server.
*/
NULL) {
"isnst_esi_thread: Unable to create socket");
continue;
}
/*
* Set options, bind, and listen until we're told to stop
*/
continue;
}
/*
* Get the port (sin6 is meaningless at this point)
*/
"failure 0x%x", rc);
continue;
}
while (esi.esi_enabled) {
/*
* If we were interrupted with EINTR
* it's not really a failure.
*/
"accept failure (0x%x)", rc);
continue;
} else {
break;
}
}
if (pl_size == 0) {
"rcv_pdu failure");
continue;
}
/*
* 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.
*/
if (esi.esi_enabled)
}
thread_exit();
}
/*
* Handle an incoming ESI request
*/
static void
{
static char log_addr_buf[INET6_ADDRSTRLEN];
struct sockaddr_storage ss;
struct sockaddr_in6 *portal_addr6;
return;
}
"payload exceeds PDU size (%d > %d)",
(int)pdu_size);
/* Not all data is present -- ignore */
return;
}
"isnst_handle_esi_req: PDU payload exceeds max (%ld bytes)",
req_pl_len + sizeof (uint32_t));
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
*/
while (tlv_len <= req_pl_len) {
switch (attr_id) {
case ISNS_TIMESTAMP_ATTR_ID:
break;
case ISNS_EID_ATTR_ID:
break;
/* Bad attribute format */
} else {
sizeof (portal_addr6->sin6_addr));
}
break;
case ISNS_PORTAL_PORT_ATTR_ID:
/* Bad attribute format */
} else {
}
break;
default:
/* Bad request format */
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;
}
if (!portal_port_valid)
if (portal_addr_valid) {
} else {
}
/*
* 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.
*/
if ((esi_response != ISNS_RSP_SUCCESSFUL) ||
!isnst_portal_exists(&ss)) {
return;
}
/*
* Build response validating the portal
*/
if (rsp_size == 0) {
return;
}
/* Use xid from the request pdu */
/* Copy original data */
"isnst_handle_esi_req: Send response failed");
}
/*
* 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.
*/
}
}
int
{
/*
* Sort by target (pointer to iscsit_tgt_t).
*/
return (-1);
return (1);
}
return (0);
}
static void
isnst_get_target_list(void)
{
/*
* Initialize our list of targets with those from the global
* list that are online.
*/
(void) isnst_add_to_target_list(tgt);
}
}
}
static void
{
if (registered == B_TRUE) {
} else {
}
}
static boolean_t
isnst_lookup_default_portal(struct sockaddr_storage *p)
{
struct sockaddr_storage dportal_ss;
int idx;
/*
* 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
*/
return (B_FALSE);
}
/*
* Get the global list of default portals
*/
if (default_portal_list_size == 0) {
"No default portals");
return (B_FALSE);
}
/*
* Scan the through the current default portal list (this should
* be refreshed just before lookup since the contents can change)
*/
/*
* Translate the address idm_get_ipaddr returned into
* sockaddr_storage format
*/
sizeof (struct in_addr));
sizeof (struct in6_addr)) {
sizeof (struct in6_addr));
} else {
continue;
}
/*
* Now we can compare to the address we were passed
*/
if (idm_ss_compare(p, &dportal_ss,
B_TRUE /* v4_mapped_as_v4 */) == 0) {
}
}
return (result);
}
/*
* These functions are called by iscsit proper when a portal comes online
* or goes offline.
*/
void
{
if (portal->portal_default) {
/* Portals should only be onlined once */
return;
}
}
void
{
if (portal->portal_default) {
/* Portals should only be offlined once */
return;
}
}