diff options
| author | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
|---|---|---|
| committer | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
| commit | fcf3ce441efd61da9bb2884968af01cb7c1452cc (patch) | |
| tree | 0e80d59ad41702571586195bf099ccc14222ce02 /usr/src/lib/libsun_ima/common/ima.c | |
| parent | 247b82a1f1cb5ebd2d163bd9afdb1a3065611962 (diff) | |
| download | illumos-joyent-fcf3ce441efd61da9bb2884968af01cb7c1452cc.tar.gz | |
6745433 Merge NWS consolidation into OS/Net consolidation
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); +} | 
