/*
* 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#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 <fcntl.h>
#include <stdio.h>
#include <time.h>
#include <libdevinfo.h>
#include <sys/scsi/adapters/iscsi_if.h>
#include <sys/scsi/adapters/iscsi_door.h>
#include <sys/iscsi_protocol.h>
#include <ima.h>
#include "iscsiadm.h"
#include "sun_ima.h"
#define LIBRARY_PROPERTY_SUPPORTED_IMA_VERSION 1
#define LIBRARY_PROPERTY_IMPLEMENTATION_VERSION L"1.0.0"
#define LIBRARY_PROPERTY_VENDOR L"Sun Microsystems, Inc."
#define DEFAULT_NODE_NAME_FORMAT "iqn.2003-13.com.ima.%s"
#define PLUGIN_OWNER 1
#define MAX_CHAP_SECRET_LEN 16
/* LINTED E_STATIC_UNUSED */
static IMA_INT32 number_of_plugins = -1;
/* LINTED E_STATIC_UNUSED */
static IMA_NODE_NAME sharedNodeName;
/* LINTED E_STATIC_UNUSED */
static IMA_NODE_ALIAS sharedNodeAlias;
/* LINTED E_STATIC_UNUSED */
static IMA_PLUGIN_PROPERTIES PluginProperties;
/* LINTED E_STATIC_UNUSED */
static IMA_OID pluginOid;
static IMA_OID lhbaObjectId;
/* LINTED E_STATIC_UNUSED */
static boolean_t pluginInit = B_FALSE;
/* Forward declaration */
#define BOOL_PARAM 1
#define MIN_MAX_PARAM 2
#define PARAM_OP_OK 0
#define PARAM_OP_FAILED 1
static int open_driver(int *fd);
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 getDigest(IMA_OID oid, int ioctlCmd,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm);
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);
IMA_STATUS getNegotiatedDigest(int digestType,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
SUN_IMA_CONN_PROPERTIES *connProps);
/* 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
static int prepare_discovery_entry(SUN_IMA_TARGET_ADDRESS discoveryAddress,
entry_t *entry);
static int prepare_discovery_entry_IMA(IMA_TARGET_ADDRESS discoveryAddress,
entry_t *entry);
/* LINTED E_STATIC_UNUSED */
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 *arg);
static IMA_STATUS getConnOidList(
IMA_OID *oid,
iscsi_conn_list_t **ppConnList);
static IMA_STATUS getConnProps(
iscsi_if_conn_t *pConn,
iscsi_conn_props_t **ppConnProps);
/* LINTED E_STATIC_UNUSED */
static void libSwprintf(wchar_t *wcs, const wchar_t *lpszFormat, ...)
{
va_list args;
va_start(args, lpszFormat);
(void) vswprintf(wcs, 255, lpszFormat, args);
va_end(args);
}
char *
_strlwr(char *s)
{
char *t = s;
while (t != NULL && *t) {
if (*t >= 'A' && *t <= 'Z')
*t += 32;
t++;
}
return (s);
}
/* LINTED E_STATIC_UNUSED */
static void GetBuildTime(IMA_DATETIME* pdatetime)
{
#if defined(BUILD_DATE)
if (strptime(BUILD_DATE, "%Y/%m/%d %T %Z", pdatetime) == NULL) {
(void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
}
#else
(void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
#endif
}
/*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_GetDiscoveryAddressPropertiesList(
SUN_IMA_DISC_ADDR_PROP_LIST **ppList
)
{
char discovery_addr_str[256];
int fd;
int i;
int discovery_addr_list_size;
int status;
int out_cnt;
iscsi_addr_list_t *ialp;
/* LINTED E_FUNC_SET_NOT_USED */
IMA_IP_ADDRESS *ipAddr;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t));
if (ialp == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
ialp->al_vers = ISCSI_INTERFACE_VERSION;
ialp->al_in_cnt = ialp->al_out_cnt = 1;
/*
* Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl
* We have allocated space for one entry, if more than one
* address is going to be returned, we will re-issue the ioctl
*/
if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 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);
}
if (ialp->al_out_cnt > 1) {
/*
* we need to allocate more space, save off the out_cnt
* and free ialp
*/
out_cnt = ialp->al_out_cnt;
free(ialp);
discovery_addr_list_size = sizeof (iscsi_addr_list_t);
discovery_addr_list_size += (sizeof (iscsi_addr_t) *
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 = out_cnt;
/*
* Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl again to obtain all
* the discovery addresses.
*/
if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) {
#define ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d"
free(ialp);
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
ERROR_STR, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
#undef ERROR_STR
}
}
*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 {
(void) strlcpy(discovery_addr_str, "unknown",
sizeof (discovery_addr_str));
}
ipAddr = &(*ppList)->props[i].discoveryAddress.
hostnameIpAddress.id.ipAddress;
bcopy(&ialp->al_addrs[i].a_addr.i_addr,
(*ppList)->props[i].discoveryAddress.hostnameIpAddress.id.
ipAddress.ipAddress,
sizeof (ipAddr->ipAddress));
(*ppList)->props[i].discoveryAddress.portNumber =
ialp->al_addrs[i].a_port;
}
free(ialp);
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_API IMA_STATUS SUN_IMA_GetStaticTargetProperties(
IMA_OID staticTargetOid,
SUN_IMA_STATIC_TARGET_PROPERTIES *pProps
)
{
int fd;
int status;
iscsi_static_property_t prop;
/* LINTED */
IMA_IP_ADDRESS *ipAddr;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(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 */
pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.
id.ipAddress.ipv4Address = IMA_TRUE;
} else if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
sizeof (struct in6_addr)) {
/* IPv6 */
pProps->staticTarget.targetAddress.imaStruct.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);
}
ipAddr = &pProps->staticTarget.targetAddress.imaStruct.
hostnameIpAddress.id.ipAddress;
bcopy(&prop.p_addr_list.al_addrs[0].a_addr.i_addr,
pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.id.
ipAddress.ipAddress, sizeof (ipAddr->ipAddress));
pProps->staticTarget.targetAddress.imaStruct.portNumber =
prop.p_addr_list.al_addrs[0].a_port;
if (prop.p_addr_list.al_tpgt == (uint32_t)ISCSI_DEFAULT_TPGT) {
pProps->staticTarget.targetAddress.defaultTpgt = IMA_TRUE;
pProps->staticTarget.targetAddress.tpgt = 0;
} else {
pProps->staticTarget.targetAddress.defaultTpgt = IMA_FALSE;
pProps->staticTarget.targetAddress.tpgt =
prop.p_addr_list.al_tpgt;
}
return (IMA_STATUS_SUCCESS);
}
/*ARGSUSED*/
IMA_API IMA_STATUS SUN_IMA_AddStaticTarget(
IMA_OID lhbaOid,
const SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig,
IMA_OID *pTargetOid
)
{
iscsi_target_entry_t target;
int fd;
int target_in_addr_size;
int status;
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.
*/
if (staticConfig.targetAddress.imaStruct.hostnameIpAddress.id.ipAddress.
ipv4Address == IMA_FALSE) {
bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress.
id.ipAddress.ipAddress, &target_in.u_in6,
sizeof (target_in.u_in6));
target_in_addr_size = sizeof (struct in6_addr);
} else {
bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress.
id.ipAddress.ipAddress, &target_in.u_in4,
sizeof (target_in.u_in4));
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;
(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 {
return (IMA_ERROR_INVALID_PARAMETER);
}
target.te_entry.e_port =
staticConfig.targetAddress.imaStruct.portNumber;
if (staticConfig.targetAddress.defaultTpgt == IMA_TRUE) {
target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
} else {
target.te_entry.e_tpgt = staticConfig.targetAddress.tpgt;
}
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
if (ioctl(fd, ISCSI_STATIC_SET, &target)) {
/*
* Encountered problem setting the IP address and port for
* the target just added.
*/
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_STATIC_SET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
pTargetOid->objectType = IMA_OBJECT_TYPE_TARGET;
pTargetOid->ownerId = 1;
pTargetOid->objectSequenceNumber = target.te_entry.e_oid;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_API IMA_STATUS SUN_IMA_GetTargetProperties(
IMA_OID targetId,
SUN_IMA_TARGET_PROPERTIES *pProps
)
{
int fd;
int status;
iscsi_property_t prop;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(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) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) mbstowcs(pProps->imaProps.name,
(char *)prop.p_name, IMA_NODE_NAME_LEN);
(void) memset(pProps->imaProps.alias, 0,
(sizeof (IMA_WCHAR) * SUN_IMA_NODE_ALIAS_LEN));
if (prop.p_alias_len > 0) {
(void) mbstowcs(pProps->imaProps.alias, (char *)prop.p_alias,
SUN_IMA_NODE_ALIAS_LEN);
}
/* Initialize the discovery method to unknown method. */
pProps->imaProps.discoveryMethodFlags =
IMA_TARGET_DISCOVERY_METHOD_UNKNOWN;
if (!((prop.p_discovery & iSCSIDiscoveryMethodStatic) ^
iSCSIDiscoveryMethodStatic)) {
pProps->imaProps.discoveryMethodFlags |=
IMA_TARGET_DISCOVERY_METHOD_STATIC;
}
if (!((prop.p_discovery & iSCSIDiscoveryMethodSLP) ^
iSCSIDiscoveryMethodSLP)) {
pProps->imaProps.discoveryMethodFlags |=
IMA_TARGET_DISCOVERY_METHOD_SLP;
}
if (!((prop.p_discovery & iSCSIDiscoveryMethodISNS) ^
iSCSIDiscoveryMethodISNS)) {
pProps->imaProps.discoveryMethodFlags |=
iSCSIDiscoveryMethodISNS;
}
if (!((prop.p_discovery & iSCSIDiscoveryMethodSendTargets) ^
iSCSIDiscoveryMethodSendTargets)) {
pProps->imaProps.discoveryMethodFlags |=
iSCSIDiscoveryMethodSendTargets;
}
if (prop.p_tpgt_conf == ISCSI_DEFAULT_TPGT) {
pProps->defaultTpgtConf = IMA_TRUE;
pProps->tpgtConf = 0;
} else {
pProps->defaultTpgtConf = IMA_FALSE;
pProps->tpgtConf = prop.p_tpgt_conf;
}
if (prop.p_tpgt_nego == ISCSI_DEFAULT_TPGT) {
pProps->defaultTpgtNego = IMA_TRUE;
pProps->tpgtNego = 0;
} else {
pProps->defaultTpgtNego = IMA_FALSE;
pProps->tpgtNego = prop.p_tpgt_nego;
}
bcopy(prop.p_isid, pProps->isid, ISCSI_ISID_LEN);
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
/*
* This function only sets CHAP params since we only support CHAP for now.
*/
IMA_STATUS SUN_IMA_SetTargetAuthParams(
IMA_OID targetOid,
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 ((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)targetOid.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 (ioctl(fd, ISCSI_CHAP_SET, &chap_p) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_CHAP_SET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetTargetAuthMethods(
IMA_OID lhbaOid,
IMA_OID targetOid,
IMA_UINT *pMethodCount,
IMA_AUTHMETHOD *pMethodList
)
{
if (getAuthMethods(targetOid, pMethodCount, pMethodList)
!= IMA_STATUS_SUCCESS) {
return (getAuthMethods(lhbaOid, pMethodCount, pMethodList));
}
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_SetInitiatorRadiusConfig(
IMA_OID lhbaOid,
SUN_IMA_RADIUS_CONFIG *config
)
{
int af;
int fd;
int status;
iscsi_radius_props_t radius;
union {
struct in_addr u_in4;
struct in6_addr u_in6;
} radius_in;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
radius.r_vers = ISCSI_INTERFACE_VERSION;
radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
/* Get first because other data fields may already exist */
if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
/* EMPTY */
/* It's fine if other data fields are not there. */
}
if (config->isIpv6 == IMA_TRUE) {
af = AF_INET6;
} else {
af = AF_INET;
}
if (inet_pton(af, config->hostnameIpAddress, &radius_in.u_in4) != 1) {
return (IMA_ERROR_INVALID_PARAMETER);
}
switch (af) {
case AF_INET:
radius.r_addr.u_in4.s_addr = radius_in.u_in4.s_addr;
radius.r_insize = sizeof (struct in_addr);
break;
case AF_INET6:
(void) memcpy(radius.r_addr.u_in6.s6_addr,
radius_in.u_in6.s6_addr, 16);
radius.r_insize = sizeof (struct in6_addr);
break;
}
radius.r_port = config->port;
radius.r_radius_config_valid = B_TRUE;
/* Allow resetting the RADIUS shared secret to NULL */
if (config->sharedSecretValid == IMA_TRUE) {
radius.r_shared_secret_len = config->sharedSecretLength;
(void) memset(&radius.r_shared_secret[0], 0,
MAX_RAD_SHARED_SECRET_LEN);
(void) memcpy(&radius.r_shared_secret[0], config->sharedSecret,
config->sharedSecretLength);
}
if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_RADIUS_SET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetInitiatorRadiusConfig(
IMA_OID lhbaOid,
SUN_IMA_RADIUS_CONFIG *config
)
{
int af;
int fd;
int status;
iscsi_radius_props_t radius;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
radius.r_vers = ISCSI_INTERFACE_VERSION;
radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) memset(config, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
if (radius.r_insize == sizeof (struct in_addr)) {
/* IPv4 */
af = AF_INET;
} else if (radius.r_insize == sizeof (struct in6_addr)) {
/* IPv6 */
af = AF_INET6;
} else {
/*
* It's legitimate that the existing RADIUS record does not
* have configuration data.
*/
config->hostnameIpAddress[0] = '\0';
config->port = 0;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
(void) inet_ntop(af, (void *)&radius.r_addr.u_in4,
config->hostnameIpAddress, 256);
config->port = radius.r_port;
(void) memcpy(config->sharedSecret, &radius.r_shared_secret[0],
radius.r_shared_secret_len);
config->sharedSecretLength = radius.r_shared_secret_len;
config->sharedSecretValid = B_TRUE;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_SetInitiatorRadiusAccess(
IMA_OID lhbaOid,
IMA_BOOL radiusAccess
)
{
int fd;
int status;
iscsi_radius_props_t radius;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
radius.r_vers = ISCSI_INTERFACE_VERSION;
radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
/* Get first because other data fields may already exist */
if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
if (radiusAccess == IMA_TRUE) {
/*
* Cannot enable RADIUS if no RADIUS configuration
* can be found.
*/
syslog(LOG_USER|LOG_DEBUG,
"RADIUS config data not found - "
"cannot enable RADIUS, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
} else {
/* EMPTY */
/* Otherwise it's fine to disable RADIUS */
}
}
if ((radius.r_insize != sizeof (struct in_addr)) &&
(radius.r_insize != sizeof (struct in6_addr))) {
/*
* Cannot enable RADIUS if no RADIUS configuration
* can be found.
*/
if (radiusAccess == IMA_TRUE) {
syslog(LOG_USER|LOG_DEBUG,
"RADIUS config data not found - "
"cannot enable RADIUS");
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
}
radius.r_radius_access = (radiusAccess == IMA_TRUE) ?
B_TRUE : B_FALSE;
if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_RADIUS_SET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetInitiatorRadiusAccess(
IMA_OID lhbaOid,
IMA_BOOL *radiusAccess
)
{
int fd;
int status;
iscsi_radius_props_t radius;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
radius.r_vers = ISCSI_INTERFACE_VERSION;
radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
(void) close(fd);
if (errno == ENOENT) {
return (IMA_ERROR_OBJECT_NOT_FOUND);
} else {
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
}
*radiusAccess = (radius.r_radius_access == B_TRUE) ?
IMA_TRUE : IMA_FALSE;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_SendTargets(
IMA_NODE_NAME nodeName,
IMA_TARGET_ADDRESS address,
SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
)
{
char *colonPos;
char discAddrStr[256];
char nodeNameStr[ISCSI_MAX_NAME_LEN];
int fd;
int ctr;
int stl_sz;
int status;
iscsi_sendtgts_list_t *stl_hdr = NULL;
IMA_BOOL retry = IMA_TRUE;
/* LINTED */
IMA_IP_ADDRESS *ipAddr;
#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;
(void) wcstombs(nodeNameStr, nodeName, ISCSI_MAX_NAME_LEN);
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);
}
ipAddr = &address.hostnameIpAddress.id.ipAddress;
bcopy(address.hostnameIpAddress.id.ipAddress.ipAddress,
&stl_hdr->stl_entry.e_u, sizeof (ipAddr->ipAddress));
stl_hdr->stl_entry.e_port = address.portNumber;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
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);
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_STATUS SUN_IMA_SetTargetBidirAuthFlag(
IMA_OID targetOid,
IMA_BOOL *bidirAuthFlag
)
{
int fd;
int status;
iscsi_auth_props_t auth;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
auth.a_vers = ISCSI_INTERFACE_VERSION;
auth.a_oid = (uint32_t)targetOid.objectSequenceNumber;
/* Get first because other data fields may already exist */
if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
/* EMPTY */
/* It is fine if there is no other data fields. */
}
auth.a_bi_auth = (*bidirAuthFlag == IMA_TRUE) ? B_TRUE : B_FALSE;
if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_AUTH_SET ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetTargetBidirAuthFlag(
IMA_OID targetOid,
IMA_BOOL *bidirAuthFlag
)
{
int fd;
int status;
iscsi_auth_props_t auth;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
auth.a_vers = ISCSI_INTERFACE_VERSION;
auth.a_oid = (uint32_t)targetOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
*bidirAuthFlag = (auth.a_bi_auth == B_TRUE) ?
IMA_TRUE : IMA_FALSE;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_CreateTargetOid(
IMA_NODE_NAME targetName,
IMA_OID *targetOid
)
{
int fd;
int status;
iscsi_oid_t oid;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&oid, 0, sizeof (iscsi_oid_t));
(void) wcstombs((char *)oid.o_name, targetName, ISCSI_MAX_NAME_LEN);
oid.o_tpgt = ISCSI_DEFAULT_TPGT;
oid.o_vers = ISCSI_INTERFACE_VERSION;
if (ioctl(fd, ISCSI_CREATE_OID, &oid) == -1) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_CREATE_OID ioctl failed, errno: %d", errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
targetOid->objectType = IMA_OBJECT_TYPE_TARGET;
targetOid->ownerId = 1;
targetOid->objectSequenceNumber = oid.o_oid;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_RemoveTargetParam(
IMA_OID targetOid
)
{
entry_t entry;
int fd;
int status;
iscsi_auth_props_t auth_p;
iscsi_chap_props_t chap_p;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&entry, 0, sizeof (entry_t));
entry.e_vers = ISCSI_INTERFACE_VERSION;
entry.e_oid = (uint32_t)targetOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_TARGET_PARAM_CLEAR, &entry)) {
/*
* It could be that the target exists but the associated
* target_param does not, and that is legitimate.
*/
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_TARGET_PARAM_CLEAR ioctl failed, errno: %d", errno);
}
/* Issue ISCSI_CHAP_CLEAR ioctl */
(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
chap_p.c_vers = ISCSI_INTERFACE_VERSION;
chap_p.c_oid = (uint32_t)targetOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_CHAP_CLEAR, &chap_p) != 0) {
/*
* It could be that the CHAP of this target has never
* been set.
*/
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_CHAP_CLEAR ioctl failed, errno: %d", errno);
}
/*
* Issue ISCSI_AUTH_CLEAR ioctl, in which the authentication information
* is removed and the target that is not discovered by initiator
* is removed from the memory. So this ioctl should be called at last
*/
(void) memset(&auth_p, 0, sizeof (iscsi_auth_props_t));
auth_p.a_vers = ISCSI_INTERFACE_VERSION;
auth_p.a_oid = (uint32_t)targetOid.objectSequenceNumber;
if (ioctl(fd, ISCSI_AUTH_CLEAR, &auth_p) != 0) {
/*
* It could be that the auth data of this target has
* never been set.
*/
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_API IMA_STATUS SUN_IMA_SetHeaderDigest(
IMA_OID oid,
IMA_UINT algorithmCount,
const SUN_IMA_DIGEST_ALGORITHM *algorithmList
)
{
IMA_MIN_MAX_VALUE mv;
uint32_t digest_algorithm;
/* We only support one preference of digest algorithm. */
if (algorithmCount > 1) {
syslog(LOG_USER|LOG_DEBUG,
"More than one digest algorithm specified.");
return (IMA_ERROR_NOT_SUPPORTED);
}
switch (algorithmList[0]) {
case SUN_IMA_DIGEST_NONE:
digest_algorithm = ISCSI_DIGEST_NONE;
break;
case SUN_IMA_DIGEST_CRC32:
digest_algorithm = ISCSI_DIGEST_CRC32C;
break;
default:
digest_algorithm = ISCSI_DIGEST_NONE;
break;
}
mv.currentValue = digest_algorithm;
return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
ISCSI_LOGIN_PARAM_HEADER_DIGEST));
}
IMA_API IMA_STATUS SUN_IMA_SetDataDigest(
IMA_OID oid,
IMA_UINT algorithmCount,
const SUN_IMA_DIGEST_ALGORITHM *algorithmList
)
{
IMA_MIN_MAX_VALUE mv;
uint32_t digest_algorithm;
/* We only support one preference of digest algorithm. */
if (algorithmCount > 1) {
syslog(LOG_USER|LOG_DEBUG,
"More than one digest algorithm specified.");
return (IMA_ERROR_NOT_SUPPORTED);
}
switch (algorithmList[0]) {
case SUN_IMA_DIGEST_NONE:
digest_algorithm = ISCSI_DIGEST_NONE;
break;
case SUN_IMA_DIGEST_CRC32:
digest_algorithm = ISCSI_DIGEST_CRC32C;
break;
default:
digest_algorithm = ISCSI_DIGEST_NONE;
break;
}
mv.currentValue = digest_algorithm;
return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
ISCSI_LOGIN_PARAM_DATA_DIGEST));
}
IMA_API IMA_STATUS SUN_IMA_GetHeaderDigest(
IMA_OID oid,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
)
{
return (getDigest(oid, ISCSI_LOGIN_PARAM_HEADER_DIGEST, algorithm));
}
IMA_API IMA_STATUS SUN_IMA_GetDataDigest(
IMA_OID oid,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
)
{
return (getDigest(oid, ISCSI_LOGIN_PARAM_DATA_DIGEST, algorithm));
}
typedef struct walk_devlink {
char *path;
size_t len;
char **linkpp;
} walk_devlink_t;
IMA_STATUS SUN_IMA_GetLuProperties(
IMA_OID luId,
SUN_IMA_LU_PROPERTIES *pProps
)
{
IMA_STATUS status;
iscsi_lun_list_t *pLunList;
int j;
IMA_BOOL lunMatch = IMA_FALSE;
int fd;
int openStatus;
iscsi_lun_props_t lun;
di_devlink_handle_t hdl;
walk_devlink_t warg;
char *minor_path, *devlinkp, lunpath[MAXPATHLEN];
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 ((openStatus = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | openStatus);
}
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->imaProps.associatedTargetOid.objectType =
IMA_OBJECT_TYPE_TARGET;
pProps->imaProps.associatedTargetOid.ownerId = 1;
pProps->imaProps.associatedTargetOid.objectSequenceNumber = lun.lp_oid;
pProps->imaProps.targetLun = (IMA_UINT64)lun.lp_num;
(void) strncpy(pProps->vendorId, lun.lp_vid, SUN_IMA_LU_VENDOR_ID_LEN);
(void) strncpy(pProps->productId, lun.lp_pid,
SUN_IMA_LU_PRODUCT_ID_LEN);
/*
* lun.lp_status is defined as
* LunValid = 0
* LunDoesNotExist = 1
* IMA_LU_PROPS.exposedtoOS is defined as an IMA_BOOL
* IMA_TRUE = 1
* IMA_FALSE = 0
*/
pProps->imaProps.exposedToOs = !lun.lp_status;
if (gmtime_r(&lun.lp_time_online, &pProps->imaProps.timeExposedToOs)
== NULL) {
(void) memset(&pProps->imaProps.timeExposedToOs, 0,
sizeof (pProps->imaProps.timeExposedToOs));
}
if (lun.lp_status == LunValid) {
if ((strlen(lun.lp_pathname) + strlen("/devices")) >
(MAXPATHLEN -1)) {
/*
* lun.lp_pathname length too long
*/
pProps->imaProps.osDeviceNameValid = IMA_FALSE;
pProps->imaProps.osParallelIdsValid = IMA_FALSE;
return (IMA_STATUS_SUCCESS);
}
if ((strstr(lun.lp_pathname, "st@") != NULL) ||
(strstr(lun.lp_pathname, "tape@") != NULL)) {
(void) strlcat(lun.lp_pathname, ":n", MAXPATHLEN);
} else 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) strlcat(lun.lp_pathname, ":c,raw", MAXPATHLEN);
} else if ((strstr(lun.lp_pathname, "ses@") != NULL) ||
(strstr(lun.lp_pathname, "enclosure@") != NULL)) {
(void) strlcat(lun.lp_pathname, ":0", MAXPATHLEN);
}
(void) snprintf(lunpath, sizeof (lun.lp_pathname),
"/devices%s", lun.lp_pathname);
if (strchr(lunpath, ':')) {
minor_path = lunpath;
if (strstr(minor_path, "/devices") != NULL) {
minor_path = lunpath +
strlen("/devices");
} else {
minor_path = lunpath;
}
warg.path = NULL;
} else {
minor_path = NULL;
warg.len = strlen(lunpath);
warg.path = lunpath;
}
devlinkp = NULL;
warg.linkpp = &devlinkp;
/*
* 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->imaProps.osDeviceName[0] = L'\0';
(void) di_devlink_walk(hdl, NULL, minor_path,
DI_PRIMARY_LINK, (void *)&warg, get_lun_devlink);
if (devlinkp != NULL) {
(void) mbstowcs(pProps->imaProps.osDeviceName,
devlinkp, MAXPATHLEN);
free(devlinkp);
pProps->imaProps.osDeviceNameValid = IMA_TRUE;
} else {
/* OS device name is asynchronously made */
pProps->imaProps.osDeviceNameValid = IMA_FALSE;
}
(void) di_devlink_fini(&hdl);
} else {
pProps->imaProps.osDeviceNameValid = IMA_FALSE;
}
} else {
pProps->imaProps.osDeviceNameValid = IMA_FALSE;
}
pProps->imaProps.osParallelIdsValid = IMA_FALSE;
return (IMA_STATUS_SUCCESS);
}
static int
get_lun_devlink(di_devlink_t link, void *arg)
{
walk_devlink_t *warg = (walk_devlink_t *)arg;
if (warg->path) {
char *content = (char *)di_devlink_content(link);
char *start = strstr(content, "/devices");
if (start == NULL ||
strncmp(start, warg->path, warg->len) != 0 ||
start[warg->len] != ':')
return (DI_WALK_CONTINUE);
}
*(warg->linkpp) = strdup(di_devlink_path(link));
return (DI_WALK_TERMINATE);
}
/*
* SUN_IMA_GetConnectionOidList -
*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_GetConnOidList(
IMA_OID *oid,
IMA_OID_LIST **ppList
)
{
IMA_STATUS imaStatus;
IMA_OID_LIST *imaOidList;
iscsi_conn_list_t *iscsiConnList = NULL;
int i;
size_t allocLen;
if ((lhbaObjectId.objectType == oid->objectType) &&
(lhbaObjectId.ownerId == oid->ownerId) &&
(lhbaObjectId.objectSequenceNumber == oid->objectSequenceNumber)) {
imaStatus = getConnOidList(NULL, &iscsiConnList);
} else {
if (oid->objectType == IMA_OBJECT_TYPE_TARGET) {
imaStatus = getConnOidList(oid, &iscsiConnList);
} else {
return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
}
}
if (imaStatus != IMA_STATUS_SUCCESS) {
return (imaStatus);
}
/*
* Based on the results a SUN_IMA_CONN_LIST structure is allocated.
*/
allocLen = iscsiConnList->cl_out_cnt * sizeof (IMA_OID);
allocLen += sizeof (IMA_OID_LIST) - sizeof (IMA_OID);
imaOidList = (IMA_OID_LIST *)calloc(1, allocLen);
if (imaOidList == NULL) {
free(iscsiConnList);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
/* The data is transfered from iscsiConnList to imaConnList. */
imaOidList->oidCount = iscsiConnList->cl_out_cnt;
for (i = 0; i < iscsiConnList->cl_out_cnt; i++) {
imaOidList->oids[i].objectType = SUN_IMA_OBJECT_TYPE_CONN;
imaOidList->oids[i].ownerId = 1;
imaOidList->oids[i].objectSequenceNumber =
iscsiConnList->cl_list[i].c_oid;
}
/* The pointer to the SUN_IMA_CONN_LIST structure is returned. */
*ppList = imaOidList;
free(iscsiConnList);
return (IMA_STATUS_SUCCESS);
}
/*
* SUN_IMA_GetConnProperties -
*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_GetConnProperties(
IMA_OID *connOid,
SUN_IMA_CONN_PROPERTIES **pProps
)
{
iscsi_conn_list_t *pConnList;
iscsi_conn_props_t *pConnProps;
/* LINTED */
struct sockaddr_in6 *addrIn6;
/* LINTED */
struct sockaddr_in *addrIn;
SUN_IMA_CONN_PROPERTIES *pImaConnProps;
IMA_STATUS imaStatus;
int i;
/* If there is any error *pProps should be set to NULL */
*pProps = NULL;
pImaConnProps = (SUN_IMA_CONN_PROPERTIES *)calloc(1,
sizeof (SUN_IMA_CONN_PROPERTIES));
if (pImaConnProps == NULL) {
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
imaStatus = getConnOidList(NULL, &pConnList);
if (imaStatus != IMA_STATUS_SUCCESS) {
free(pImaConnProps);
return (imaStatus);
}
/*
* Walk the list returned to find our connection.
*/
for (i = 0; i < pConnList->cl_out_cnt; i++) {
if (pConnList->cl_list[i].c_oid ==
(uint32_t)connOid->objectSequenceNumber) {
/* This is our connection. */
imaStatus = getConnProps(&pConnList->cl_list[i],
&pConnProps);
if (imaStatus != IMA_STATUS_SUCCESS) {
free(pConnList);
free(pImaConnProps);
return (imaStatus);
}
pImaConnProps->connectionID = pConnProps->cp_cid;
/*
* Local Propeties
*/
if (pConnProps->cp_local.soa4.sin_family == AF_INET) {
pImaConnProps->local.ipAddress.ipv4Address =
IMA_TRUE;
pImaConnProps->local.portNumber =
pConnProps->cp_local.soa4.sin_port;
addrIn = &(pConnProps->cp_local.soa4);
bcopy(&pConnProps->cp_local.soa4.sin_addr,
pImaConnProps->local.ipAddress.ipAddress,
sizeof (addrIn->sin_addr));
} else {
pImaConnProps->local.ipAddress.ipv4Address =
IMA_FALSE;
pImaConnProps->local.portNumber =
pConnProps->cp_local.soa6.sin6_port;
addrIn6 = &(pConnProps->cp_local.soa6);
bcopy(&pConnProps->cp_local.soa6.sin6_addr,
pImaConnProps->local.ipAddress.ipAddress,
sizeof (addrIn6->sin6_addr));
}
/*
* Peer Propeties
*/
if (pConnProps->cp_peer.soa4.sin_family == AF_INET) {
pImaConnProps->peer.ipAddress.ipv4Address =
IMA_TRUE;
pImaConnProps->peer.portNumber =
pConnProps->cp_peer.soa4.sin_port;
addrIn = &(pConnProps->cp_local.soa4);
bcopy(&pConnProps->cp_peer.soa4.sin_addr,
pImaConnProps->peer.ipAddress.ipAddress,
sizeof (addrIn->sin_addr));
} else {
pImaConnProps->peer.ipAddress.ipv4Address =
IMA_FALSE;
pImaConnProps->peer.portNumber =
pConnProps->cp_peer.soa6.sin6_port;
addrIn6 = &pConnProps->cp_local.soa6;
bcopy(&pConnProps->cp_peer.soa6.sin6_addr,
pImaConnProps->peer.ipAddress.ipAddress,
sizeof (addrIn6->sin6_addr));
}
pImaConnProps->valuesValid =
pConnProps->cp_params_valid;
pImaConnProps->defaultTime2Retain =
pConnProps->cp_params.default_time_to_retain;
pImaConnProps->defaultTime2Wait =
pConnProps->cp_params.default_time_to_wait;
pImaConnProps->errorRecoveryLevel =
pConnProps->cp_params.error_recovery_level;
pImaConnProps->firstBurstLength =
pConnProps->cp_params.first_burst_length;
pImaConnProps->maxBurstLength =
pConnProps->cp_params.max_burst_length;
pImaConnProps->maxConnections =
pConnProps->cp_params.max_connections;
pImaConnProps->maxOutstandingR2T =
pConnProps->cp_params.max_outstanding_r2t;
pImaConnProps->maxRecvDataSegmentLength =
pConnProps->cp_params.max_recv_data_seg_len;
pImaConnProps->dataPduInOrder =
pConnProps->cp_params.data_pdu_in_order;
pImaConnProps->dataSequenceInOrder =
pConnProps->cp_params.data_sequence_in_order;
pImaConnProps->immediateData =
pConnProps->cp_params.immediate_data;
pImaConnProps->initialR2T =
pConnProps->cp_params.initial_r2t;
pImaConnProps->headerDigest =
pConnProps->cp_params.header_digest;
pImaConnProps->dataDigest =
pConnProps->cp_params.data_digest;
free(pConnProps);
break;
}
}
free(pConnList);
*pProps = pImaConnProps;
return (IMA_STATUS_SUCCESS);
}
/*
* SUN_IMA_GetConfigSessions -
*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_GetConfigSessions(
IMA_OID targetOid,
SUN_IMA_CONFIG_SESSIONS **pConfigSessions
)
{
int fd;
int status;
iscsi_config_sess_t *ics;
int size, idx;
/* Allocate and setup initial buffer */
size = sizeof (*ics);
ics = (iscsi_config_sess_t *)calloc(1, size);
if (ics == NULL) {
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
ics->ics_ver = ISCSI_INTERFACE_VERSION;
ics->ics_oid = targetOid.objectSequenceNumber;
ics->ics_in = 1;
/* Open driver devctl for ioctl */
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
/* Issue ioctl request */
if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
errno);
(void) close(fd);
free(ics);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
/* Check if we need to collect more information */
idx = ics->ics_out;
if (idx > 1) {
/* Free old buffer and reallocate re-sized buffer */
free(ics);
size = ISCSI_SESSION_CONFIG_SIZE(idx);
ics = (iscsi_config_sess_t *)calloc(1, size);
if (ics == NULL) {
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
ics->ics_ver = ISCSI_INTERFACE_VERSION;
ics->ics_oid = targetOid.objectSequenceNumber;
ics->ics_in = idx;
/* Issue ioctl request */
if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
errno);
(void) close(fd);
free(ics);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
}
(void) close(fd);
/* Allocate output buffer */
size = sizeof (SUN_IMA_CONFIG_SESSIONS) +
((ics->ics_out - 1) * sizeof (IMA_ADDRESS_KEY));
*pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
if ((*pConfigSessions) == NULL) {
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
/* Copy output information */
(*pConfigSessions)->bound =
(ics->ics_bound == B_TRUE ? IMA_TRUE : IMA_FALSE);
(*pConfigSessions)->in = ics->ics_in;
(*pConfigSessions)->out = ics->ics_out;
for (idx = 0; idx < ics->ics_in; idx++) {
if (ics->ics_bindings[idx].i_insize ==
sizeof (struct in_addr)) {
(*pConfigSessions)->bindings[idx].ipAddress.
ipv4Address = IMA_TRUE;
bcopy(&ics->ics_bindings[idx].i_addr.in4,
(*pConfigSessions)->bindings[idx].ipAddress.
ipAddress, sizeof (struct in_addr));
} else {
(*pConfigSessions)->bindings[idx].ipAddress.
ipv4Address = IMA_FALSE;
bcopy(&ics->ics_bindings[idx].i_addr.in6,
(*pConfigSessions)->bindings[idx].ipAddress.
ipAddress, sizeof (struct in6_addr));
}
}
free(ics);
return (IMA_STATUS_SUCCESS);
}
/*
* SUN_IMA_SetConfigSessions -
*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_SetConfigSessions(
IMA_OID targetOid,
SUN_IMA_CONFIG_SESSIONS *pConfigSessions
)
{
int fd;
int status;
iscsi_config_sess_t *ics;
int idx, size;
/* verify allowed range of sessions */
if ((pConfigSessions->in < ISCSI_MIN_CONFIG_SESSIONS) ||
(pConfigSessions->in > ISCSI_MAX_CONFIG_SESSIONS)) {
return (IMA_ERROR_INVALID_PARAMETER);
}
/* allocate record config_sess size */
size = ISCSI_SESSION_CONFIG_SIZE(pConfigSessions->in);
ics = (iscsi_config_sess_t *)malloc(size);
/* setup config_sess information */
(void) memset(ics, 0, sizeof (iscsi_config_sess_t));
ics->ics_ver = ISCSI_INTERFACE_VERSION;
ics->ics_oid = targetOid.objectSequenceNumber;
ics->ics_bound =
(pConfigSessions->bound == IMA_TRUE ? B_TRUE : B_FALSE);
ics->ics_in = pConfigSessions->in;
for (idx = 0; idx < ics->ics_in; idx++) {
if (pConfigSessions->bindings[idx].ipAddress.
ipv4Address == IMA_TRUE) {
ics->ics_bindings[idx].i_insize =
sizeof (struct in_addr);
bcopy(pConfigSessions->bindings[idx].
ipAddress.ipAddress,
&ics->ics_bindings[idx].i_addr.in4,
sizeof (struct in_addr));
} else {
ics->ics_bindings[idx].i_insize =
sizeof (struct in6_addr);
bcopy(pConfigSessions->bindings[idx].
ipAddress.ipAddress,
&ics->ics_bindings[idx].i_addr.in6,
sizeof (struct in6_addr));
}
}
/* open driver */
if ((status = open_driver(&fd))) {
free(ics);
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
/* issue ioctl request */
if (ioctl(fd, ISCSI_SET_CONFIG_SESSIONS, ics) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_SET_CONFIG_SESSIONS ioctl failed, errno: %d",
errno);
(void) close(fd);
free(ics);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
free(ics);
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;
int status;
iscsi_param_get_t pg;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(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;
}
/* Issue ISCSI_PARAM_GET ioctl again to obtain connection parameters. */
pg.g_param_type = ISCSI_CONN_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);
}
(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;
int status;
iscsi_param_set_t ps;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(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)) {
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
static int
prepare_discovery_entry(
SUN_IMA_TARGET_ADDRESS discoveryAddress,
entry_t *entry
)
{
return (prepare_discovery_entry_IMA(discoveryAddress.imaStruct, entry));
}
static int
prepare_discovery_entry_IMA(
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 ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
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)) {
status = errno;
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_DISCOVERY_SET ioctl failed, errno: %d",
status);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
}
/* LINTED E_STATIC_UNUSED */
static IMA_BOOL authMethodMatch(
IMA_AUTHMETHOD matchingMethod,
IMA_AUTHMETHOD *methodList,
IMA_UINT maxEntries
)
{
IMA_UINT i;
for (i = 0; i < maxEntries; i++) {
if (methodList[i] == matchingMethod) {
return (IMA_TRUE);
}
}
return (IMA_FALSE);
}
static IMA_STATUS get_target_oid_list(
uint32_t targetListType,
IMA_OID_LIST **ppList)
{
int fd;
int i;
int target_list_size;
int status;
int out_cnt;
iscsi_target_list_t *idlp;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
idlp = (iscsi_target_list_t *)calloc(1, sizeof (iscsi_target_list_t));
if (idlp == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
idlp->tl_vers = ISCSI_INTERFACE_VERSION;
idlp->tl_in_cnt = idlp->tl_out_cnt = 1;
idlp->tl_tgt_list_type = targetListType;
/*
* Issue ioctl. Space has been allocted for one entry.
* If more than one entry should be returned, we will re-issue the
* entry with the right amount of space allocted
*/
if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 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);
}
if (idlp->tl_out_cnt > 1) {
out_cnt = idlp->tl_out_cnt;
free(idlp);
target_list_size = sizeof (iscsi_target_list_t);
target_list_size += (sizeof (uint32_t) * 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 = out_cnt;
idlp->tl_tgt_list_type = targetListType;
/* Issue the same ioctl again to obtain all the OIDs. */
if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
#define ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d"
free(idlp);
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
ERROR_STR, targetListType, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
#undef ERROR_STR
}
}
*ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
idlp->tl_out_cnt * sizeof (IMA_OID));
(*ppList)->oidCount = idlp->tl_out_cnt;
for (i = 0; i < idlp->tl_out_cnt; i++) {
(*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET;
(*ppList)->oids[i].ownerId = 1;
(*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, *illp_saved;
int lun_list_size;
int status;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
illp = (iscsi_lun_list_t *)calloc(1, sizeof (iscsi_lun_list_t));
if (illp == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
illp->ll_vers = ISCSI_INTERFACE_VERSION;
if (targetOid == NULL) {
/* get lun oid list for all targets */
illp->ll_all_tgts = B_TRUE;
} else {
/* get lun oid list for single target */
illp->ll_all_tgts = B_FALSE;
illp->ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber;
}
illp->ll_in_cnt = illp->ll_out_cnt = 1;
/*
* Issue ioctl to retrieve the target luns. Space has been allocted
* for one entry. If more than one entry should be returned, we
* will re-issue the entry with the right amount of space allocted
*/
if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (illp->ll_out_cnt > 1) {
illp_saved = illp;
lun_list_size = sizeof (iscsi_lun_list_t);
lun_list_size += (sizeof (iscsi_if_lun_t) *
(illp->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 = illp_saved->ll_all_tgts;
illp->ll_tgt_oid = illp_saved->ll_tgt_oid;
illp->ll_in_cnt = illp_saved->ll_out_cnt;
free(illp_saved);
/* Issue the same ioctl again to get all 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 obtain digest algorithms. */
static IMA_STATUS
getDigest(
IMA_OID oid,
int ioctlCmd,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
)
{
IMA_MIN_MAX_VALUE pProps;
IMA_STATUS status;
if ((status = getISCSINodeParameter(MIN_MAX_PARAM, &oid, &pProps,
ioctlCmd)) != IMA_STATUS_SUCCESS) {
return (status);
}
switch (pProps.defaultValue) {
case ISCSI_DIGEST_NONE:
algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
algorithm->defaultAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C:
algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
algorithm->defaultAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C_NONE:
algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_NONE;
algorithm->defaultAlgorithmCount = 2;
break;
case ISCSI_DIGEST_NONE_CRC32C:
algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_CRC32C;
algorithm->defaultAlgorithmCount = 2;
break;
default:
/* Error */
syslog(LOG_USER|LOG_DEBUG,
"Invalid default digest: %d", pProps.defaultValue);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
/* The configured value */
if (pProps.currentValueValid == IMA_TRUE) {
algorithm->currentValid = IMA_TRUE;
switch (pProps.currentValue) {
case ISCSI_DIGEST_NONE:
algorithm->currentAlgorithms[0] =
ISCSI_DIGEST_NONE;
algorithm->currentAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C:
algorithm->currentAlgorithms[0] =
ISCSI_DIGEST_CRC32C;
algorithm->currentAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C_NONE:
algorithm->currentAlgorithms[0] =
ISCSI_DIGEST_CRC32C;
algorithm->currentAlgorithms[1] =
ISCSI_DIGEST_NONE;
algorithm->currentAlgorithmCount = 2;
break;
case ISCSI_DIGEST_NONE_CRC32C:
algorithm->currentAlgorithms[0] =
ISCSI_DIGEST_NONE;
algorithm->currentAlgorithms[1] =
ISCSI_DIGEST_CRC32C;
algorithm->currentAlgorithmCount = 2;
break;
default:
/* Error */
syslog(LOG_USER|LOG_DEBUG,
"Invalid configured digest: %d",
pProps.defaultValue);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
} else {
algorithm->currentValid = IMA_FALSE;
}
return (IMA_STATUS_SUCCESS);
}
/*
* getConnOidList -
*/
static IMA_STATUS getConnOidList(
IMA_OID *sessOid,
iscsi_conn_list_t **ppConnList
)
{
iscsi_conn_list_t *iscsiConnList = NULL;
size_t allocLen;
int fd;
int status;
int out_cnt;
/* Preset it to NULL to prepare for the case of failure */
*ppConnList = NULL;
/* We try to open the driver now. */
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
iscsiConnList = (iscsi_conn_list_t *)calloc(1,
sizeof (iscsi_conn_list_t));
if (iscsiConnList == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
iscsiConnList->cl_in_cnt = iscsiConnList->cl_out_cnt = 1;
if (sessOid == NULL) {
iscsiConnList->cl_all_sess = B_TRUE;
} else {
iscsiConnList->cl_all_sess = B_FALSE;
iscsiConnList->cl_sess_oid =
(uint32_t)sessOid->objectSequenceNumber;
}
/*
* Issue ioctl to retrieve the connection OIDs. Space has been
* allocated for one entry. If more than one entry should be
* returned, we will re-issue the entry with the right amount of
* space allocted
*/
if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d", errno);
*ppConnList = NULL;
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (iscsiConnList->cl_out_cnt > 1) {
out_cnt = iscsiConnList->cl_out_cnt;
free(iscsiConnList);
allocLen = sizeof (iscsi_conn_list_t);
allocLen += (sizeof (iscsi_if_conn_t) * out_cnt - 1);
iscsiConnList = (iscsi_conn_list_t *)calloc(1, allocLen);
if (iscsiConnList == NULL) {
*ppConnList = NULL;
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
iscsiConnList->cl_in_cnt = out_cnt;
if (sessOid == NULL) {
iscsiConnList->cl_all_sess = B_TRUE;
} else {
iscsiConnList->cl_all_sess = B_FALSE;
iscsiConnList->cl_sess_oid =
(uint32_t)sessOid->objectSequenceNumber;
}
/* Issue the same ioctl again to obtain all the OIDs */
if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d",
errno);
*ppConnList = NULL;
free(iscsiConnList);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (out_cnt < iscsiConnList->cl_out_cnt) {
/*
* The connection list grew between the first and second
* ioctls.
*/
syslog(LOG_USER|LOG_DEBUG,
"The connection list has grown. There could be "
"more connections than listed.");
}
}
(void) close(fd);
*ppConnList = iscsiConnList;
return (IMA_STATUS_SUCCESS);
}
/*
* getConnProps -
*/
static IMA_STATUS getConnProps(
iscsi_if_conn_t *pConn,
iscsi_conn_props_t **ppConnProps
)
{
iscsi_conn_props_t *iscsiConnProps;
int fd;
int status;
/* We try to open the driver. */
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
iscsiConnProps = (iscsi_conn_props_t *)calloc(1,
sizeof (*iscsiConnProps));
if (iscsiConnProps == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
iscsiConnProps->cp_vers = ISCSI_INTERFACE_VERSION;
iscsiConnProps->cp_oid = pConn->c_oid;
iscsiConnProps->cp_cid = pConn->c_cid;
iscsiConnProps->cp_sess_oid = pConn->c_sess_oid;
/* The IOCTL is submitted. */
if (ioctl(fd, ISCSI_CONN_PROPS_GET, iscsiConnProps) != 0) {
/* IOCTL failed */
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
free(iscsiConnProps);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
*ppConnProps = iscsiConnProps;
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;
int status;
iscsi_auth_props_t auth;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
auth.a_vers = ISCSI_INTERFACE_VERSION;
auth.a_oid = (uint32_t)oid.objectSequenceNumber;
/*
* Get the current auth fields so they don't need to be reset
* here.
*/
if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
/* EMPTY */
/* Initializing auth structure with current settings */
}
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 set authentication method. */
static IMA_STATUS getAuthMethods(
IMA_OID oid,
IMA_UINT *pMethodCount,
IMA_AUTHMETHOD *pMethodList
)
{
int fd;
int status;
iscsi_auth_props_t auth;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(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);
}
if (auth.a_auth_method == authMethodNone) {
pMethodList[0] = IMA_AUTHMETHOD_NONE;
*pMethodCount = 1;
} else {
int i = 0;
if (!((auth.a_auth_method & authMethodCHAP)^authMethodCHAP)) {
pMethodList[i++] = IMA_AUTHMETHOD_CHAP;
}
*pMethodCount = i;
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
/* Helper function to open driver */
int open_driver(
int *fd
)
{
int ret = 0;
if ((*fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
ret = errno;
syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
ISCSI_DRIVER_DEVCTL, ret);
}
return (ret);
}
/*
* Iscsi driver does not support OID for discovery address. Create
* a modified version of IMA_RemoveDiscoveryAddress that takes
* discoveryAddress (instead of an OID) as input argument.
*/
IMA_API IMA_STATUS SUN_IMA_RemoveDiscoveryAddress(
SUN_IMA_TARGET_ADDRESS discoveryAddress
)
{
entry_t entry;
int fd;
int status, i, addr_list_size, insize;
iscsi_addr_list_t *idlp, al_info;
iscsi_addr_t *matched_addr = NULL;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
if (prepare_discovery_entry(discoveryAddress, &entry) !=
DISC_ADDR_OK) {
(void) close(fd);
return (IMA_ERROR_INVALID_PARAMETER);
}
(void) memset(&al_info, 0, sizeof (al_info));
al_info.al_vers = ISCSI_INTERFACE_VERSION;
al_info.al_in_cnt = 0;
/*
* Issue ioctl to get 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) {
(void) close(fd);
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_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 to get all the discovery addresses */
if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
free(idlp);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
/*
* find the matched discovery address
*/
for (i = 0; i < idlp->al_out_cnt; i++) {
insize = idlp->al_addrs[i].a_addr.i_insize;
if (insize != entry.e_insize) {
continue;
}
if (insize == sizeof (struct in_addr)) {
if (idlp->al_addrs[i].a_addr.i_addr.in4.s_addr ==
entry.e_u.u_in4.s_addr) {
matched_addr = &(idlp->al_addrs[i]);
break;
}
}
if (insize == sizeof (struct in6_addr)) {
if (bcmp(entry.e_u.u_in6.s6_addr,
idlp->al_addrs[i].a_addr.i_addr.in6.s6_addr,
insize) == 0) {
matched_addr = &(idlp->al_addrs[i]);
break;
}
}
}
free(idlp);
if (matched_addr == NULL) {
(void) close(fd);
return (IMA_ERROR_OBJECT_NOT_FOUND);
}
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);
}
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_SetTargetAuthMethods(
IMA_OID targetOid,
IMA_UINT *methodCount,
const IMA_AUTHMETHOD *pMethodList
)
{
return (setAuthMethods(targetOid, methodCount, pMethodList));
}
IMA_STATUS getNegotiatedDigest(
int digestType,
SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
SUN_IMA_CONN_PROPERTIES *connProps) {
IMA_UINT digest;
if (connProps->valuesValid == IMA_TRUE) {
algorithm->negotiatedValid = IMA_TRUE;
if (digestType == ISCSI_LOGIN_PARAM_HEADER_DIGEST) {
digest = connProps->headerDigest;
} else {
digest = connProps->dataDigest;
}
switch (digest) {
case ISCSI_DIGEST_NONE:
algorithm->negotiatedAlgorithms[0] =
ISCSI_DIGEST_NONE;
algorithm->negotiatedAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C:
algorithm->negotiatedAlgorithms[0] =
ISCSI_DIGEST_CRC32C;
algorithm->negotiatedAlgorithmCount = 1;
break;
case ISCSI_DIGEST_CRC32C_NONE:
algorithm->negotiatedAlgorithms[0] =
ISCSI_DIGEST_CRC32C;
algorithm->negotiatedAlgorithms[1] =
ISCSI_DIGEST_NONE;
algorithm->negotiatedAlgorithmCount = 2;
break;
case ISCSI_DIGEST_NONE_CRC32C:
algorithm->negotiatedAlgorithms[0] =
ISCSI_DIGEST_NONE;
algorithm->negotiatedAlgorithms[1] =
ISCSI_DIGEST_CRC32C;
algorithm->negotiatedAlgorithmCount = 2;
break;
default:
syslog(LOG_USER|LOG_DEBUG,
"Invalid negotiated digest: %d",
digest);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
} else {
algorithm->negotiatedValid = IMA_FALSE;
}
return (IMA_STATUS_SUCCESS);
}
/*
* Non-IMA defined function.
*/
IMA_API IMA_STATUS SUN_IMA_GetISNSServerAddressPropertiesList(
SUN_IMA_DISC_ADDR_PROP_LIST **ppList
)
{
char isns_server_addr_str[256];
int fd;
int i;
int isns_server_addr_list_size;
int status;
int out_cnt;
iscsi_addr_list_t *ialp;
/* LINTED */
IMA_IP_ADDRESS *ipAddr;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t));
if (ialp == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
ialp->al_vers = ISCSI_INTERFACE_VERSION;
ialp->al_in_cnt = ialp->al_out_cnt = 1;
/*
* Issue ioctl to retrieve the isns server addresses. Space has been
* allocted for one entry. If more than one entry should be returned,
* we will re-issue the entry with the right amount of space allocted
*/
if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, errno: %d",
errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
isns_server_addr_list_size = sizeof (iscsi_addr_list_t);
if (ialp->al_out_cnt > 1) {
out_cnt = ialp->al_out_cnt;
free(ialp);
isns_server_addr_list_size += (sizeof (iscsi_addr_t) *
out_cnt - 1);
ialp = (iscsi_addr_list_t *)calloc(1,
isns_server_addr_list_size);
if (ialp == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
ialp->al_vers = ISCSI_INTERFACE_VERSION;
ialp->al_in_cnt = out_cnt;
/*
* Issue ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl again to obtain
* the list of all the iSNS server addresses
*/
if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
free(ialp);
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_ISNS_SERVER_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 {
(void) strlcpy(isns_server_addr_str, "unknown",
sizeof (isns_server_addr_str));
}
ipAddr = &(*ppList)->props[i].discoveryAddress.
hostnameIpAddress.id.ipAddress;
bcopy(&ialp->al_addrs[i].a_addr.i_addr,
(*ppList)->props[i].discoveryAddress.hostnameIpAddress.id.
ipAddress.ipAddress,
sizeof (ipAddr->ipAddress));
(*ppList)->props[i].discoveryAddress.portNumber =
ialp->al_addrs[i].a_port;
}
free(ialp);
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
/*ARGSUSED*/
/*
* Remove iSNS Server Address
*/
IMA_API IMA_STATUS SUN_IMA_RemoveISNSServerAddress(
SUN_IMA_TARGET_ADDRESS isnsServerAddress
)
{
entry_t entry;
int fd, status;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
if (prepare_discovery_entry(isnsServerAddress, &entry) !=
DISC_ADDR_OK) {
(void) close(fd);
return (IMA_ERROR_INVALID_PARAMETER);
}
if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_CLEAR, &entry)) {
status = errno;
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_ISNS_SERVER_ADDR_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);
}
/*ARGSUSED*/
IMA_API IMA_STATUS SUN_IMA_AddISNSServerAddress(
const SUN_IMA_TARGET_ADDRESS isnsServerAddress
)
{
entry_t entry;
int fd;
int status;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
if (prepare_discovery_entry(isnsServerAddress, &entry) !=
DISC_ADDR_OK) {
(void) close(fd);
return (IMA_ERROR_INVALID_PARAMETER);
}
if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_SET, &entry)) {
/*
* Encountered problem setting the discovery address.
*/
(void) close(fd);
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_ISNS_SERVER_ADDR_SET ioctl failed, errno: %d",
errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_RetrieveISNSServerTargets(
IMA_TARGET_ADDRESS serverAddress,
SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
)
{
int fd;
int ctr;
int server_pg_list_sz;
int status;
isns_server_portal_group_list_t *server_pg_list = NULL;
isns_portal_group_list_t *pg_list = NULL;
IMA_BOOL retry = IMA_TRUE;
entry_t entry;
#define ISNS_SERVER_DEFAULT_NUM_TARGETS 50
server_pg_list_sz = sizeof (*server_pg_list) +
((ISNS_SERVER_DEFAULT_NUM_TARGETS - 1) *
sizeof (isns_portal_group_t));
server_pg_list = (isns_server_portal_group_list_t *)calloc(1,
server_pg_list_sz);
if (server_pg_list == NULL) {
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
server_pg_list->addr_port_list.pg_in_cnt =
ISNS_SERVER_DEFAULT_NUM_TARGETS;
if ((prepare_discovery_entry_IMA(serverAddress, &entry)
!= DISC_ADDR_OK)) {
free(server_pg_list);
return (IMA_ERROR_INVALID_PARAMETER);
}
server_pg_list->addr.a_port = entry.e_port;
server_pg_list->addr.a_addr.i_insize = entry.e_insize;
if (entry.e_insize == sizeof (struct in_addr)) {
server_pg_list->addr.a_addr.i_addr.in4.s_addr =
(entry.e_u.u_in4.s_addr);
} else if (entry.e_insize == sizeof (struct in6_addr)) {
bcopy(&entry.e_u.u_in6.s6_addr,
server_pg_list->addr.a_addr.i_addr.in6.s6_addr, 16);
}
if ((status = open_driver(&fd))) {
free(server_pg_list);
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
retry_isns:
/*
* Issue ioctl to obtain the ISNS Portal Group List list
*/
if (ioctl(fd, ISCSI_ISNS_SERVER_GET, server_pg_list) != 0) {
int tmp_errno = errno;
IMA_STATUS return_status;
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_ISNS_SERVER_GET ioctl failed, errno: %d", tmp_errno);
if (tmp_errno == EACCES) {
return_status = IMA_ERROR_OBJECT_NOT_FOUND;
} else {
return_status = IMA_ERROR_UNEXPECTED_OS_ERROR;
}
(void) close(fd);
free(server_pg_list);
return (return_status);
}
pg_list = &server_pg_list->addr_port_list;
/* check if all targets received */
if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) {
if (retry == IMA_TRUE) {
server_pg_list_sz = sizeof (*server_pg_list) +
((pg_list->pg_out_cnt - 1) *
sizeof (isns_server_portal_group_list_t));
server_pg_list = (isns_server_portal_group_list_t *)
realloc(server_pg_list, server_pg_list_sz);
if (server_pg_list == NULL) {
(void) close(fd);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
pg_list = &server_pg_list->addr_port_list;
pg_list->pg_in_cnt = pg_list->pg_out_cnt;
retry = IMA_FALSE;
goto retry_isns;
} else {
/*
* don't retry after 2 attempts. The target list
* shouldn't continue growing. Just continue
* on and display what was found.
*/
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_SENDTGTS_GET overflow: "
"failed to obtain all targets");
pg_list->pg_out_cnt = pg_list->pg_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) +
pg_list->pg_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
if (*ppList == NULL) {
free(server_pg_list);
return (IMA_ERROR_INSUFFICIENT_MEMORY);
}
(*ppList)->keyCount = pg_list->pg_out_cnt;
for (ctr = 0; ctr < pg_list->pg_out_cnt; ctr++) {
(void) mbstowcs((*ppList)->keys[ctr].name,
(char *)pg_list->pg_list[ctr].pg_iscsi_name,
IMA_NODE_NAME_LEN);
(*ppList)->keys[ctr].tpgt = pg_list->pg_list[ctr].pg_tag;
(*ppList)->keys[ctr].address.portNumber =
pg_list->pg_list[ctr].pg_port;
if (pg_list->pg_list[ctr].insize == sizeof (struct in_addr)) {
(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
IMA_TRUE;
} else if (pg_list->pg_list[ctr].insize ==
sizeof (struct in6_addr)) {
(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
IMA_FALSE;
} else {
free(pg_list);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
(void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
&(pg_list->pg_list[ctr].pg_ip_addr),
pg_list->pg_list[ctr].insize);
}
free(server_pg_list);
return (IMA_STATUS_SUCCESS);
}
/* ARGSUSED */
IMA_STATUS SUN_IMA_GetSessionOidList(
IMA_OID initiatorOid,
IMA_OID_LIST **ppList
)
{
return (get_target_oid_list(ISCSI_TGT_OID_LIST, ppList));
}
/*ARGSUSED*/
IMA_API IMA_STATUS SUN_IMA_GetTargetAuthParms(
IMA_OID oid,
IMA_AUTHMETHOD method,
IMA_INITIATOR_AUTHPARMS *pParms
)
{
int fd;
iscsi_chap_props_t chap_p;
if (pParms == NULL) {
return (IMA_ERROR_INVALID_PARAMETER);
}
if (oid.objectType != IMA_OBJECT_TYPE_TARGET) {
return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
}
if (method != IMA_AUTHMETHOD_CHAP) {
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)oid.objectSequenceNumber;
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);
}
(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 SUN_IMA_GetBootTargetName(
IMA_NODE_NAME tgtName
)
{
int fd;
IMA_STATUS rtn;
iscsi_boot_property_t bootProp;
bootProp.tgt_name.n_name[0] = '\0';
bootProp.tgt_chap.c_user[0] = '\0';
tgtName[0] = L'\0';
rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
ISCSI_DRIVER_DEVCTL, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if ((bootProp.tgt_name.n_name[0] != '\0') && (tgtName != NULL)) {
if (mbstowcs(tgtName, (const char *)bootProp.tgt_name.n_name,
IMA_NODE_NAME_LEN) == (size_t)-1) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI Target name covert to WCHAR fail");
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
} else {
rtn = IMA_STATUS_SUCCESS;
}
}
return (rtn);
}
IMA_API IMA_STATUS SUN_IMA_GetBootTargetAuthParams(
IMA_INITIATOR_AUTHPARMS *pTgtCHAP
)
{
int fd;
IMA_STATUS rtn;
iscsi_boot_property_t bootProp;
bootProp.tgt_name.n_name[0] = '\0';
bootProp.tgt_chap.c_user[0] = '\0';
bootProp.tgt_chap.c_secret[0] = '\0';
rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
ISCSI_DRIVER_DEVCTL, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (pTgtCHAP != NULL) {
if (bootProp.tgt_chap.c_user[0] != '\0') {
(void) memcpy(pTgtCHAP->chapParms.name,
bootProp.tgt_chap.c_user, ISCSI_MAX_NAME_LEN);
} else {
pTgtCHAP->chapParms.name[0] = '\0';
}
if (bootProp.tgt_chap.c_secret[0] != '\0') {
(void) memcpy(pTgtCHAP->chapParms.challengeSecret,
bootProp.tgt_chap.c_secret, MAX_CHAP_SECRET_LEN);
} else {
pTgtCHAP->chapParms.challengeSecret[0] = '\0';
}
rtn = IMA_STATUS_SUCCESS;
}
return (rtn);
}
IMA_STATUS SUN_IMA_GetBootMpxio(
IMA_BOOL *pMpxioEnabled
)
{
int fd;
iscsi_boot_property_t bootProp;
bootProp.hba_mpxio_enabled = B_FALSE;
*pMpxioEnabled = IMA_UNKNOWN;
if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
ISCSI_DRIVER_DEVCTL, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (bootProp.hba_mpxio_enabled) {
*pMpxioEnabled = IMA_TRUE;
} else {
*pMpxioEnabled = IMA_FALSE;
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetBootIscsi(
IMA_BOOL *pIscsiBoot
)
{
int fd;
iscsi_boot_property_t bootProp;
bootProp.iscsiboot = 0;
*pIscsiBoot = 0;
if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
ISCSI_DRIVER_DEVCTL, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
*pIscsiBoot = bootProp.iscsiboot;
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_GetSvcStatus(
IMA_BOOL *pSvcEnabled)
{
int fd;
uint32_t status = ISCSI_SERVICE_DISABLED;
if (pSvcEnabled == NULL)
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
*pSvcEnabled = 0;
if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
ISCSI_DRIVER_DEVCTL, errno);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (ioctl(fd, ISCSI_SMF_GET, &status) != 0) {
syslog(LOG_USER|LOG_DEBUG,
"ISCSI_SVC_GET ioctl failed, errno: %d",
errno);
(void) close(fd);
return (IMA_ERROR_UNEXPECTED_OS_ERROR);
}
if (status == ISCSI_SERVICE_ENABLED) {
*pSvcEnabled = 1;
}
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}
IMA_STATUS SUN_IMA_ReEnumeration(
IMA_OID targetId
)
{
int fd;
int status;
iscsi_reen_t reet;
reet.re_ver = ISCSI_INTERFACE_VERSION;
reet.re_oid = (uint32_t)targetId.objectSequenceNumber;
if ((status = open_driver(&fd))) {
return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
}
(void) ioctl(fd, ISCSI_TARGET_REENUM, &reet);
(void) close(fd);
return (IMA_STATUS_SUCCESS);
}