diff options
Diffstat (limited to 'usr/src/lib/libsun_ima/common/ima.c')
| -rw-r--r-- | usr/src/lib/libsun_ima/common/ima.c | 3212 |
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); +} |
