/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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 #define MAX_LONG_LONG_STRING_LEN 10 #define MAX_INQUIRY_BUFFER_LEN 0xffff #define MAX_REPORT_LUNS_BUFFER_LEN 0xffffffff #define MAX_READ_CAPACITY16_BUFFER_LEN 0xffffffff /* 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 = '\0'; (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 != '\0') { (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 = '\0'; (void) strlcpy(target_addr_str, tmp_target_str, sizeof (target_addr_str)); /* Extract the port number */ colonPos++; if (*colonPos != '\0') { (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); } 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; unsigned char cmdblk[CDB_GROUP0]; IMA_UINT buflen; int fd; iscsi_uscsi_t uscsi; (void) memset(&cmdblk[0], 0, CDB_GROUP0); cmdblk[0] = SCMD_INQUIRY; if (evpd == IMA_TRUE) cmdblk[1] |= 0x01; if (cmddt == IMA_TRUE) cmdblk[1] |= 0x02; cmdblk[2] = pageCode; if (*pOutputBufferLength > MAX_INQUIRY_BUFFER_LEN) { buflen = MAX_INQUIRY_BUFFER_LEN; } else { buflen = *pOutputBufferLength; } cmdblk[3] = (buflen & 0xff00) >> 8; cmdblk[4] = (buflen & 0x00ff); (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 = buflen; uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer; uscsi.iu_ucmd.uscsi_rqlen = (pSenseBufferLength != NULL) ? *pSenseBufferLength : 0; uscsi.iu_ucmd.uscsi_cdb = (char *)&cmdblk[0]; uscsi.iu_ucmd.uscsi_cdblen = CDB_GROUP0; 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); } if (uscsi.iu_ucmd.uscsi_status == STATUS_CHECK) { if (pSenseBufferLength != NULL) { *pSenseBufferLength -= uscsi.iu_ucmd.uscsi_rqresid; } return (IMA_ERROR_SCSI_STATUS_CHECK_CONDITION); } *pOutputBufferLength = buflen - uscsi.iu_ucmd.uscsi_resid; return (IMA_STATUS_SUCCESS); } 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; /* CDB_GROUP4 size is safe for both 10 and 16 byte CDBs */ unsigned char cmdblk[CDB_GROUP4]; IMA_UINT buflen; int fd; iscsi_uscsi_t uscsi; (void) memset(&cmdblk[0], 0, CDB_GROUP4); if (cdbLength == CDB_GROUP1) { /* Read Capacity (10) command. */ cmdblk[0] = SCMD_READ_CAPACITY; buflen = *pOutputBufferLength; } else if (cdbLength == CDB_GROUP4) { /* * Read Capacity (16) is a Service Action In command. One * command byte (0x9E) is overloaded for multiple operations, * with the second CDB byte specifying the desired operation. */ cmdblk[0] = SCMD_SVC_ACTION_IN_G4; cmdblk[1] = SSVC_ACTION_READ_CAPACITY_G4; if (*pOutputBufferLength > MAX_READ_CAPACITY16_BUFFER_LEN) { buflen = MAX_READ_CAPACITY16_BUFFER_LEN; } else { buflen = *pOutputBufferLength; } cmdblk[10] = (buflen & 0xff000000) >> 24; cmdblk[11] = (buflen & 0x00ff0000) >> 16; cmdblk[12] = (buflen & 0x0000ff00) >> 8; cmdblk[13] = (buflen & 0x000000ff); } else { /* only 10 and 16 byte CDB are supported */ return (IMA_ERROR_NOT_SUPPORTED); } (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 = buflen; uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer; uscsi.iu_ucmd.uscsi_rqlen = (pSenseBufferLength != NULL) ? *pSenseBufferLength : 0; uscsi.iu_ucmd.uscsi_cdb = (char *)&cmdblk[0]; uscsi.iu_ucmd.uscsi_cdblen = cdbLength; 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); } if (uscsi.iu_ucmd.uscsi_status == STATUS_CHECK) { if (pSenseBufferLength != NULL) { *pSenseBufferLength -= uscsi.iu_ucmd.uscsi_rqresid; } return (IMA_ERROR_SCSI_STATUS_CHECK_CONDITION); } *pOutputBufferLength = buflen - uscsi.iu_ucmd.uscsi_resid; return (IMA_STATUS_SUCCESS); } 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; unsigned char cmdblk[CDB_GROUP5]; IMA_UINT buflen; int fd; iscsi_uscsi_t uscsi; (void) memset(&cmdblk[0], 0, CDB_GROUP5); cmdblk[0] = SCMD_REPORT_LUNS; cmdblk[2] = selectReport; if (*pOutputBufferLength > MAX_REPORT_LUNS_BUFFER_LEN) { buflen = MAX_REPORT_LUNS_BUFFER_LEN; } else { buflen = *pOutputBufferLength; } cmdblk[6] = (buflen & 0xff000000) >> 24; cmdblk[7] = (buflen & 0x00ff0000) >> 16; cmdblk[8] = (buflen & 0x0000ff00) >> 8; cmdblk[9] = (buflen & 0x000000ff); (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) { if (sendToWellKnownLun == IMA_TRUE) { /* this optional feature is not supported now */ return (IMA_ERROR_NOT_SUPPORTED); } 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 = buflen; uscsi.iu_ucmd.uscsi_rqbuf = (char *)pSenseBuffer; uscsi.iu_ucmd.uscsi_rqlen = (pSenseBufferLength != NULL) ? *pSenseBufferLength : 0; uscsi.iu_ucmd.uscsi_cdb = (char *)&cmdblk[0]; uscsi.iu_ucmd.uscsi_cdblen = CDB_GROUP5; 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); } if (uscsi.iu_ucmd.uscsi_status == STATUS_CHECK) { if (pSenseBufferLength != NULL) { *pSenseBufferLength -= uscsi.iu_ucmd.uscsi_rqresid; } return (IMA_ERROR_SCSI_STATUS_CHECK_CONDITION); } *pOutputBufferLength = buflen - uscsi.iu_ucmd.uscsi_resid; 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 == authMethodNone) { 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); } IMA_API IMA_STATUS SUN_IMA_GetTunableProperties( IMA_OID oid, ISCSI_TUNABLE_PARAM *param) { int fd; iscsi_tunable_object_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_tunable_object_t)); pg.t_param = param->tunable_objectType; pg.t_oid = (uint32_t)oid.objectSequenceNumber; if (ioctl(fd, ISCSI_TUNABLE_PARAM_GET, &pg) == -1) { syslog(LOG_USER|LOG_DEBUG, "ISCSI_TUNABLE_PARAM_GET ioctl failed, errno: %d", errno); (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } else { long long value; char tmp[MAX_LONG_LONG_STRING_LEN], *ptr = NULL; if (pg.t_set == B_FALSE) { /* default value */ (void) close(fd); return (IMA_STATUS_SUCCESS); } value = (long long)pg.t_value.v_integer; ptr = lltostr(value, &tmp[MAX_LONG_LONG_STRING_LEN -1]); if ((ptr != NULL) && (ptr != tmp)) { tmp[MAX_LONG_LONG_STRING_LEN - 1] = '\0'; } else { (void) close(fd); return (IMA_ERROR_UNEXPECTED_OS_ERROR); } switch (param->tunable_objectType) { case ISCSI_RX_TIMEOUT_VALUE: (void) strlcpy(param->tunable_objectValue, ptr, strlen(ptr) + 1); break; case ISCSI_CONN_DEFAULT_LOGIN_MAX: (void) strlcpy(param->tunable_objectValue, ptr, strlen(ptr) + 1); break; case ISCSI_LOGIN_POLLING_DELAY: (void) strlcpy(param->tunable_objectValue, ptr, strlen(ptr) + 1); break; default: break; } } (void) close(fd); return (IMA_STATUS_SUCCESS); } IMA_API IMA_STATUS SUN_IMA_SetTunableProperties( IMA_OID oid, ISCSI_TUNABLE_PARAM *param) { int fd; iscsi_tunable_object_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_tunable_object_t)); ps.t_oid = oid.objectSequenceNumber; ps.t_param = param->tunable_objectType; switch (param->tunable_objectType) { long tmp; case ISCSI_RX_TIMEOUT_VALUE: case ISCSI_CONN_DEFAULT_LOGIN_MAX: case ISCSI_LOGIN_POLLING_DELAY: tmp = strtol(param->tunable_objectValue, NULL, 10); if (((tmp == 0) && (errno == EINVAL)) || ((tmp == LONG_MAX) && (errno == ERANGE)) || ((tmp == LONG_MIN) && (errno == ERANGE))) { (void) close(fd); return (IMA_ERROR_INVALID_PARAMETER); } ps.t_value.v_integer = (uint32_t)tmp; break; default: break; } if (ioctl(fd, ISCSI_TUNABLE_PARAM_SET, &ps)) { int tmpErrno = errno; syslog(LOG_USER|LOG_DEBUG, "ISCSI_TUNABLE_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); }