summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsun_ima/common/ima.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsun_ima/common/ima.c')
-rw-r--r--usr/src/lib/libsun_ima/common/ima.c3212
1 files changed, 3212 insertions, 0 deletions
diff --git a/usr/src/lib/libsun_ima/common/ima.c b/usr/src/lib/libsun_ima/common/ima.c
new file mode 100644
index 0000000000..f35016f5ef
--- /dev/null
+++ b/usr/src/lib/libsun_ima/common/ima.c
@@ -0,0 +1,3212 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#include <wchar.h>
+#include <widec.h>
+#include <libsysevent.h>
+#include <sys/nvpair.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <time.h>
+#include <libdevinfo.h>
+#include <sys/scsi/adapters/iscsi_if.h>
+#include <sys/scsi/adapters/iscsi_protocol.h>
+#include <ima.h>
+
+#define LIBRARY_PROPERTY_IMPLEMENTATION_VERSION L"1.0.0"
+#define LIBRARY_PROPERTY_VENDOR L"Sun Microsystems, Inc."
+#define OS_DEVICE_NAME "/devices/iscsi"
+#define LIBRARY_FILE_NAME L"libsun_ima.so"
+
+#define OS_DEVICE_NAME_LEN 256
+#define INQUIRY_CMD 0x12
+#define GETCAPACITY_CMD 0x25
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_REPLY_LEN 96
+#define USCSI_TIMEOUT_IN_SEC 10
+#define MAX_AUTHMETHODS 10
+#define NUM_SUPPORTED_AUTH_METHODS 2
+#define SUN_IMA_MAX_DIGEST_ALGORITHMS 2 /* NONE and CRC 32 */
+#define SUN_IMA_IP_ADDRESS_LEN 256
+#define SUN_IMA_IP_PORT_LEN 64
+#define SUN_IMA_MAX_RADIUS_SECRET_LEN 128
+
+/* Forward declaration */
+#define BOOL_PARAM 1
+#define MIN_MAX_PARAM 2
+
+/* OK */
+#define DISC_ADDR_OK 0
+/* Incorrect IP address */
+#define DISC_ADDR_INTEGRITY_ERROR 1
+/* Error converting text IP address to numeric binary form */
+#define DISC_ADDR_IP_CONV_ERROR 2
+
+/* Currently not defined in IMA_TARGET_DISCOVERY_METHOD enum */
+#define IMA_TARGET_DISCOVERY_METHOD_UNKNOWN 0
+
+static IMA_OID lhbaObjectId;
+static IMA_UINT32 pluginOwnerId;
+static sysevent_handle_t *shp;
+
+
+
+/*
+ * Custom struct to allow tgpt to be specified.
+ */
+typedef struct _SUN_IMA_DISC_ADDRESS_KEY
+{
+ IMA_NODE_NAME name;
+ IMA_ADDRESS_KEY address;
+ IMA_UINT16 tpgt;
+} SUN_IMA_DISC_ADDRESS_KEY;
+
+/*
+ * Custom struct to allow tgpt to be specified.
+ */
+typedef struct _SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES
+{
+ IMA_UINT keyCount;
+ SUN_IMA_DISC_ADDRESS_KEY keys[1];
+} SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES;
+
+/*
+ * Custom struct to allow tgpt to be specified.
+ */
+typedef struct _SUN_IMA_DISC_ADDR_PROP_LIST
+{
+ IMA_UINT discAddrCount;
+ IMA_DISCOVERY_ADDRESS_PROPERTIES props[1];
+} SUN_IMA_DISC_ADDR_PROP_LIST;
+
+
+static IMA_OBJECT_VISIBILITY_FN pObjectVisibilityCallback = NULL;
+static IMA_OBJECT_PROPERTY_FN pObjectPropertyCallback = NULL;
+
+static IMA_STATUS getISCSINodeParameter(int paramType, IMA_OID *oid,
+ void *pProps, uint32_t paramIndex);
+static IMA_STATUS setISCSINodeParameter(int paramType, IMA_OID *oid,
+ void *pProps, uint32_t paramIndex);
+static IMA_STATUS setAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
+ const IMA_AUTHMETHOD *pMethodList);
+static IMA_STATUS getAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList);
+
+static int prepare_discovery_entry(IMA_TARGET_ADDRESS discoveryAddress,
+ entry_t *entry);
+static IMA_STATUS configure_discovery_method(IMA_BOOL enable,
+ iSCSIDiscoveryMethod_t method);
+static IMA_STATUS get_target_oid_list(uint32_t targetListType,
+ IMA_OID_LIST **ppList);
+static IMA_STATUS get_target_lun_oid_list(IMA_OID * targetOid,
+ iscsi_lun_list_t **ppLunList);
+static int get_lun_devlink(di_devlink_t link, void *osDeviceName);
+static IMA_STATUS getDiscoveryAddressPropertiesList(
+ SUN_IMA_DISC_ADDR_PROP_LIST **ppList
+);
+static IMA_STATUS sendTargets(IMA_TARGET_ADDRESS address,
+ SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
+);
+
+static IMA_STATUS getSupportedAuthMethods(IMA_OID lhbaOid,
+ IMA_BOOL getSettableMethods, IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList);
+static IMA_STATUS getLuProperties(IMA_OID luId, IMA_LU_PROPERTIES *pProps);
+static IMA_STATUS getTargetProperties(IMA_OID targetId,
+ IMA_TARGET_PROPERTIES *pProps);
+
+void InitLibrary();
+
+static void libSwprintf(wchar_t *wcs, const wchar_t *lpszFormat, ...)
+{
+ va_list args;
+ va_start(args, lpszFormat);
+ (void) vswprintf(wcs, OS_DEVICE_NAME_LEN - 1, lpszFormat, args);
+ va_end(args);
+}
+
+static void
+sysevent_handler(sysevent_t *ev)
+{
+ IMA_OID tmpOid;
+ IMA_BOOL becomingVisible = IMA_FALSE;
+ IMA_UINT i;
+
+ const char *visibility_subclasses[] = {
+ ESC_ISCSI_STATIC_START,
+ ESC_ISCSI_STATIC_END,
+ ESC_ISCSI_SEND_TARGETS_START,
+ ESC_ISCSI_SEND_TARGETS_END,
+ ESC_ISCSI_SLP_START,
+ ESC_ISCSI_SLP_END,
+ ESC_ISCSI_ISNS_START,
+ ESC_ISCSI_ISNS_END,
+ NULL
+ };
+
+ tmpOid.ownerId = pluginOwnerId;
+ tmpOid.objectType = IMA_OBJECT_TYPE_TARGET;
+ tmpOid.objectSequenceNumber = 0;
+
+ /* Make sure our event class matches what we are looking for */
+ if (strncmp(EC_ISCSI, sysevent_get_class_name(ev),
+ strlen(EC_ISCSI)) != 0) {
+ return;
+ }
+
+
+ /* Check for object property changes */
+ if ((strncmp(ESC_ISCSI_PROP_CHANGE,
+ sysevent_get_subclass_name(ev),
+ strlen(ESC_ISCSI_PROP_CHANGE)) == 0)) {
+ if (pObjectPropertyCallback != NULL)
+ pObjectPropertyCallback(tmpOid);
+ } else {
+ i = 0;
+ while (visibility_subclasses[i] != NULL) {
+ if ((strncmp(visibility_subclasses[i],
+ sysevent_get_subclass_name(ev),
+ strlen(visibility_subclasses[i])) == 0) &&
+ pObjectVisibilityCallback != NULL) {
+ becomingVisible = IMA_TRUE;
+ pObjectVisibilityCallback(becomingVisible,
+ tmpOid);
+ }
+ i++;
+ }
+ }
+}
+
+IMA_STATUS init_sysevents() {
+ const char *subclass_list[] = {
+ ESC_ISCSI_STATIC_START,
+ ESC_ISCSI_STATIC_END,
+ ESC_ISCSI_SEND_TARGETS_START,
+ ESC_ISCSI_SEND_TARGETS_END,
+ ESC_ISCSI_SLP_START,
+ ESC_ISCSI_SLP_END,
+ ESC_ISCSI_ISNS_START,
+ ESC_ISCSI_ISNS_END,
+ ESC_ISCSI_PROP_CHANGE,
+ };
+
+ /* Bind event handler and create subscriber handle */
+ shp = sysevent_bind_handle(sysevent_handler);
+ if (shp == NULL) {
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (sysevent_subscribe_event(shp, EC_ISCSI, subclass_list, 9) != 0) {
+ sysevent_unbind_handle(shp);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_STATUS Initialize(IMA_UINT32 pluginOid) {
+ pluginOwnerId = pluginOid;
+ return (init_sysevents());
+}
+
+void Terminate() {
+ if (shp != NULL) {
+ sysevent_unsubscribe_event(shp, EC_ISCSI);
+ }
+
+}
+
+void InitLibrary() {
+}
+
+static void GetBuildTime(IMA_DATETIME* pdatetime)
+{
+ (void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetNodeProperties(
+ IMA_OID nodeOid,
+ IMA_NODE_PROPERTIES *pProps
+)
+{
+ int fd;
+ iscsi_param_get_t pg;
+
+ pProps->runningInInitiatorMode = IMA_TRUE;
+ pProps->runningInTargetMode = IMA_FALSE;
+ pProps->nameAndAliasSettable = IMA_FALSE;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&pg, 0, sizeof (iscsi_param_get_t));
+ pg.g_vers = ISCSI_INTERFACE_VERSION;
+ pg.g_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME;
+
+ if (ioctl(fd, ISCSI_PARAM_GET, &pg) == -1) {
+ pProps->nameValid = IMA_FALSE;
+ } else {
+ if (strlen((char *)pg.g_value.v_name) > 0) {
+ (void) mbstowcs(pProps->name,
+ (char *)pg.g_value.v_name,
+ IMA_NODE_NAME_LEN);
+ pProps->nameValid = IMA_TRUE;
+ } else {
+ pProps->nameValid = IMA_FALSE;
+ }
+ }
+
+ (void) memset(&pg, 0, sizeof (iscsi_param_get_t));
+ pg.g_vers = ISCSI_INTERFACE_VERSION;
+ pg.g_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
+ (void) memset(pProps->alias, 0,
+ sizeof (IMA_WCHAR) * IMA_NODE_ALIAS_LEN);
+ if (ioctl(fd, ISCSI_PARAM_GET, &pg) == -1) {
+ pProps->aliasValid = IMA_FALSE;
+ } else {
+ if (strlen((char *)pg.g_value.v_name) > 0) {
+ (void) mbstowcs(pProps->alias,
+ (char *)pg.g_value.v_name,
+ IMA_NODE_ALIAS_LEN);
+ pProps->aliasValid = IMA_TRUE;
+ }
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_SetNodeName(
+ IMA_OID nodeOid,
+ const IMA_NODE_NAME newName
+)
+{
+ int fd;
+ iscsi_param_set_t ps;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&ps, 0, sizeof (iscsi_param_set_t));
+ ps.s_oid = nodeOid.objectSequenceNumber;
+ ps.s_vers = ISCSI_INTERFACE_VERSION;
+ ps.s_param = ISCSI_LOGIN_PARAM_INITIATOR_NAME;
+ (void) wcstombs((char *)ps.s_value.v_name, newName, ISCSI_MAX_NAME_LEN);
+ if (ioctl(fd, ISCSI_INIT_NODE_NAME_SET, &ps)) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_SetNodeAlias(
+ IMA_OID nodeOid,
+ const IMA_NODE_ALIAS newAlias
+)
+{
+ int fd;
+ iscsi_param_set_t ps;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&ps, 0, sizeof (iscsi_param_set_t));
+ ps.s_oid = nodeOid.objectSequenceNumber;
+ ps.s_vers = ISCSI_INTERFACE_VERSION;
+ ps.s_param = ISCSI_LOGIN_PARAM_INITIATOR_ALIAS;
+
+ /* newAlias = NULL specifies that the alias should be deleted. */
+ if (newAlias != NULL)
+ (void) wcstombs((char *)ps.s_value.v_name, newAlias,
+ ISCSI_MAX_NAME_LEN);
+ else
+ (void) wcstombs((char *)ps.s_value.v_name,
+ L"", ISCSI_MAX_NAME_LEN);
+
+ if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+IMA_API IMA_STATUS IMA_GetLhbaOidList(
+ IMA_OID_LIST **ppList
+)
+{
+ /* Always return the same object ID for the lhba */
+ lhbaObjectId.objectType = IMA_OBJECT_TYPE_LHBA;
+ lhbaObjectId.ownerId = pluginOwnerId;
+ lhbaObjectId.objectSequenceNumber = ISCSI_INITIATOR_OID;
+
+ *ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST));
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ (*ppList)->oidCount = 1;
+ (void) memcpy(&(*ppList)->oids[0],
+ &lhbaObjectId, sizeof (lhbaObjectId));
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+/*
+ * Get the discovery properties of the LHBA
+ */
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetDiscoveryProperties(
+ IMA_OID oid,
+ IMA_DISCOVERY_PROPERTIES *pProps
+)
+{
+ int fd;
+ iSCSIDiscoveryProperties_t discoveryProps;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&discoveryProps, 0, sizeof (discoveryProps));
+ discoveryProps.vers = ISCSI_INTERFACE_VERSION;
+
+ if (ioctl(fd, ISCSI_DISCOVERY_PROPS, &discoveryProps) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_PROPS ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ pProps->iSnsDiscoverySettable = discoveryProps.iSNSDiscoverySettable;
+ pProps->iSnsDiscoveryEnabled = discoveryProps.iSNSDiscoveryEnabled;
+ /*
+ * Set the iSNS discovery method - The IMA specification indicates
+ * this field is valid only if iSNS discovery is enabled.
+ */
+ if (pProps->iSnsDiscoveryEnabled == IMA_TRUE) {
+ switch (discoveryProps.iSNSDiscoveryMethod) {
+ case iSNSDiscoveryMethodStatic:
+ pProps->iSnsDiscoveryMethod =
+ IMA_ISNS_DISCOVERY_METHOD_STATIC;
+ break;
+ case iSNSDiscoveryMethodDHCP:
+ pProps->iSnsDiscoveryMethod =
+ IMA_ISNS_DISCOVERY_METHOD_DHCP;
+ break;
+ case iSNSDiscoveryMethodSLP:
+ pProps->iSnsDiscoveryMethod =
+ IMA_ISNS_DISCOVERY_METHOD_SLP;
+ break;
+ default:
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+ (void) memcpy(pProps->iSnsHost.id.hostname,
+ discoveryProps.iSNSDomainName,
+ sizeof (pProps->iSnsHost.id.hostname));
+ pProps->slpDiscoverySettable = discoveryProps.SLPDiscoverySettable;
+ pProps->slpDiscoveryEnabled = discoveryProps.SLPDiscoveryEnabled;
+ pProps->staticDiscoverySettable =
+ discoveryProps.StaticDiscoverySettable;
+ pProps->staticDiscoveryEnabled = discoveryProps.StaticDiscoveryEnabled;
+ pProps->sendTargetsDiscoverySettable =
+ discoveryProps.SendTargetsDiscoverySettable;
+ pProps->sendTargetsDiscoveryEnabled =
+ discoveryProps.SendTargetsDiscoveryEnabled;
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_FreeMemory(
+ void *pMemory
+)
+{
+ if (pMemory != NULL)
+ free(pMemory);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetNonSharedNodeOidList(
+ IMA_OID_LIST **ppList
+)
+{
+ if (ppList == NULL)
+ return (IMA_ERROR_INVALID_PARAMETER);
+
+ *ppList = (IMA_OID_LIST*) calloc(1, sizeof (IMA_OID_LIST));
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = 0;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetFirstBurstLengthProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH));
+}
+
+IMA_API IMA_STATUS IMA_GetMaxBurstLengthProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH));
+}
+
+IMA_API IMA_STATUS IMA_GetMaxRecvDataSegmentLengthProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH));
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_PluginIOCtl(
+ IMA_OID pluginOid,
+ IMA_UINT command,
+ const void *pInputBuffer,
+ IMA_UINT inputBufferLength,
+ void *pOutputBuffer,
+ IMA_UINT *pOutputBufferLength
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+IMA_API IMA_STATUS IMA_SetFirstBurstLength(
+ IMA_OID lhbaId,
+ IMA_UINT firstBurstLength
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = firstBurstLength;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_FIRST_BURST_LENGTH));
+}
+
+IMA_API IMA_STATUS IMA_SetMaxBurstLength(
+ IMA_OID lhbaId,
+ IMA_UINT maxBurstLength
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = maxBurstLength;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_MAX_BURST_LENGTH));
+}
+
+IMA_API IMA_STATUS IMA_SetMaxRecvDataSegmentLength(
+ IMA_OID lhbaId,
+ IMA_UINT maxRecvDataSegmentLength
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = maxRecvDataSegmentLength;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_MAX_RECV_DATA_SEGMENT_LENGTH));
+}
+
+IMA_API IMA_STATUS IMA_GetMaxConnectionsProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_MAX_CONNECTIONS));
+}
+
+IMA_API IMA_STATUS IMA_SetMaxConnections(
+ IMA_OID lhbaId,
+ IMA_UINT maxConnections
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = maxConnections;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_MAX_CONNECTIONS));
+}
+
+IMA_API IMA_STATUS IMA_GetDefaultTime2RetainProperties(
+ IMA_OID lhbaId,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, pProps,
+ ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN));
+}
+
+IMA_API IMA_STATUS IMA_SetDefaultTime2Retain(
+ IMA_OID lhbaId,
+ IMA_UINT defaultTime2Retain
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = defaultTime2Retain;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_RETAIN));
+}
+
+IMA_API IMA_STATUS IMA_GetDefaultTime2WaitProperties(
+ IMA_OID lhbaId,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, pProps,
+ ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT));
+}
+
+IMA_API IMA_STATUS IMA_SetDefaultTime2Wait(
+ IMA_OID lhbaId,
+ IMA_UINT defaultTime2Wait
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = defaultTime2Wait;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_DEFAULT_TIME_2_WAIT));
+}
+
+IMA_API IMA_STATUS IMA_GetMaxOutstandingR2TProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_OUTSTANDING_R2T));
+}
+
+IMA_API IMA_STATUS IMA_SetMaxOutstandingR2T(
+ IMA_OID lhbaId,
+ IMA_UINT maxOutstandingR2T
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = maxOutstandingR2T;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &lhbaId, &mv,
+ ISCSI_LOGIN_PARAM_OUTSTANDING_R2T));
+}
+
+
+IMA_API IMA_STATUS IMA_GetErrorRecoveryLevelProperties(
+ IMA_OID Oid,
+ IMA_MIN_MAX_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(MIN_MAX_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL));
+}
+
+IMA_API IMA_STATUS IMA_SetErrorRecoveryLevel(
+ IMA_OID Oid,
+ IMA_UINT errorRecoveryLevel
+)
+{
+ IMA_MIN_MAX_VALUE mv;
+
+ mv.currentValue = errorRecoveryLevel;
+ return (setISCSINodeParameter(MIN_MAX_PARAM, &Oid, &mv,
+ ISCSI_LOGIN_PARAM_ERROR_RECOVERY_LEVEL));
+}
+
+IMA_API IMA_STATUS IMA_GetInitialR2TProperties(
+ IMA_OID Oid,
+ IMA_BOOL_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_INITIAL_R2T));
+}
+
+IMA_API IMA_STATUS IMA_SetInitialR2T(
+ IMA_OID Oid,
+ IMA_BOOL initialR2T
+)
+{
+ IMA_BOOL_VALUE bv;
+
+ bv.currentValue = initialR2T;
+ return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
+ ISCSI_LOGIN_PARAM_INITIAL_R2T));
+}
+
+
+IMA_API IMA_STATUS IMA_GetImmediateDataProperties(
+ IMA_OID Oid,
+ IMA_BOOL_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_IMMEDIATE_DATA));
+}
+
+IMA_API IMA_STATUS IMA_SetImmediateData(
+ IMA_OID Oid,
+ IMA_BOOL immediateData
+)
+{
+ IMA_BOOL_VALUE bv;
+
+ bv.currentValue = immediateData;
+ return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
+ ISCSI_LOGIN_PARAM_IMMEDIATE_DATA));
+}
+
+IMA_API IMA_STATUS IMA_GetDataPduInOrderProperties(
+ IMA_OID Oid,
+ IMA_BOOL_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER));
+}
+
+IMA_API IMA_STATUS IMA_SetDataPduInOrder(
+ IMA_OID Oid,
+ IMA_BOOL dataPduInOrder
+)
+{
+ IMA_BOOL_VALUE bv;
+
+ bv.currentValue = dataPduInOrder;
+ return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
+ ISCSI_LOGIN_PARAM_DATA_PDU_IN_ORDER));
+}
+
+IMA_API IMA_STATUS IMA_GetDataSequenceInOrderProperties(
+ IMA_OID Oid,
+ IMA_BOOL_VALUE *pProps
+)
+{
+ return (getISCSINodeParameter(BOOL_PARAM, &Oid, pProps,
+ ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER));
+}
+
+IMA_API IMA_STATUS IMA_SetDataSequenceInOrder(
+ IMA_OID Oid,
+ IMA_BOOL dataSequenceInOrder
+)
+{
+ IMA_BOOL_VALUE bv;
+
+ bv.currentValue = dataSequenceInOrder;
+ return (setISCSINodeParameter(BOOL_PARAM, &Oid, &bv,
+ ISCSI_LOGIN_PARAM_DATA_SEQUENCE_IN_ORDER));
+}
+
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_SetStatisticsCollection(
+ IMA_OID Oid,
+ IMA_BOOL enableStatisticsCollection
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetDiscoveryAddressOidList(
+ IMA_OID Oid,
+ IMA_OID_LIST **ppList
+)
+{
+ int fd, i, addr_list_size;
+ iscsi_addr_list_t *idlp, al_info;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&al_info, 0, sizeof (al_info));
+ al_info.al_vers = ISCSI_INTERFACE_VERSION;
+ al_info.al_in_cnt = 0;
+
+ /*
+ * Issue ioctl to obtain the number of targets.
+ */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ addr_list_size = sizeof (iscsi_addr_list_t);
+ if (al_info.al_out_cnt > 1) {
+ addr_list_size += (sizeof (iscsi_addr_list_t) *
+ al_info.al_out_cnt - 1);
+ }
+
+ idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
+ if (idlp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ idlp->al_vers = ISCSI_INTERFACE_VERSION;
+ idlp->al_in_cnt = al_info.al_out_cnt;
+ /* Issue the same ioctl again to obtain the OIDs. */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ free(idlp);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ *ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
+ idlp->al_out_cnt * sizeof (IMA_OID));
+ if (*ppList == NULL) {
+ free(idlp);
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = idlp->al_out_cnt;
+
+ for (i = 0; i < idlp->al_out_cnt; i++) {
+ (*ppList)->oids[i].objectType =
+ IMA_OBJECT_TYPE_DISCOVERY_ADDRESS;
+ (*ppList)->oids[i].ownerId = pluginOwnerId;
+ (*ppList)->oids[i].objectSequenceNumber =
+ idlp->al_addrs[i].a_oid;
+ }
+
+ free(idlp);
+ (void) close(fd);
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetStaticDiscoveryTargetOidList(
+ IMA_OID Oid,
+ IMA_OID_LIST **ppList
+)
+{
+ if (Oid.objectType == IMA_OBJECT_TYPE_PNP) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ return (get_target_oid_list(ISCSI_STATIC_TGT_OID_LIST, ppList));
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetTargetOidList(
+ IMA_OID Oid,
+ IMA_OID_LIST **ppList
+)
+{
+ return (get_target_oid_list(ISCSI_TGT_PARAM_OID_LIST, ppList));
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_SetIsnsDiscovery(
+ IMA_OID phbaId,
+ IMA_BOOL enableIsnsDiscovery,
+ IMA_ISNS_DISCOVERY_METHOD discoveryMethod,
+ const IMA_HOST_ID *iSnsHost
+)
+{
+ /* XXX need to set discovery Method and domaineName */
+ return (configure_discovery_method(enableIsnsDiscovery,
+ iSCSIDiscoveryMethodISNS));
+}
+
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetSlpDiscovery(
+ IMA_OID phbaId,
+ IMA_BOOL enableSlpDiscovery
+)
+{
+ return (configure_discovery_method(enableSlpDiscovery,
+ iSCSIDiscoveryMethodSLP));
+}
+
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetStaticDiscovery(
+ IMA_OID phbaId,
+ IMA_BOOL enableStaticDiscovery
+)
+{
+ return (configure_discovery_method(enableStaticDiscovery,
+ iSCSIDiscoveryMethodStatic));
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetSendTargetsDiscovery(
+ IMA_OID phbaId,
+ IMA_BOOL enableSendTargetsDiscovery
+)
+{
+ return (configure_discovery_method(enableSendTargetsDiscovery,
+ iSCSIDiscoveryMethodSendTargets));
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_RemoveDiscoveryAddress(
+ IMA_OID discoveryAddressOid
+)
+{
+ int status, fd, i, addr_list_size;
+ iscsi_addr_list_t *idlp, al_info;
+ iscsi_addr_t *matched_addr = NULL;
+ entry_t entry;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&al_info, 0, sizeof (al_info));
+ al_info.al_vers = ISCSI_INTERFACE_VERSION;
+ al_info.al_in_cnt = 0;
+
+ /*
+ * Issue ioctl to obtain the number of discovery address.
+ */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (al_info.al_out_cnt == 0) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ addr_list_size = sizeof (iscsi_addr_list_t);
+ if (al_info.al_out_cnt > 1) {
+ addr_list_size += (sizeof (iscsi_addr_list_t) *
+ al_info.al_out_cnt - 1);
+ }
+
+ idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
+ if (idlp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ idlp->al_vers = ISCSI_INTERFACE_VERSION;
+ idlp->al_in_cnt = al_info.al_out_cnt;
+
+ /* Issue the same ioctl again to obtain the OIDs. */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ free(idlp);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ for (i = 0; i < idlp->al_out_cnt; i++) {
+ if (discoveryAddressOid.objectSequenceNumber !=
+ idlp->al_addrs[i].a_oid)
+ continue;
+ matched_addr = &(idlp->al_addrs[i]);
+ }
+
+ if (matched_addr == NULL) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+
+ (void) memset(&entry, 0, sizeof (entry_t));
+ entry.e_vers = ISCSI_INTERFACE_VERSION;
+ entry.e_oid = discoveryAddressOid.objectSequenceNumber;
+ if (matched_addr->a_addr.i_insize == sizeof (struct in_addr)) {
+ bcopy(&matched_addr->a_addr.i_addr.in4,
+ &entry.e_u.u_in4, sizeof (entry.e_u.u_in4));
+ entry.e_insize = sizeof (struct in_addr);
+ } else if (matched_addr->a_addr.i_insize == sizeof (struct in6_addr)) {
+ bcopy(&matched_addr->a_addr.i_addr.in6,
+ &entry.e_u.u_in6, sizeof (entry.e_u.u_in6));
+ entry.e_insize = sizeof (struct in6_addr);
+ } else {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ entry.e_port = matched_addr->a_port;
+ entry.e_tpgt = 0;
+ entry.e_oid = discoveryAddressOid.objectSequenceNumber;
+
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_CLEAR, &entry)) {
+ status = errno;
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_CLEAR ioctl failed, errno: %d",
+ errno);
+ if (status == EBUSY) {
+ return (IMA_ERROR_LU_IN_USE);
+ } else {
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+
+ free(idlp);
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_AddDiscoveryAddress(
+ IMA_OID oid,
+ const IMA_TARGET_ADDRESS discoveryAddress,
+ IMA_OID *pDiscoveryAddressOid
+)
+{
+ entry_t entry;
+ int fd;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (prepare_discovery_entry(discoveryAddress, &entry) !=
+ DISC_ADDR_OK) {
+ (void) close(fd);
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_SET, &entry)) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_SET ioctl failed, errno: %d",
+ errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ pDiscoveryAddressOid->ownerId = pluginOwnerId;
+ pDiscoveryAddressOid->objectType = IMA_OBJECT_TYPE_DISCOVERY_ADDRESS;
+ pDiscoveryAddressOid->objectSequenceNumber = entry.e_oid;
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetStaticDiscoveryTargetProperties(
+ IMA_OID staticTargetOid,
+ IMA_STATIC_DISCOVERY_TARGET_PROPERTIES *pProps
+)
+{
+ char static_target_addr_str[SUN_IMA_IP_ADDRESS_LEN];
+ char static_target_addr_port_str[SUN_IMA_IP_ADDRESS_LEN];
+ int af, fd, status;
+ iscsi_static_property_t prop;
+ /* LINTED */
+ IMA_HOST_ID *host;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&prop, 0, sizeof (iscsi_static_property_t));
+ prop.p_vers = ISCSI_INTERFACE_VERSION;
+ prop.p_oid = (uint32_t)staticTargetOid.objectSequenceNumber;
+ if (ioctl(fd, ISCSI_STATIC_GET, &prop) != 0) {
+ status = errno;
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET ioctl failed, errno: %d", status);
+ if (status == ENOENT) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+
+ } else {
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+ (void) close(fd);
+
+ (void) mbstowcs(pProps->staticTarget.targetName, (char *)prop.p_name,
+ sizeof (pProps->staticTarget.targetName)/sizeof (IMA_WCHAR));
+
+ if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
+ sizeof (struct in_addr)) {
+ /* IPv4 */
+ af = AF_INET;
+ } else if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
+ sizeof (struct in6_addr)) {
+ /* IPv6 */
+ af = AF_INET6;
+ } else {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (inet_ntop(af, &prop.p_addr_list.al_addrs[0].a_addr.i_addr,
+ static_target_addr_str, sizeof (static_target_addr_str)) == NULL) {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned address that cannot "
+ "be inet_ntop");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ } else {
+ if (af == AF_INET) {
+ (void) snprintf(static_target_addr_port_str,
+ SUN_IMA_IP_ADDRESS_LEN,
+ "%s:%ld",
+ static_target_addr_str,
+ prop.p_addr_list.al_addrs[0].a_port);
+ } else {
+ (void) snprintf(static_target_addr_port_str,
+ SUN_IMA_IP_ADDRESS_LEN,
+ "[%s]:%ld",
+ static_target_addr_str,
+ prop.p_addr_list.al_addrs[0].a_port);
+ }
+ host = &pProps->staticTarget.targetAddress.hostnameIpAddress;
+ (void) mbstowcs(pProps->staticTarget.
+ targetAddress.hostnameIpAddress.
+ id.hostname, static_target_addr_port_str,
+ sizeof (host->id.hostname) / sizeof (IMA_WCHAR));
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetDiscoveryAddressProperties(
+ IMA_OID discoveryAddressOid,
+ IMA_DISCOVERY_ADDRESS_PROPERTIES *pProps
+)
+{
+ int fd;
+ int i;
+ int addr_list_size;
+ iscsi_addr_list_t *idlp, al_info;
+ iscsi_addr_t *matched_addr = NULL;
+ /* LINTED */
+ IMA_TARGET_ADDRESS *addr;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&al_info, 0, sizeof (al_info));
+ al_info.al_vers = ISCSI_INTERFACE_VERSION;
+ al_info.al_in_cnt = 0;
+
+ /*
+ * Issue ioctl to obtain the number of discovery addresses.
+ */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (al_info.al_out_cnt == 0) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ addr_list_size = sizeof (iscsi_addr_list_t);
+ if (al_info.al_out_cnt > 1) {
+ addr_list_size += (sizeof (iscsi_addr_list_t) *
+ al_info.al_out_cnt - 1);
+ }
+
+ idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
+ if (idlp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ idlp->al_vers = ISCSI_INTERFACE_VERSION;
+ idlp->al_in_cnt = al_info.al_out_cnt;
+
+ /* Issue the same ioctl again to obtain the OIDs. */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
+ free(idlp);
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
+ ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ for (i = 0; i < idlp->al_out_cnt; i++) {
+ if (discoveryAddressOid.objectSequenceNumber !=
+ idlp->al_addrs[i].a_oid)
+ continue;
+ matched_addr = &(idlp->al_addrs[i]);
+ }
+
+ if (matched_addr == NULL) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ if (matched_addr->a_addr.i_insize == sizeof (struct in_addr)) {
+ pProps->discoveryAddress.hostnameIpAddress.id.
+ ipAddress.ipv4Address = IMA_TRUE;
+ } else if (matched_addr->a_addr.i_insize == sizeof (struct in6_addr)) {
+ pProps->discoveryAddress.hostnameIpAddress.id.
+ ipAddress.ipv4Address = IMA_FALSE;
+ } else {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ addr = &pProps->discoveryAddress;
+ bcopy(&(matched_addr->a_addr.i_addr), pProps->discoveryAddress.
+ hostnameIpAddress.id.ipAddress.ipAddress,
+ sizeof (addr->hostnameIpAddress.id.ipAddress.ipAddress));
+
+ pProps->discoveryAddress.portNumber = matched_addr->a_port;
+
+ pProps->associatedLhbaOid.objectType = IMA_OBJECT_TYPE_LHBA;
+ pProps->associatedLhbaOid.ownerId = pluginOwnerId;
+ pProps->associatedLhbaOid.objectSequenceNumber = ISCSI_INITIATOR_OID;
+
+ free(idlp);
+ (void) close(fd);
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_RemoveStaticDiscoveryTarget(
+ IMA_OID staticTargetOid
+)
+{
+ entry_t entry;
+ int status, fd;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&entry, 0, sizeof (entry_t));
+ entry.e_vers = ISCSI_INTERFACE_VERSION;
+ entry.e_oid = (uint32_t)staticTargetOid.objectSequenceNumber;
+
+ if (ioctl(fd, ISCSI_STATIC_CLEAR, &entry)) {
+ status = errno;
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_CLEAR ioctl failed, errno: %d", errno);
+ if (status == EBUSY) {
+ return (IMA_ERROR_LU_IN_USE);
+ } else {
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_AddStaticDiscoveryTarget(
+ IMA_OID lhbaOid,
+ const IMA_STATIC_DISCOVERY_TARGET staticConfig,
+ IMA_OID *pTargetOid
+)
+{
+ char tmp_target_str[SUN_IMA_IP_ADDRESS_LEN];
+ char target_addr_str[SUN_IMA_IP_ADDRESS_LEN];
+ char target_port_str[SUN_IMA_IP_PORT_LEN];
+ iscsi_target_entry_t target;
+ int fd;
+ int target_in_addr_size;
+ int target_port;
+ union {
+ struct in_addr u_in4;
+ struct in6_addr u_in6;
+ } target_in;
+
+ /*
+ * staticConfig.address may come in with port number at its trailer.
+ * Parse it to separate the IP address and port number.
+ * Also translate the hostname to IP address if needed.
+ */
+ (void) wcstombs(tmp_target_str,
+ staticConfig.targetAddress.hostnameIpAddress.
+ id.hostname, sizeof (tmp_target_str));
+
+ if (tmp_target_str[0] == '[') {
+ /* IPv6 address */
+ char *closeBracketPos;
+ closeBracketPos = strchr(tmp_target_str, ']');
+ if (!closeBracketPos) {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ *closeBracketPos = NULL;
+ (void) strlcpy(target_addr_str, &tmp_target_str[1],
+ sizeof (target_addr_str));
+
+ if (inet_pton(AF_INET6, target_addr_str,
+ &target_in.u_in6) != 1) {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+ target_in_addr_size = sizeof (struct in6_addr);
+
+ /* Extract the port number */
+ closeBracketPos++;
+ if (*closeBracketPos == ':') {
+ closeBracketPos++;
+
+ if (*closeBracketPos != NULL) {
+ (void) strlcpy(target_port_str, closeBracketPos,
+ sizeof (target_port_str));
+ target_port = atoi(target_port_str);
+ } else {
+ target_port = ISCSI_LISTEN_PORT;
+ }
+ } else {
+ /* No port number specified; use default port */
+ target_port = ISCSI_LISTEN_PORT;
+ }
+ } else {
+ /* IPv4 address */
+ char *colonPos;
+ colonPos = strchr(tmp_target_str, ':');
+ if (!colonPos) {
+ /* No port number specified; use default port */
+ target_port = ISCSI_LISTEN_PORT;
+ (void) strlcpy(target_addr_str, tmp_target_str,
+ sizeof (target_addr_str));
+ } else {
+ *colonPos = NULL;
+ (void) strlcpy(target_addr_str, tmp_target_str,
+ sizeof (target_addr_str));
+ /* Extract the port number */
+ colonPos++;
+ if (*colonPos != NULL) {
+ (void) strlcpy(target_port_str, colonPos,
+ sizeof (target_port_str));
+ target_port = atoi(target_port_str);
+ } else {
+ target_port = ISCSI_LISTEN_PORT;
+ }
+ }
+
+ if (inet_pton(AF_INET, target_addr_str,
+ &target_in.u_in4) != 1) {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ target_in_addr_size = sizeof (struct in_addr);
+ }
+
+
+ (void) memset(&target, 0, sizeof (iscsi_target_entry_t));
+ target.te_entry.e_vers = ISCSI_INTERFACE_VERSION;
+ target.te_entry.e_oid = ISCSI_OID_NOTSET;
+ target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
+
+ (void) wcstombs((char *)target.te_name, staticConfig.targetName,
+ ISCSI_MAX_NAME_LEN);
+
+ target.te_entry.e_insize = target_in_addr_size;
+ if (target.te_entry.e_insize == sizeof (struct in_addr)) {
+ target.te_entry.e_u.u_in4.s_addr = target_in.u_in4.s_addr;
+ } else if (target.te_entry.e_insize == sizeof (struct in6_addr)) {
+ bcopy(target_in.u_in6.s6_addr,
+ target.te_entry.e_u.u_in6.s6_addr,
+ sizeof (struct in6_addr));
+ } else {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ target.te_entry.e_port = target_port;
+
+ /* No target portal group specified. Default to -1. */
+ target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (ioctl(fd, ISCSI_STATIC_SET, &target)) {
+ /*
+ * Encountered problem setting the IP address and port for
+ * the target just added.
+ */
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_SET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ pTargetOid->objectType = IMA_OBJECT_TYPE_TARGET;
+ pTargetOid->ownerId = pluginOwnerId;
+ pTargetOid->objectSequenceNumber = target.te_entry.e_oid;
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetTargetProperties(
+ IMA_OID targetId,
+ IMA_TARGET_PROPERTIES *pProps
+)
+{
+ return (getTargetProperties(targetId, pProps));
+}
+
+static IMA_STATUS getTargetProperties(
+ IMA_OID targetId,
+ IMA_TARGET_PROPERTIES *pProps
+)
+{
+ int fd;
+ iscsi_property_t prop;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&prop, 0, sizeof (iscsi_property_t));
+ prop.p_vers = ISCSI_INTERFACE_VERSION;
+ prop.p_oid = (uint32_t)targetId.objectSequenceNumber;
+
+ if (ioctl(fd, ISCSI_TARGET_PROPS_GET, &prop) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) mbstowcs(pProps->name, (char *)prop.p_name, IMA_NODE_NAME_LEN);
+ (void) memset(pProps->alias, 0,
+ sizeof (IMA_WCHAR) * IMA_NODE_ALIAS_LEN);
+ if (prop.p_alias_len > 0) {
+ (void) mbstowcs(pProps->alias, (char *)prop.p_alias,
+ IMA_NODE_ALIAS_LEN);
+ }
+
+ /* Initialize the discovery method to unknown method. */
+ pProps->discoveryMethodFlags = IMA_TARGET_DISCOVERY_METHOD_UNKNOWN;
+ if (!((prop.p_discovery & iSCSIDiscoveryMethodStatic) ^
+ iSCSIDiscoveryMethodStatic)) {
+ pProps->discoveryMethodFlags |=
+ IMA_TARGET_DISCOVERY_METHOD_STATIC;
+ }
+
+ if (!((prop.p_discovery & iSCSIDiscoveryMethodSLP) ^
+ iSCSIDiscoveryMethodSLP)) {
+ pProps->discoveryMethodFlags |= IMA_TARGET_DISCOVERY_METHOD_SLP;
+ }
+
+ if (!((prop.p_discovery & iSCSIDiscoveryMethodISNS) ^
+ iSCSIDiscoveryMethodISNS)) {
+ pProps->discoveryMethodFlags |= iSCSIDiscoveryMethodISNS;
+ }
+
+ if (!((prop.p_discovery & iSCSIDiscoveryMethodSendTargets) ^
+ iSCSIDiscoveryMethodSendTargets)) {
+ pProps->discoveryMethodFlags |= iSCSIDiscoveryMethodSendTargets;
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetTargetErrorStatistics(
+ IMA_OID targetId,
+ IMA_TARGET_ERROR_STATISTICS *pStats
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+IMA_API IMA_STATUS IMA_GetLuOidList(
+ IMA_OID oid,
+ IMA_OID_LIST **ppList
+)
+{
+ IMA_STATUS status;
+ int i;
+ iscsi_lun_list_t *pLunList;
+
+ if (oid.objectType == IMA_OBJECT_TYPE_LHBA) {
+ status = get_target_lun_oid_list(NULL, &pLunList);
+ } else {
+ status = get_target_lun_oid_list(&oid, &pLunList);
+ }
+
+ if (!IMA_SUCCESS(status)) {
+ return (status);
+ }
+
+ *ppList = (IMA_OID_LIST *) calloc(1, (sizeof (IMA_OID_LIST) +
+ (pLunList->ll_out_cnt * sizeof (IMA_OID))));
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = pLunList->ll_out_cnt;
+ for (i = 0; i < pLunList->ll_out_cnt; i++) {
+ (*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_LU;
+ (*ppList)->oids[i].ownerId = pluginOwnerId;
+ (*ppList)->oids[i].objectSequenceNumber =
+ pLunList->ll_luns[i].l_oid;
+ }
+
+ free(pLunList);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetLuOid(
+ IMA_OID targetId,
+ IMA_UINT64 lun,
+ IMA_OID *pluId
+)
+{
+ IMA_STATUS status;
+ int i;
+ iscsi_lun_list_t *pLunList;
+
+ status = get_target_lun_oid_list(&targetId, &pLunList);
+ if (!IMA_SUCCESS(status)) {
+ return (status);
+ }
+
+ for (i = 0; i < pLunList->ll_out_cnt; i++) {
+ if (pLunList->ll_luns[i].l_num == lun) {
+ pluId->objectType = IMA_OBJECT_TYPE_LU;
+ pluId->ownerId = pluginOwnerId;
+ pluId->objectSequenceNumber =
+ pLunList->ll_luns[i].l_oid;
+ free(pLunList);
+ return (IMA_STATUS_SUCCESS);
+ }
+ }
+
+ free(pLunList);
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+IMA_API IMA_STATUS IMA_GetLuProperties(
+ IMA_OID luId,
+ IMA_LU_PROPERTIES *pProps
+)
+{
+ return (getLuProperties(luId, pProps));
+}
+
+static IMA_STATUS getLuProperties(
+ IMA_OID luId,
+ IMA_LU_PROPERTIES *pProps
+)
+{
+ IMA_STATUS status;
+ iscsi_lun_list_t *pLunList;
+ int j;
+ IMA_BOOL lunMatch = IMA_FALSE;
+ int fd;
+ iscsi_lun_props_t lun;
+ di_devlink_handle_t hdl;
+
+ if (luId.objectType != IMA_OBJECT_TYPE_LU) {
+ return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
+ }
+
+ /*
+ * get list of lun oids for all targets
+ */
+ status = get_target_lun_oid_list(NULL, &pLunList);
+ if (!IMA_SUCCESS(status)) {
+ return (status);
+ }
+ for (j = 0; j < pLunList->ll_out_cnt; j++) {
+ /*
+ * for each lun, check if match is found
+ */
+ if (pLunList->ll_luns[j].l_oid == luId.objectSequenceNumber) {
+ /*
+ * match found, break out of lun loop
+ */
+ lunMatch = IMA_TRUE;
+ break;
+ }
+ }
+
+ if (lunMatch == IMA_TRUE) {
+ (void) memset(&lun, 0, sizeof (iscsi_lun_props_t));
+ lun.lp_vers = ISCSI_INTERFACE_VERSION;
+ lun.lp_tgt_oid = pLunList->ll_luns[j].l_tgt_oid;
+ lun.lp_oid = pLunList->ll_luns[j].l_oid;
+ }
+
+ free(pLunList);
+
+ if (lunMatch == IMA_FALSE) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ /*
+ * get lun properties
+ */
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (ioctl(fd, ISCSI_LUN_PROPS_GET, &lun)) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_LUN_PROPS_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ (void) close(fd);
+
+ /*
+ * set property values
+ */
+ pProps->associatedTargetOid.objectType = IMA_OBJECT_TYPE_TARGET;
+ pProps->associatedTargetOid.ownerId = pluginOwnerId;
+ pProps->associatedTargetOid.objectSequenceNumber = lun.lp_tgt_oid;
+ pProps->targetLun = (IMA_UINT64)lun.lp_num;
+ pProps->exposedToOs = IMA_TRUE;
+ (void) memset(&pProps->timeExposedToOs, 0,
+ sizeof (pProps->timeExposedToOs));
+
+ if (lun.lp_status == LunValid) {
+
+ /* add minor device delimiter */
+ (void) strcat(lun.lp_pathname, ":");
+
+ if ((strstr(lun.lp_pathname, "sd@") != NULL) ||
+ (strstr(lun.lp_pathname, "ssd@") != NULL) ||
+ (strstr(lun.lp_pathname, "disk@") != NULL)) {
+ /*
+ * modify returned pathname to obtain the 2nd slice
+ * of the raw disk
+ */
+ (void) strcat(lun.lp_pathname, "c,raw");
+ }
+
+ /*
+ * Pathname returned by driver is the physical device path.
+ * This name needs to be converted to the OS device name.
+ */
+ if (hdl = di_devlink_init(lun.lp_pathname, DI_MAKE_LINK)) {
+ pProps->osDeviceName[0] = L'\0';
+ (void) di_devlink_walk(hdl, NULL, lun.lp_pathname,
+ DI_PRIMARY_LINK, (void *)pProps->osDeviceName,
+ get_lun_devlink);
+ if (pProps->osDeviceName[0] != L'\0') {
+ /* OS device name synchronously made */
+ pProps->osDeviceNameValid = IMA_TRUE;
+ } else {
+ pProps->osDeviceNameValid = IMA_FALSE;
+ }
+
+ (void) di_devlink_fini(&hdl);
+ } else {
+ pProps->osDeviceNameValid = IMA_FALSE;
+ }
+
+ } else {
+ pProps->osDeviceNameValid = IMA_FALSE;
+ }
+
+ pProps->osParallelIdsValid = IMA_FALSE;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetStatisticsProperties(
+ IMA_OID oid,
+ IMA_STATISTICS_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetDeviceStatistics(
+ IMA_OID luId,
+ IMA_DEVICE_STATISTICS *pStats
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_LuInquiry(
+ IMA_OID deviceId,
+ IMA_BOOL evpd,
+ IMA_BOOL cmddt,
+ IMA_BYTE pageCode,
+ IMA_BYTE *pOutputBuffer,
+ IMA_UINT *pOutputBufferLength,
+ IMA_BYTE *pSenseBuffer,
+ IMA_UINT *pSenseBufferLength
+)
+{
+ IMA_LU_PROPERTIES luProps;
+ IMA_STATUS status;
+
+ char cmdblk [ INQUIRY_CMDLEN ] =
+ { INQUIRY_CMD, /* command */
+ 0, /* lun/reserved */
+ 0, /* page code */
+ 0, /* reserved */
+ INQUIRY_REPLY_LEN, /* allocation length */
+ 0 }; /* reserved/flag/link */
+
+
+ int fd;
+ iscsi_uscsi_t uscsi;
+
+ cmdblk[2] = pageCode;
+
+ (void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
+ uscsi.iu_vers = ISCSI_INTERFACE_VERSION;
+
+ /* iu_oid is a session oid in the driver */
+ if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
+ uscsi.iu_oid = deviceId.objectSequenceNumber;
+ uscsi.iu_lun = 0;
+ } else {
+ /*
+ * Get LU properties and associated session oid
+ * for this lun(deviceId) and put in uscsi.iu_oid
+ */
+ status = getLuProperties(deviceId, &luProps);
+ if (status != IMA_STATUS_SUCCESS) {
+ return (status);
+ }
+ uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
+ objectSequenceNumber;
+ uscsi.iu_lun = luProps.targetLun;
+ }
+
+ uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
+ uscsi.iu_ucmd.uscsi_timeout = USCSI_TIMEOUT_IN_SEC;
+ uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
+ uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
+ uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
+ uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
+ uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
+ uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_LuReadCapacity(
+ IMA_OID deviceId,
+ IMA_UINT cdbLength,
+ IMA_BYTE *pOutputBuffer,
+ IMA_UINT *pOutputBufferLength,
+
+ IMA_BYTE *pSenseBuffer,
+ IMA_UINT *pSenseBufferLength
+)
+{
+ IMA_LU_PROPERTIES luProps;
+ IMA_STATUS status;
+ int fd;
+ iscsi_uscsi_t uscsi;
+
+ char cmdblk [ INQUIRY_CMDLEN ] =
+ { GETCAPACITY_CMD, /* command */
+ 0, /* lun/reserved */
+ 0, /* page code */
+ 0, /* reserved */
+ INQUIRY_REPLY_LEN, /* allocation length */
+ 0 }; /* reserved/flag/link */
+
+
+
+ (void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
+ uscsi.iu_vers = ISCSI_INTERFACE_VERSION;
+
+ /* iu_oid is a session oid in the driver */
+ if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
+ uscsi.iu_oid = deviceId.objectSequenceNumber;
+ uscsi.iu_lun = 0;
+ } else {
+ /*
+ * Get LU properties and associated session oid
+ * for this lun(deviceId) and put in uscsi.iu_oid
+ */
+ status = getLuProperties(deviceId, &luProps);
+ if (status != IMA_STATUS_SUCCESS) {
+ return (status);
+ }
+ uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
+ objectSequenceNumber;
+ uscsi.iu_lun = luProps.targetLun;
+ }
+
+ uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
+ uscsi.iu_ucmd.uscsi_timeout = 10;
+ uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
+ uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
+ uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
+ uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
+ uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
+ uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_LuReportLuns(
+ IMA_OID deviceId,
+ IMA_BOOL sendToWellKnownLun,
+ IMA_BYTE selectReport,
+
+ IMA_BYTE *pOutputBuffer,
+ IMA_UINT *pOutputBufferLength,
+
+ IMA_BYTE *pSenseBuffer,
+ IMA_UINT *pSenseBufferLength
+)
+{
+ IMA_LU_PROPERTIES luProps;
+ IMA_STATUS status;
+ int fd;
+ iscsi_uscsi_t uscsi;
+
+ char cmdblk [ INQUIRY_CMDLEN ] =
+ { INQUIRY_CMD, /* command */
+ 0, /* lun/reserved */
+ 0, /* page code */
+ 0, /* reserved */
+ INQUIRY_REPLY_LEN, /* allocation length */
+ 0 }; /* reserved/flag/link */
+
+ (void) memset(&uscsi, 0, sizeof (iscsi_uscsi_t));
+ uscsi.iu_vers = ISCSI_INTERFACE_VERSION;
+
+ /* iu_oid is a session oid in the driver */
+ if (deviceId.objectType == IMA_OBJECT_TYPE_TARGET) {
+ uscsi.iu_oid = deviceId.objectSequenceNumber;
+ uscsi.iu_lun = 0;
+ } else {
+ /*
+ * Get LU properties and associated session oid
+ * for this lun(deviceId) and put in uscsi.iu_oid
+ */
+ status = getLuProperties(deviceId, &luProps);
+ if (status != IMA_STATUS_SUCCESS) {
+ return (status);
+ }
+ uscsi.iu_oid = (uint32_t)luProps.associatedTargetOid.
+ objectSequenceNumber;
+ uscsi.iu_lun = luProps.targetLun;
+ }
+
+ uscsi.iu_ucmd.uscsi_flags = USCSI_READ;
+ uscsi.iu_ucmd.uscsi_timeout = 10;
+ uscsi.iu_ucmd.uscsi_bufaddr = (char *)pOutputBuffer;
+ uscsi.iu_ucmd.uscsi_buflen = *pOutputBufferLength;
+ uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer;
+ uscsi.iu_ucmd.uscsi_rqlen = *pSenseBufferLength;
+ uscsi.iu_ucmd.uscsi_cdb = &cmdblk[0];
+ uscsi.iu_ucmd.uscsi_cdblen = INQUIRY_CMDLEN;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (ioctl(fd, ISCSI_USCSI, &uscsi) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_ExposeLu(
+ IMA_OID luId
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_UnexposeLu(
+ IMA_OID luId
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+IMA_API IMA_STATUS IMA_GetAddressKeys(
+ IMA_OID targetOid,
+ IMA_ADDRESS_KEYS **ppKeys
+)
+{
+ IMA_STATUS status;
+ IMA_TARGET_PROPERTIES targetProps;
+ SUN_IMA_DISC_ADDR_PROP_LIST *discAddressList;
+ SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
+ int i, j, addressKeyCount = 0;
+ int addressKeyIdx = 0;
+
+ status = getTargetProperties(targetOid, &targetProps);
+ if (status != IMA_STATUS_SUCCESS) {
+ return (status);
+ }
+
+ status = getDiscoveryAddressPropertiesList(&discAddressList);
+ if (status != IMA_STATUS_SUCCESS) {
+ return (status);
+ }
+
+ /* Get the number of addresses to allocate */
+ for (i = 0; i < discAddressList->discAddrCount; i++) {
+ (void) sendTargets(discAddressList->props[i].discoveryAddress,
+ &pList);
+ for (j = 0; j < pList->keyCount; j++) {
+ if (wcsncmp(pList->keys[j].name, targetProps.name,
+ wslen(pList->keys[j].name)) == 0) {
+ addressKeyCount++;
+ }
+ }
+ (void) IMA_FreeMemory(pList);
+ }
+
+ *ppKeys = (IMA_ADDRESS_KEYS *)calloc(1, sizeof (IMA_ADDRESS_KEYS) +
+ addressKeyCount * sizeof (IMA_ADDRESS_KEY));
+ if (*ppKeys == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppKeys)->addressKeyCount = addressKeyCount;
+ addressKeyIdx = 0;
+
+ for (i = 0; i < discAddressList->discAddrCount; i++) {
+ (void) sendTargets(discAddressList->props[i].discoveryAddress,
+ &pList);
+ for (j = 0; j < pList->keyCount; j++) {
+ if (wcsncmp(pList->keys[j].name, targetProps.name,
+ wslen(pList->keys[j].name)) != 0) {
+ continue;
+ }
+
+ bcopy(&(pList->keys[j].address.ipAddress),
+ &((*ppKeys)->addressKeys[addressKeyIdx].
+ ipAddress), sizeof (IMA_IP_ADDRESS));
+
+ (*ppKeys)->addressKeys[addressKeyIdx++].portNumber =
+ pList->keys[j].address.portNumber;
+
+ }
+ (void) IMA_FreeMemory(pList);
+ }
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_BOOL isAuthMethodValid(IMA_OID oid, IMA_AUTHMETHOD method) {
+ IMA_STATUS status;
+ IMA_AUTHMETHOD supportedList[MAX_AUTHMETHODS];
+ IMA_UINT i, supportedCount;
+ IMA_BOOL supported;
+ status = getSupportedAuthMethods(oid, IMA_FALSE, &supportedCount,
+ supportedList);
+ if (status != IMA_STATUS_SUCCESS)
+ return (IMA_FALSE);
+
+ supported = IMA_FALSE;
+ for (i = 0; i < supportedCount; i++) {
+ if (method == supportedList[i]) {
+ supported = IMA_TRUE;
+ }
+ }
+
+ return (supported);
+}
+
+IMA_BOOL isAuthMethodListValid(IMA_OID oid, const IMA_AUTHMETHOD *pMethodList,
+ IMA_UINT methodCount) {
+ IMA_UINT i, j;
+
+ if (pMethodList == NULL) {
+ return (IMA_FALSE);
+ }
+ /* Check list for duplicates */
+ for (i = 0; i < methodCount; i++) {
+ for (j = i + 1; j < methodCount; j++) {
+ if (pMethodList[i] == pMethodList[j]) {
+ return (IMA_FALSE);
+ }
+ }
+
+ if (isAuthMethodValid(oid, pMethodList[i]) == IMA_FALSE) {
+ return (IMA_FALSE);
+ }
+ }
+ return (IMA_TRUE);
+}
+
+IMA_API IMA_STATUS IMA_GetSupportedAuthMethods(
+ IMA_OID lhbaOid,
+ IMA_BOOL getSettableMethods,
+ IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList
+)
+{
+ return (getSupportedAuthMethods(lhbaOid, getSettableMethods,
+ pMethodCount, pMethodList));
+}
+
+
+/*ARGSUSED*/
+static IMA_STATUS getSupportedAuthMethods(
+ IMA_OID lhbaOid,
+ IMA_BOOL getSettableMethods,
+ IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList
+)
+{
+ if (pMethodList == NULL) {
+ *pMethodCount = 0;
+ return (IMA_STATUS_SUCCESS);
+ }
+
+ *pMethodCount = NUM_SUPPORTED_AUTH_METHODS;
+ if (*pMethodCount > 1) {
+ pMethodList[0] = IMA_AUTHMETHOD_NONE;
+ pMethodList[1] = IMA_AUTHMETHOD_CHAP;
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetInUseInitiatorAuthMethods(
+ IMA_OID lhbaOid,
+ IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList
+)
+{
+ return (getAuthMethods(lhbaOid, pMethodCount, pMethodList));
+}
+
+/*ARGSUSED*/
+IMA_API IMA_STATUS IMA_GetInitiatorAuthParms(
+ IMA_OID lhbaOid,
+ IMA_AUTHMETHOD method,
+ IMA_INITIATOR_AUTHPARMS *pParms
+)
+{
+ int fd;
+ iscsi_chap_props_t chap_p;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
+ chap_p.c_vers = ISCSI_INTERFACE_VERSION;
+ chap_p.c_oid = (uint32_t)lhbaOid.objectSequenceNumber;
+
+ if (method == IMA_AUTHMETHOD_CHAP) {
+ if (ioctl(fd, ISCSI_CHAP_GET, &chap_p) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_CHAP_GET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ } else {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ (void) memcpy(pParms->chapParms.name, chap_p.c_user,
+ chap_p.c_user_len);
+ pParms->chapParms.nameLength = chap_p.c_user_len;
+ (void) memcpy(pParms->chapParms.challengeSecret, chap_p.c_secret,
+ chap_p.c_secret_len);
+ pParms->chapParms.challengeSecretLength = chap_p.c_secret_len;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_SetInitiatorAuthMethods(
+ IMA_OID lhbaOid,
+ IMA_UINT methodCount,
+ const IMA_AUTHMETHOD *pMethodList
+)
+{
+ if (isAuthMethodListValid(lhbaOid, pMethodList,
+ methodCount) == IMA_FALSE)
+ return (IMA_ERROR_INVALID_PARAMETER);
+ return (setAuthMethods(lhbaOid, &methodCount, pMethodList));
+}
+
+/*
+ * This function only sets CHAP params since we only support CHAP for now.
+ */
+IMA_API IMA_STATUS IMA_SetInitiatorAuthParms(
+ IMA_OID lhbaOid,
+ IMA_AUTHMETHOD method,
+ const IMA_INITIATOR_AUTHPARMS *pParms
+)
+{
+ int fd;
+ iscsi_chap_props_t chap_p;
+
+ if (method != IMA_AUTHMETHOD_CHAP)
+ return (IMA_ERROR_INVALID_PARAMETER);
+
+ if (isAuthMethodValid(lhbaOid, method) == IMA_FALSE) {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
+ chap_p.c_vers = ISCSI_INTERFACE_VERSION;
+ chap_p.c_oid = (uint32_t)lhbaOid.objectSequenceNumber;
+
+ chap_p.c_user_len = pParms->chapParms.nameLength;
+ (void) memcpy(chap_p.c_user, pParms->chapParms.name, chap_p.c_user_len);
+
+ chap_p.c_secret_len = pParms->chapParms.challengeSecretLength;
+ (void) memcpy(chap_p.c_secret, pParms->chapParms.challengeSecret,
+ chap_p.c_secret_len);
+
+ if (method == IMA_AUTHMETHOD_CHAP) {
+ if (ioctl(fd, ISCSI_CHAP_SET, &chap_p) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_CHAP_SET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* A helper function to obtain iSCSI node parameters. */
+static IMA_STATUS
+getISCSINodeParameter(
+ int paramType,
+ IMA_OID *oid,
+ void *pProps,
+ uint32_t paramIndex
+)
+{
+ int fd;
+ iscsi_param_get_t pg;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&pg, 0, sizeof (iscsi_param_get_t));
+ pg.g_vers = ISCSI_INTERFACE_VERSION;
+ pg.g_oid = (uint32_t)oid->objectSequenceNumber;
+ pg.g_param = paramIndex;
+ pg.g_param_type = ISCSI_SESS_PARAM;
+
+ if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ switch (paramType) {
+ IMA_BOOL_VALUE *bp;
+ IMA_MIN_MAX_VALUE *mp;
+
+ case MIN_MAX_PARAM:
+ mp = (IMA_MIN_MAX_VALUE *)pProps;
+
+ mp->currentValueValid =
+ (pg.g_value.v_valid == B_TRUE) ?
+ IMA_TRUE : IMA_FALSE;
+ mp->currentValue = pg.g_value.v_integer.i_current;
+ mp->defaultValue = pg.g_value.v_integer.i_default;
+ mp->minimumValue = pg.g_value.v_integer.i_min;
+ mp->maximumValue = pg.g_value.v_integer.i_max;
+ mp->incrementValue = pg.g_value.v_integer.i_incr;
+ break;
+
+ case BOOL_PARAM:
+ bp = (IMA_BOOL_VALUE *)pProps;
+ bp->currentValueValid =
+ (pg.g_value.v_valid == B_TRUE) ?
+ IMA_TRUE : IMA_FALSE;
+ bp->currentValue = pg.g_value.v_bool.b_current;
+ bp->defaultValue = pg.g_value.v_bool.b_default;
+ break;
+
+ default:
+ break;
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* A helper function to set iSCSI node parameters. */
+static IMA_STATUS
+setISCSINodeParameter(
+ int paramType,
+ IMA_OID *oid,
+ void *pProp,
+ uint32_t paramIndex
+)
+{
+ int fd;
+ iscsi_param_set_t ps;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&ps, 0, sizeof (iscsi_param_set_t));
+ ps.s_vers = ISCSI_INTERFACE_VERSION;
+ ps.s_oid = (uint32_t)oid->objectSequenceNumber;
+ ps.s_param = paramIndex;
+
+ switch (paramType) {
+ IMA_BOOL_VALUE *bp;
+ IMA_MIN_MAX_VALUE *mp;
+
+ case MIN_MAX_PARAM:
+ mp = (IMA_MIN_MAX_VALUE *)pProp;
+ ps.s_value.v_integer = mp->currentValue;
+ break;
+ case BOOL_PARAM:
+ bp = (IMA_BOOL_VALUE *)pProp;
+ ps.s_value.v_bool =
+ (bp->currentValue == IMA_TRUE) ?
+ B_TRUE : B_FALSE;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
+ int tmpErrno = errno;
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ switch (tmpErrno) {
+ case ENOTSUP :
+ return (IMA_ERROR_NOT_SUPPORTED);
+ default :
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+static int
+prepare_discovery_entry(
+ IMA_TARGET_ADDRESS discoveryAddress,
+ entry_t *entry
+)
+{
+ (void) memset(entry, 0, sizeof (entry_t));
+ entry->e_vers = ISCSI_INTERFACE_VERSION;
+ entry->e_oid = ISCSI_OID_NOTSET;
+
+ if (discoveryAddress.hostnameIpAddress.id.ipAddress.ipv4Address ==
+ IMA_FALSE) {
+ bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
+ entry->e_u.u_in6.s6_addr,
+ sizeof (entry->e_u.u_in6.s6_addr));
+ entry->e_insize = sizeof (struct in6_addr);
+ } else {
+ bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
+ &entry->e_u.u_in4.s_addr,
+ sizeof (entry->e_u.u_in4.s_addr));
+ entry->e_insize = sizeof (struct in_addr);
+ }
+
+ entry->e_port = discoveryAddress.portNumber;
+ entry->e_tpgt = 0;
+ return (DISC_ADDR_OK);
+}
+
+static IMA_STATUS configure_discovery_method(
+ IMA_BOOL enable,
+ iSCSIDiscoveryMethod_t method
+)
+{
+ int fd, status;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ if (enable == IMA_FALSE) {
+ if (ioctl(fd, ISCSI_DISCOVERY_CLEAR, &method)) {
+ status = errno;
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_CLEAR ioctl failed, errno: %d",
+ status);
+ if (status == EBUSY) {
+ return (IMA_ERROR_LU_IN_USE);
+ } else {
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+ } else {
+ /* Set the discovery method */
+ if (ioctl(fd, ISCSI_DISCOVERY_SET, &method)) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_SET ioctl failed, errno: %d",
+ errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+ }
+}
+
+static IMA_STATUS get_target_oid_list(
+ uint32_t targetListType,
+ IMA_OID_LIST **ppList)
+{
+ int fd;
+ int i;
+ int target_list_size;
+ iscsi_target_list_t *idlp, tl_info;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&tl_info, 0, sizeof (tl_info));
+ tl_info.tl_vers = ISCSI_INTERFACE_VERSION;
+ tl_info.tl_in_cnt = 0;
+ tl_info.tl_tgt_list_type = targetListType;
+
+ /*
+ * Issue ioctl to obtain the number of targets.
+ */
+ if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, &tl_info) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
+ targetListType, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ target_list_size = sizeof (iscsi_target_list_t);
+ if (tl_info.tl_out_cnt > 1) {
+ target_list_size += (sizeof (uint32_t) *
+ tl_info.tl_out_cnt - 1);
+ }
+
+ idlp = (iscsi_target_list_t *)calloc(1, target_list_size);
+ if (idlp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ idlp->tl_vers = ISCSI_INTERFACE_VERSION;
+ idlp->tl_in_cnt = tl_info.tl_out_cnt;
+ idlp->tl_tgt_list_type = targetListType;
+
+ /* Issue the same ioctl again to obtain the OIDs. */
+ if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
+ free(idlp);
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
+ targetListType, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ *ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
+ idlp->tl_out_cnt * sizeof (IMA_OID));
+ if (*ppList == NULL) {
+ free(idlp);
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = idlp->tl_out_cnt;
+
+ for (i = 0; i < idlp->tl_out_cnt; i++) {
+
+ if (targetListType == ISCSI_STATIC_TGT_OID_LIST)
+ (*ppList)->oids[i].objectType =
+ IMA_OBJECT_TYPE_STATIC_DISCOVERY_TARGET;
+ else
+ (*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET;
+
+ (*ppList)->oids[i].ownerId = pluginOwnerId;
+ (*ppList)->oids[i].objectSequenceNumber = idlp->tl_oid_list[i];
+ }
+
+ free(idlp);
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+static IMA_STATUS get_target_lun_oid_list(
+ IMA_OID * targetOid,
+ iscsi_lun_list_t **ppLunList)
+{
+ int fd;
+ iscsi_lun_list_t *illp, ll_info;
+ int lun_list_size;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&ll_info, 0, sizeof (ll_info));
+ ll_info.ll_vers = ISCSI_INTERFACE_VERSION;
+ if (targetOid == NULL) {
+ /* get lun oid list for all targets */
+ ll_info.ll_all_tgts = B_TRUE;
+ } else {
+ /* get lun oid list for single target */
+ ll_info.ll_all_tgts = B_FALSE;
+ ll_info.ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber;
+ }
+ ll_info.ll_in_cnt = 0;
+
+ /*
+ * Issue ioctl to obtain the number of target LUNs.
+ */
+ if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, &ll_info) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ lun_list_size = sizeof (iscsi_lun_list_t);
+ if (ll_info.ll_out_cnt > 1) {
+ lun_list_size += (sizeof (iscsi_if_lun_t) *
+ (ll_info.ll_out_cnt - 1));
+ }
+
+ illp = (iscsi_lun_list_t *)calloc(1, lun_list_size);
+ if (illp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ illp->ll_vers = ISCSI_INTERFACE_VERSION;
+ illp->ll_all_tgts = ll_info.ll_all_tgts;
+ illp->ll_tgt_oid = ll_info.ll_tgt_oid;
+ illp->ll_in_cnt = ll_info.ll_out_cnt;
+
+ /* Issue the same ioctl again to get the target LUN list */
+ if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
+ free(illp);
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ *ppLunList = illp;
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+/* A helper function to set authentication method. */
+static IMA_STATUS
+setAuthMethods(
+ IMA_OID oid,
+ IMA_UINT *pMethodCount,
+ const IMA_AUTHMETHOD *pMethodList
+)
+{
+ int fd;
+ int i;
+ iscsi_auth_props_t auth;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+ (void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
+ auth.a_vers = ISCSI_INTERFACE_VERSION;
+ auth.a_oid = (uint32_t)oid.objectSequenceNumber;
+ /* First do a get because other data fields may exist */
+ if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
+ /* EMPTY */
+ /* It is fine if there is no other data fields. */
+ }
+ auth.a_auth_method = authMethodNone;
+
+ for (i = 0; i < *pMethodCount; i++) {
+ switch (pMethodList[i]) {
+ case IMA_AUTHMETHOD_CHAP:
+ auth.a_auth_method |= authMethodCHAP;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_AUTH_SET failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* A helper function to get authentication method. */
+static IMA_STATUS
+getAuthMethods(
+ IMA_OID oid,
+ IMA_UINT *pMethodCount,
+ IMA_AUTHMETHOD *pMethodList
+)
+{
+ int fd, i;
+ iscsi_auth_props_t auth;
+
+ if (pMethodList == NULL) {
+ *pMethodCount = 0;
+ return (IMA_STATUS_SUCCESS);
+ }
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
+ auth.a_vers = ISCSI_INTERFACE_VERSION;
+ auth.a_oid = (uint32_t)oid.objectSequenceNumber;
+
+ if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_AUTH_GET failed, errno: %d", errno);
+ (void) close(fd);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ i = 0;
+ if (auth.a_auth_method == IMA_AUTHMETHOD_NONE) {
+ pMethodList[i++] = IMA_AUTHMETHOD_NONE;
+ } else if (auth.a_auth_method & authMethodCHAP) {
+ pMethodList[i++] = IMA_AUTHMETHOD_CHAP;
+ }
+ *pMethodCount = i;
+
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetPhbaOidList(
+ IMA_OID_LIST **ppList
+)
+{
+ *ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST));
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = 0;
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPhbaProperties(
+ IMA_OID phbaOid,
+ IMA_PHBA_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPhbaStatus(
+ IMA_OID phbaOid,
+ IMA_PHBA_STATUS *pStatus
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPhbaDownloadProperties(
+ IMA_OID phbaOid,
+ IMA_PHBA_DOWNLOAD_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_IsPhbaDownloadFile(
+ IMA_OID phbaOid,
+ const IMA_WCHAR *pFileName,
+ IMA_PHBA_DOWNLOAD_IMAGE_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_PhbaDownload(
+ IMA_OID phbaOid,
+ IMA_PHBA_DOWNLOAD_IMAGE_TYPE imageType,
+ const IMA_WCHAR *pFileName
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+IMA_API IMA_STATUS IMA_GetPnpOidList(
+ IMA_OID pnpOid,
+ IMA_OID_LIST **ppList
+)
+{
+ /*
+ * Always return the same object ID for the pnp as the spec
+ * states that this function will always return a list of at least
+ * one element
+ */
+ pnpOid.objectType = IMA_OBJECT_TYPE_PNP;
+ pnpOid.ownerId = pluginOwnerId;
+ pnpOid.objectSequenceNumber = ISCSI_INITIATOR_OID;
+
+ *ppList = (IMA_OID_LIST*)calloc(1, sizeof (IMA_OID_LIST) +
+ (1* sizeof (IMA_OID)));
+
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ (*ppList)->oidCount = 1;
+ (void) memcpy(&(*ppList)->oids[0], &pnpOid, sizeof (pnpOid));
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPnpProperties(
+ IMA_OID pnpOid,
+ IMA_PNP_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPnpStatistics(
+ IMA_OID pnpOid,
+ IMA_PNP_STATISTICS *pStats
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetIpProperties(
+ IMA_OID oid,
+ IMA_IP_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetDefaultGateway(
+ IMA_OID oid,
+ IMA_IP_ADDRESS defaultGateway
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetDnsServerAddress(
+ IMA_OID oid,
+ const IMA_IP_ADDRESS *pPrimaryDnsServerAddress,
+ const IMA_IP_ADDRESS *pAlternateDnsServerAddress
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetSubnetMask(
+ IMA_OID oid,
+ IMA_IP_ADDRESS subnetMask
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetIpConfigMethod(
+ IMA_OID oid,
+ IMA_BOOL enableDhcpIpConfiguration
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+IMA_API IMA_STATUS IMA_RegisterForObjectPropertyChanges(
+ IMA_OBJECT_PROPERTY_FN pClientFn
+)
+{
+ pObjectPropertyCallback = pClientFn;
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_DeregisterForObjectPropertyChanges(
+ IMA_OBJECT_PROPERTY_FN pClientFn
+)
+{
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_RegisterForObjectVisibilityChanges(
+ IMA_OBJECT_VISIBILITY_FN pClientFn
+)
+{
+ pObjectVisibilityCallback = pClientFn;
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_DeregisterForObjectVisibilityChanges(
+ IMA_OBJECT_VISIBILITY_FN pClientFn
+)
+{
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetNetworkPortStatus(
+ IMA_OID portOid,
+ IMA_NETWORK_PORT_STATUS *pStaus
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetNetworkPortalOidList(
+ IMA_OID pnpOid,
+ IMA_OID_LIST **ppList
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetNetworkPortalProperties(
+ IMA_OID networkPortalOid,
+ IMA_NETWORK_PORTAL_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_SetNetworkPortalIpAddress(
+ IMA_OID networkPortalOid,
+ const IMA_IP_ADDRESS NewIpAddress
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_RemoveStaleData(
+ IMA_OID lhbaOid
+)
+{
+ return (IMA_ERROR_NOT_SUPPORTED);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetIpsecProperties(
+ IMA_OID oid,
+ IMA_IPSEC_PROPERTIES *pProps
+)
+{
+ pProps->ipsecSupported = IMA_TRUE;
+ pProps->implementedInHardware = IMA_FALSE;
+ pProps->implementedInSoftware = IMA_TRUE;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetLhbaProperties(
+ IMA_OID lhbaOid,
+ IMA_LHBA_PROPERTIES *pProps
+)
+{
+
+ if (pProps == NULL) {
+ return (IMA_ERROR_INVALID_PARAMETER);
+ }
+
+ if (lhbaObjectId.objectSequenceNumber != ISCSI_INITIATOR_OID) {
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+ }
+
+ (void) memset(pProps, 0, sizeof (IMA_LHBA_PROPERTIES));
+ (void) mbstowcs(pProps->osDeviceName, OS_DEVICE_NAME,
+ OS_DEVICE_NAME_LEN);
+ pProps->luExposingSupported = IMA_FALSE;
+ pProps->isDestroyable = IMA_FALSE;
+ pProps->staleDataRemovable = IMA_FALSE;
+ pProps->staleDataSize = 0;
+ pProps->initiatorAuthMethodsSettable = IMA_TRUE;
+ pProps->targetAuthMethodsSettable = IMA_FALSE;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_API IMA_STATUS IMA_GetLnpOidList(
+ IMA_OID_LIST **ppList
+)
+{
+ *ppList = (IMA_OID_LIST *) calloc(1, (sizeof (IMA_OID_LIST)));
+ if (*ppList == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->oidCount = 0;
+
+ return (IMA_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetLnpProperties(
+ IMA_OID lnpOid,
+ IMA_LNP_PROPERTIES *pProps
+)
+{
+ return (IMA_ERROR_OBJECT_NOT_FOUND);
+}
+
+#define IMA_DISK_DEVICE_NAME_PREFIX "/dev/rdsk/"
+#define IMA_TAPE_DEVICE_NAME_PREFIX "/dev/rmt/"
+static int
+get_lun_devlink(di_devlink_t link, void *osDeviceName)
+{
+ if ((strncmp(IMA_DISK_DEVICE_NAME_PREFIX, di_devlink_path(link),
+ strlen(IMA_DISK_DEVICE_NAME_PREFIX)) == 0) ||
+ (strncmp(IMA_TAPE_DEVICE_NAME_PREFIX, di_devlink_path(link),
+ strlen(IMA_TAPE_DEVICE_NAME_PREFIX)) == 0)) {
+ (void) mbstowcs((wchar_t *)osDeviceName, di_devlink_path(link),
+ MAXPATHLEN);
+ return (DI_WALK_TERMINATE);
+ }
+
+ return (DI_WALK_CONTINUE);
+}
+
+/* ARGSUSED */
+IMA_API IMA_STATUS IMA_GetPluginProperties(
+ IMA_OID pluginOid,
+ IMA_PLUGIN_PROPERTIES *pProps
+)
+{
+ pProps->supportedImaVersion = 1;
+ libSwprintf(pProps->vendor, L"%ls", LIBRARY_PROPERTY_VENDOR);
+ libSwprintf(pProps->implementationVersion, L"%ls",
+ LIBRARY_PROPERTY_IMPLEMENTATION_VERSION);
+ libSwprintf(pProps->fileName, L"%ls", LIBRARY_FILE_NAME);
+ GetBuildTime(&(pProps->buildTime));
+ pProps->lhbasCanBeCreatedAndDestroyed = IMA_FALSE;
+ return (IMA_STATUS_SUCCESS);
+}
+
+IMA_STATUS getDiscoveryAddressPropertiesList(
+ SUN_IMA_DISC_ADDR_PROP_LIST **ppList
+)
+{
+ int fd;
+ int i;
+ int discovery_addr_list_size;
+ iscsi_addr_list_t *ialp, al_info;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ (void) memset(&al_info, 0, sizeof (al_info));
+ al_info.al_vers = ISCSI_INTERFACE_VERSION;
+ al_info.al_in_cnt = 0;
+
+ /*
+ * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl to obtain the number of
+ * discovery addresses.
+ */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d",
+ errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ discovery_addr_list_size = sizeof (iscsi_addr_list_t);
+ if (al_info.al_out_cnt > 1) {
+ discovery_addr_list_size += (sizeof (iscsi_addr_t) *
+ al_info.al_out_cnt - 1);
+ }
+
+ ialp = (iscsi_addr_list_t *)calloc(1, discovery_addr_list_size);
+ if (ialp == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ ialp->al_vers = ISCSI_INTERFACE_VERSION;
+ ialp->al_in_cnt = al_info.al_out_cnt;
+
+ /*
+ * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl again to obtain the
+ * discovery addresses.
+ */
+ if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) {
+ free(ialp);
+ (void) close(fd);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d",
+ errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ *ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)
+ calloc(1, sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) +
+ ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES));
+
+ if (*ppList == NULL) {
+ free(ialp);
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ (*ppList)->discAddrCount = ialp->al_out_cnt;
+
+ for (i = 0; i < ialp->al_out_cnt; i++) {
+ if (ialp->al_addrs[i].a_addr.i_insize ==
+ sizeof (struct in_addr)) {
+ (*ppList)->props[i].discoveryAddress.hostnameIpAddress.
+ id.ipAddress.ipv4Address = IMA_TRUE;
+ } else if (ialp->al_addrs[i].a_addr.i_insize ==
+ sizeof (struct in6_addr)) {
+ (*ppList)->props[i].discoveryAddress.
+ hostnameIpAddress.id.ipAddress.ipv4Address = IMA_FALSE;
+ } else {
+ /* Should not happen */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ bcopy(&ialp->al_addrs[i].a_addr.i_addr, (*ppList)->props[i].
+ discoveryAddress.hostnameIpAddress.id.ipAddress.ipAddress,
+ sizeof ((*ppList)->props[i].discoveryAddress.
+ hostnameIpAddress.id.ipAddress.ipAddress));
+
+ (*ppList)->props[i].discoveryAddress.portNumber =
+ ialp->al_addrs[i].a_port;
+ }
+
+ free(ialp);
+ (void) close(fd);
+ return (IMA_STATUS_SUCCESS);
+}
+
+
+/* ARGSUSED */
+IMA_STATUS sendTargets(
+ IMA_TARGET_ADDRESS address,
+ SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
+)
+{
+ char *colonPos;
+ char discAddrStr[SUN_IMA_IP_ADDRESS_LEN];
+ int fd;
+ int ctr;
+ int stl_sz;
+ iscsi_sendtgts_list_t *stl_hdr = NULL;
+ IMA_BOOL retry = IMA_TRUE;
+
+#define SENDTGTS_DEFAULT_NUM_TARGETS 10
+
+ stl_sz = sizeof (*stl_hdr) + ((SENDTGTS_DEFAULT_NUM_TARGETS - 1) *
+ sizeof (iscsi_sendtgts_entry_t));
+ stl_hdr = (iscsi_sendtgts_list_t *)calloc(1, stl_sz);
+ if (stl_hdr == NULL) {
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
+ stl_hdr->stl_in_cnt = SENDTGTS_DEFAULT_NUM_TARGETS;
+
+ colonPos = strchr(discAddrStr, ':');
+ if (colonPos == NULL) {
+ /* IPv4 */
+ stl_hdr->stl_entry.e_insize = sizeof (struct in_addr);
+ } else {
+ /* IPv6 */
+ stl_hdr->stl_entry.e_insize = sizeof (struct in6_addr);
+ }
+
+
+ bcopy(address.hostnameIpAddress.id.ipAddress.ipAddress,
+ &stl_hdr->stl_entry.e_u,
+ sizeof (address.hostnameIpAddress.id.ipAddress.ipAddress));
+ stl_hdr->stl_entry.e_port = address.portNumber;
+
+ if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
+ syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
+ ISCSI_DRIVER_DEVCTL, errno);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+retry_sendtgts:
+ /*
+ * Issue ioctl to obtain the SendTargets list
+ */
+ if (ioctl(fd, ISCSI_SENDTGTS_GET, stl_hdr) != 0) {
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_SENDTGTS_GET ioctl failed, errno: %d", errno);
+ (void) close(fd);
+ free(stl_hdr);
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+ /* check if all targets received */
+ if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
+ if (retry == IMA_TRUE) {
+ stl_sz = sizeof (*stl_hdr) +
+ ((stl_hdr->stl_out_cnt - 1) *
+ sizeof (iscsi_sendtgts_entry_t));
+ stl_hdr = (iscsi_sendtgts_list_t *)
+ realloc(stl_hdr, stl_sz);
+ if (stl_hdr == NULL) {
+ (void) close(fd);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+ stl_hdr->stl_in_cnt = stl_hdr->stl_out_cnt;
+ retry = IMA_FALSE;
+ goto retry_sendtgts;
+ } else {
+ /*
+ * don't retry after 2 attempts. The target list
+ * shouldn't continue to growing. Justs continue
+ * on and display what was found.
+ */
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_SENDTGTS_GET overflow: "
+ "failed to obtain all targets");
+ stl_hdr->stl_out_cnt = stl_hdr->stl_in_cnt;
+ }
+ }
+
+ (void) close(fd);
+
+ /* allocate for caller return buffer */
+ *ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1,
+ sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) +
+ stl_hdr->stl_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
+ if (*ppList == NULL) {
+ free(stl_hdr);
+ return (IMA_ERROR_INSUFFICIENT_MEMORY);
+ }
+
+ (*ppList)->keyCount = stl_hdr->stl_out_cnt;
+
+ for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
+ (void) mbstowcs((*ppList)->keys[ctr].name,
+ (char *)stl_hdr->stl_list[ctr].ste_name,
+ IMA_NODE_NAME_LEN);
+
+ (*ppList)->keys[ctr].tpgt = stl_hdr->stl_list[ctr].ste_tpgt;
+
+ (*ppList)->keys[ctr].address.portNumber =
+ stl_hdr->stl_list[ctr].ste_ipaddr.a_port;
+
+ if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
+ sizeof (struct in_addr)) {
+ (*ppList)->keys[ctr].address.ipAddress.ipv4Address =
+ IMA_TRUE;
+ } else if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
+ sizeof (struct in6_addr)) {
+ (*ppList)->keys[ctr].address.ipAddress.ipv4Address =
+ IMA_FALSE;
+ } else {
+ free(stl_hdr);
+ syslog(LOG_USER|LOG_DEBUG,
+ "ISCSI_STATIC_GET returned bad address");
+ return (IMA_ERROR_UNEXPECTED_OS_ERROR);
+ }
+
+
+ (void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
+ &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
+ stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize);
+ }
+ free(stl_hdr);
+
+ return (IMA_STATUS_SUCCESS);
+}