Home | History | Annotate | Download | only in iscsiadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <arpa/inet.h>
     27 #include <sys/socket.h>
     28 #include <sys/types.h>
     29 #include <stdarg.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <strings.h>
     33 #include <unistd.h>
     34 #include <syslog.h>
     35 #include <errno.h>
     36 
     37 #include <fcntl.h>
     38 #include <stdio.h>
     39 #include <time.h>
     40 #include <libdevinfo.h>
     41 
     42 #include <sys/scsi/adapters/iscsi_if.h>
     43 #include <sys/scsi/adapters/iscsi_door.h>
     44 #include <sys/iscsi_protocol.h>
     45 #include <ima.h>
     46 #include "iscsiadm.h"
     47 #include "sun_ima.h"
     48 
     49 #define	LIBRARY_PROPERTY_SUPPORTED_IMA_VERSION	1
     50 #define	LIBRARY_PROPERTY_IMPLEMENTATION_VERSION	L"1.0.0"
     51 #define	LIBRARY_PROPERTY_VENDOR	L"Sun Microsystems, Inc."
     52 #define	DEFAULT_NODE_NAME_FORMAT    "iqn.2003-13.com.ima.%s"
     53 #define	PLUGIN_OWNER 1
     54 #define	MAX_CHAP_SECRET_LEN	16
     55 
     56 /* LINTED E_STATIC_UNUSED */
     57 static IMA_INT32		number_of_plugins = -1;
     58 /* LINTED E_STATIC_UNUSED */
     59 static IMA_NODE_NAME		sharedNodeName;
     60 /* LINTED E_STATIC_UNUSED */
     61 static IMA_NODE_ALIAS		sharedNodeAlias;
     62 /* LINTED E_STATIC_UNUSED */
     63 static IMA_PLUGIN_PROPERTIES	PluginProperties;
     64 
     65 /* LINTED E_STATIC_UNUSED */
     66 static IMA_OID			pluginOid;
     67 static IMA_OID			lhbaObjectId;
     68 /* LINTED E_STATIC_UNUSED */
     69 static boolean_t		pluginInit = B_FALSE;
     70 
     71 /* Forward declaration */
     72 #define	BOOL_PARAM		1
     73 #define	MIN_MAX_PARAM		2
     74 #define	PARAM_OP_OK		0
     75 #define	PARAM_OP_FAILED		1
     76 
     77 static int open_driver(int *fd);
     78 static IMA_STATUS getISCSINodeParameter(int paramType,
     79     IMA_OID *oid,
     80     void *pProps,
     81     uint32_t paramIndex);
     82 static IMA_STATUS setISCSINodeParameter(int paramType,
     83     IMA_OID *oid,
     84     void *pProps,
     85     uint32_t paramIndex);
     86 static IMA_STATUS getDigest(IMA_OID oid, int ioctlCmd,
     87     SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm);
     88 static IMA_STATUS setAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
     89     const IMA_AUTHMETHOD *pMethodList);
     90 static IMA_STATUS getAuthMethods(IMA_OID oid, IMA_UINT *pMethodCount,
     91     IMA_AUTHMETHOD *pMethodList);
     92 IMA_STATUS getNegotiatedDigest(int digestType,
     93 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
     94 	SUN_IMA_CONN_PROPERTIES *connProps);
     95 
     96 /* OK */
     97 #define	DISC_ADDR_OK		    0
     98 /* Incorrect IP address */
     99 #define	DISC_ADDR_INTEGRITY_ERROR   1
    100 /* Error converting text IP address to numeric binary form */
    101 #define	DISC_ADDR_IP_CONV_ERROR	    2
    102 static int prepare_discovery_entry(SUN_IMA_TARGET_ADDRESS discoveryAddress,
    103     entry_t *entry);
    104 static int prepare_discovery_entry_IMA(IMA_TARGET_ADDRESS discoveryAddress,
    105     entry_t *entry);
    106 
    107 /* LINTED E_STATIC_UNUSED */
    108 static IMA_STATUS configure_discovery_method(IMA_BOOL enable,
    109     iSCSIDiscoveryMethod_t method);
    110 
    111 static IMA_STATUS get_target_oid_list(uint32_t targetListType,
    112     IMA_OID_LIST **ppList);
    113 
    114 static IMA_STATUS get_target_lun_oid_list(IMA_OID * targetOid,
    115 					    iscsi_lun_list_t  **ppLunList);
    116 
    117 static int get_lun_devlink(di_devlink_t link, void *arg);
    118 
    119 static IMA_STATUS getConnOidList(
    120 	IMA_OID			*oid,
    121 	iscsi_conn_list_t	**ppConnList);
    122 
    123 static IMA_STATUS getConnProps(
    124 	iscsi_if_conn_t		*pConn,
    125 	iscsi_conn_props_t	**ppConnProps);
    126 
    127 /* LINTED E_STATIC_UNUSED */
    128 static void libSwprintf(wchar_t *wcs, const wchar_t *lpszFormat, ...)
    129 {
    130 	va_list args;
    131 	va_start(args, lpszFormat);
    132 	(void) vswprintf(wcs, 255, lpszFormat, args);
    133 	va_end(args);
    134 }
    135 
    136 
    137 char *
    138 _strlwr(char *s)
    139 {
    140 	char *t = s;
    141 	while (t != NULL && *t) {
    142 		if (*t >= 'A' && *t <= 'Z')
    143 			*t += 32;
    144 		t++;
    145 	}
    146 	return (s);
    147 }
    148 
    149 /* LINTED E_STATIC_UNUSED */
    150 static void GetBuildTime(IMA_DATETIME* pdatetime)
    151 {
    152 #if defined(BUILD_DATE)
    153 	if (strptime(BUILD_DATE, "%Y/%m/%d %T %Z", pdatetime) == NULL) {
    154 		(void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
    155 	}
    156 #else
    157 	(void) memset(pdatetime, 0, sizeof (IMA_DATETIME));
    158 #endif
    159 }
    160 
    161 /*
    162  * Non-IMA defined function.
    163  */
    164 IMA_API	IMA_STATUS SUN_IMA_GetDiscoveryAddressPropertiesList(
    165     SUN_IMA_DISC_ADDR_PROP_LIST	**ppList
    166 )
    167 {
    168 	char		    discovery_addr_str[256];
    169 	int		    fd;
    170 	int		    i;
    171 	int		    discovery_addr_list_size;
    172 	int		    status;
    173 	int		    out_cnt;
    174 	iscsi_addr_list_t   *ialp;
    175 	/* LINTED E_FUNC_SET_NOT_USED */
    176 	IMA_IP_ADDRESS	    *ipAddr;
    177 
    178 	if ((status = open_driver(&fd))) {
    179 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    180 	}
    181 
    182 	ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t));
    183 	if (ialp == NULL) {
    184 		(void) close(fd);
    185 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
    186 	}
    187 
    188 	ialp->al_vers = ISCSI_INTERFACE_VERSION;
    189 	ialp->al_in_cnt = ialp->al_out_cnt = 1;
    190 
    191 	/*
    192 	 * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl
    193 	 * We have allocated space for one entry, if more than one
    194 	 * address is going to be returned, we will re-issue the ioctl
    195 	 */
    196 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) {
    197 		(void) close(fd);
    198 		syslog(LOG_USER|LOG_DEBUG,
    199 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno: %d",
    200 		    errno);
    201 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    202 	}
    203 
    204 	if (ialp->al_out_cnt > 1) {
    205 		/*
    206 		 * we need to allocate more space, save off the out_cnt
    207 		 * and free ialp
    208 		 */
    209 		out_cnt = ialp->al_out_cnt;
    210 		free(ialp);
    211 
    212 		discovery_addr_list_size = sizeof (iscsi_addr_list_t);
    213 		discovery_addr_list_size += (sizeof (iscsi_addr_t) *
    214 		    out_cnt - 1);
    215 		ialp = (iscsi_addr_list_t *)calloc(1, discovery_addr_list_size);
    216 		if (ialp == NULL) {
    217 			(void) close(fd);
    218 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
    219 		}
    220 		ialp->al_vers = ISCSI_INTERFACE_VERSION;
    221 		ialp->al_in_cnt = out_cnt;
    222 
    223 		/*
    224 		 * Issue ISCSI_DISCOVERY_ADDR_LIST_GET ioctl again to obtain all
    225 		 * the discovery addresses.
    226 		 */
    227 		if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, ialp) != 0) {
    228 #define	ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d"
    229 			free(ialp);
    230 			(void) close(fd);
    231 			syslog(LOG_USER|LOG_DEBUG,
    232 			    ERROR_STR, errno);
    233 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    234 #undef ERROR_STR
    235 
    236 		}
    237 	}
    238 
    239 	*ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)calloc(1,
    240 	    sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) +
    241 	    ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES));
    242 	if (*ppList == NULL) {
    243 		free(ialp);
    244 		(void) close(fd);
    245 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
    246 	}
    247 	(*ppList)->discAddrCount = ialp->al_out_cnt;
    248 
    249 	for (i = 0; i < ialp->al_out_cnt; i++) {
    250 		if (ialp->al_addrs[i].a_addr.i_insize ==
    251 		    sizeof (struct in_addr)) {
    252 
    253 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
    254 			id.ipAddress.ipv4Address = IMA_TRUE;
    255 
    256 		} else if (ialp->al_addrs[i].a_addr.i_insize ==
    257 		    sizeof (struct in6_addr)) {
    258 
    259 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
    260 			id.ipAddress.ipv4Address = IMA_FALSE;
    261 
    262 		} else {
    263 			(void) strlcpy(discovery_addr_str, "unknown",
    264 			    sizeof (discovery_addr_str));
    265 		}
    266 
    267 		ipAddr = &(*ppList)->props[i].discoveryAddress.
    268 		    hostnameIpAddress.id.ipAddress;
    269 
    270 		bcopy(&ialp->al_addrs[i].a_addr.i_addr,
    271 		    (*ppList)->props[i].discoveryAddress.hostnameIpAddress.id.
    272 		    ipAddress.ipAddress,
    273 		    sizeof (ipAddr->ipAddress));
    274 
    275 		(*ppList)->props[i].discoveryAddress.portNumber =
    276 		    ialp->al_addrs[i].a_port;
    277 	}
    278 
    279 	free(ialp);
    280 	(void) close(fd);
    281 	return (IMA_STATUS_SUCCESS);
    282 }
    283 
    284 IMA_API IMA_STATUS SUN_IMA_GetStaticTargetProperties(
    285 		IMA_OID	staticTargetOid,
    286 		SUN_IMA_STATIC_TARGET_PROPERTIES *pProps
    287 )
    288 {
    289 	int fd;
    290 	int status;
    291 	iscsi_static_property_t prop;
    292 	/* LINTED */
    293 	IMA_IP_ADDRESS	    *ipAddr;
    294 
    295 	if ((status = open_driver(&fd))) {
    296 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    297 	}
    298 
    299 	(void) memset(&prop, 0, sizeof (iscsi_static_property_t));
    300 	prop.p_vers = ISCSI_INTERFACE_VERSION;
    301 	prop.p_oid = (uint32_t)staticTargetOid.objectSequenceNumber;
    302 	if (ioctl(fd, ISCSI_STATIC_GET, &prop) != 0) {
    303 		status = errno;
    304 		(void) close(fd);
    305 		syslog(LOG_USER|LOG_DEBUG,
    306 		    "ISCSI_STATIC_GET ioctl failed, errno: %d", status);
    307 		if (status == ENOENT) {
    308 			return (IMA_ERROR_OBJECT_NOT_FOUND);
    309 		} else {
    310 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    311 		}
    312 	}
    313 	(void) close(fd);
    314 
    315 	(void) mbstowcs(pProps->staticTarget.targetName, (char *)prop.p_name,
    316 	    sizeof (pProps->staticTarget.targetName)/sizeof (IMA_WCHAR));
    317 
    318 	if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
    319 	    sizeof (struct in_addr)) {
    320 		/* IPv4 */
    321 		pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.
    322 			id.ipAddress.ipv4Address = IMA_TRUE;
    323 	} else if (prop.p_addr_list.al_addrs[0].a_addr.i_insize ==
    324 	    sizeof (struct in6_addr)) {
    325 		/* IPv6 */
    326 		pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.
    327 			id.ipAddress.ipv4Address = IMA_FALSE;
    328 	} else {
    329 		/* Should not happen */
    330 		syslog(LOG_USER|LOG_DEBUG,
    331 		    "ISCSI_STATIC_GET returned bad address");
    332 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    333 	}
    334 
    335 	ipAddr = &pProps->staticTarget.targetAddress.imaStruct.
    336 	    hostnameIpAddress.id.ipAddress;
    337 
    338 	bcopy(&prop.p_addr_list.al_addrs[0].a_addr.i_addr,
    339 	    pProps->staticTarget.targetAddress.imaStruct.hostnameIpAddress.id.
    340 	    ipAddress.ipAddress, sizeof (ipAddr->ipAddress));
    341 
    342 	pProps->staticTarget.targetAddress.imaStruct.portNumber =
    343 	    prop.p_addr_list.al_addrs[0].a_port;
    344 
    345 
    346 	if (prop.p_addr_list.al_tpgt == (uint32_t)ISCSI_DEFAULT_TPGT) {
    347 		pProps->staticTarget.targetAddress.defaultTpgt = IMA_TRUE;
    348 		pProps->staticTarget.targetAddress.tpgt = 0;
    349 	} else {
    350 		pProps->staticTarget.targetAddress.defaultTpgt = IMA_FALSE;
    351 		pProps->staticTarget.targetAddress.tpgt =
    352 		    prop.p_addr_list.al_tpgt;
    353 	}
    354 
    355 	return (IMA_STATUS_SUCCESS);
    356 }
    357 
    358 /*ARGSUSED*/
    359 IMA_API IMA_STATUS SUN_IMA_AddStaticTarget(
    360 		IMA_OID lhbaOid,
    361 		const SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig,
    362 		IMA_OID *pTargetOid
    363 )
    364 {
    365 	iscsi_target_entry_t	target;
    366 	int			fd;
    367 	int			target_in_addr_size;
    368 	int			status;
    369 	union {
    370 		struct in_addr	u_in4;
    371 		struct in6_addr	u_in6;
    372 	}			target_in;
    373 
    374 	/*
    375 	 * staticConfig.address may come in with port number at its trailer.
    376 	 * Parse it to separate the IP address and port number.
    377 	 * Also translate the hostname to IP address if needed.
    378 	 */
    379 
    380 	if (staticConfig.targetAddress.imaStruct.hostnameIpAddress.id.ipAddress.
    381 	    ipv4Address == IMA_FALSE) {
    382 
    383 		bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress.
    384 		    id.ipAddress.ipAddress, &target_in.u_in6,
    385 		    sizeof (target_in.u_in6));
    386 
    387 		target_in_addr_size = sizeof (struct in6_addr);
    388 	} else {
    389 
    390 		bcopy(staticConfig.targetAddress.imaStruct.hostnameIpAddress.
    391 		    id.ipAddress.ipAddress, &target_in.u_in4,
    392 		    sizeof (target_in.u_in4));
    393 
    394 		target_in_addr_size = sizeof (struct in_addr);
    395 	}
    396 
    397 	(void) memset(&target, 0, sizeof (iscsi_target_entry_t));
    398 	target.te_entry.e_vers = ISCSI_INTERFACE_VERSION;
    399 	target.te_entry.e_oid = ISCSI_OID_NOTSET;
    400 
    401 	(void) wcstombs((char *)target.te_name, staticConfig.targetName,
    402 	    ISCSI_MAX_NAME_LEN);
    403 
    404 	target.te_entry.e_insize = target_in_addr_size;
    405 	if (target.te_entry.e_insize == sizeof (struct in_addr)) {
    406 		target.te_entry.e_u.u_in4.s_addr = target_in.u_in4.s_addr;
    407 	} else if (target.te_entry.e_insize == sizeof (struct in6_addr)) {
    408 		bcopy(target_in.u_in6.s6_addr,
    409 		    target.te_entry.e_u.u_in6.s6_addr,
    410 		    sizeof (struct in6_addr));
    411 	} else {
    412 		return (IMA_ERROR_INVALID_PARAMETER);
    413 	}
    414 
    415 	target.te_entry.e_port =
    416 	    staticConfig.targetAddress.imaStruct.portNumber;
    417 
    418 	if (staticConfig.targetAddress.defaultTpgt == IMA_TRUE) {
    419 		target.te_entry.e_tpgt = ISCSI_DEFAULT_TPGT;
    420 	} else {
    421 		target.te_entry.e_tpgt = staticConfig.targetAddress.tpgt;
    422 	}
    423 
    424 	if ((status = open_driver(&fd))) {
    425 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    426 	}
    427 
    428 	if (ioctl(fd, ISCSI_STATIC_SET, &target)) {
    429 		/*
    430 		 * Encountered problem setting the IP address and port for
    431 		 * the target just added.
    432 		 */
    433 		syslog(LOG_USER|LOG_DEBUG,
    434 		    "ISCSI_STATIC_SET ioctl failed, errno: %d", errno);
    435 		(void) close(fd);
    436 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    437 	}
    438 
    439 	pTargetOid->objectType = IMA_OBJECT_TYPE_TARGET;
    440 	pTargetOid->ownerId = 1;
    441 	pTargetOid->objectSequenceNumber = target.te_entry.e_oid;
    442 
    443 	(void) close(fd);
    444 	return (IMA_STATUS_SUCCESS);
    445 }
    446 
    447 IMA_API	IMA_STATUS SUN_IMA_GetTargetProperties(
    448 		IMA_OID targetId,
    449 		SUN_IMA_TARGET_PROPERTIES *pProps
    450 )
    451 {
    452 	int		    fd;
    453 	int			status;
    454 	iscsi_property_t    prop;
    455 
    456 	if ((status = open_driver(&fd))) {
    457 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    458 	}
    459 
    460 	(void) memset(&prop, 0, sizeof (iscsi_property_t));
    461 	prop.p_vers = ISCSI_INTERFACE_VERSION;
    462 	prop.p_oid = (uint32_t)targetId.objectSequenceNumber;
    463 
    464 	if (ioctl(fd, ISCSI_TARGET_PROPS_GET, &prop) != 0) {
    465 		syslog(LOG_USER|LOG_DEBUG,
    466 		    "ISCSI_TARGET_PROPS_GET ioctl failed, errno: %d", errno);
    467 		(void) close(fd);
    468 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    469 	}
    470 
    471 	(void) mbstowcs(pProps->imaProps.name,
    472 	    (char *)prop.p_name, IMA_NODE_NAME_LEN);
    473 	(void) memset(pProps->imaProps.alias, 0,
    474 	    (sizeof (IMA_WCHAR) * SUN_IMA_NODE_ALIAS_LEN));
    475 	if (prop.p_alias_len > 0) {
    476 		(void) mbstowcs(pProps->imaProps.alias, (char *)prop.p_alias,
    477 		    SUN_IMA_NODE_ALIAS_LEN);
    478 	}
    479 
    480 	/* Initialize the discovery method to unknown method. */
    481 	pProps->imaProps.discoveryMethodFlags =
    482 	    IMA_TARGET_DISCOVERY_METHOD_UNKNOWN;
    483 	if (!((prop.p_discovery & iSCSIDiscoveryMethodStatic) ^
    484 	    iSCSIDiscoveryMethodStatic)) {
    485 		pProps->imaProps.discoveryMethodFlags |=
    486 		    IMA_TARGET_DISCOVERY_METHOD_STATIC;
    487 	}
    488 
    489 	if (!((prop.p_discovery & iSCSIDiscoveryMethodSLP) ^
    490 	    iSCSIDiscoveryMethodSLP)) {
    491 		pProps->imaProps.discoveryMethodFlags |=
    492 		    IMA_TARGET_DISCOVERY_METHOD_SLP;
    493 	}
    494 
    495 	if (!((prop.p_discovery & iSCSIDiscoveryMethodISNS) ^
    496 	    iSCSIDiscoveryMethodISNS)) {
    497 		pProps->imaProps.discoveryMethodFlags |=
    498 		    iSCSIDiscoveryMethodISNS;
    499 	}
    500 
    501 	if (!((prop.p_discovery & iSCSIDiscoveryMethodSendTargets) ^
    502 	    iSCSIDiscoveryMethodSendTargets)) {
    503 		pProps->imaProps.discoveryMethodFlags |=
    504 		    iSCSIDiscoveryMethodSendTargets;
    505 	}
    506 
    507 	if (prop.p_tpgt_conf == ISCSI_DEFAULT_TPGT) {
    508 		pProps->defaultTpgtConf = IMA_TRUE;
    509 		pProps->tpgtConf = 0;
    510 	} else {
    511 		pProps->defaultTpgtConf = IMA_FALSE;
    512 		pProps->tpgtConf = prop.p_tpgt_conf;
    513 	}
    514 
    515 	if (prop.p_tpgt_nego == ISCSI_DEFAULT_TPGT) {
    516 		pProps->defaultTpgtNego = IMA_TRUE;
    517 		pProps->tpgtNego = 0;
    518 	} else {
    519 		pProps->defaultTpgtNego = IMA_FALSE;
    520 		pProps->tpgtNego = prop.p_tpgt_nego;
    521 	}
    522 
    523 	bcopy(prop.p_isid, pProps->isid, ISCSI_ISID_LEN);
    524 
    525 	(void) close(fd);
    526 	return (IMA_STATUS_SUCCESS);
    527 }
    528 
    529 /*
    530  * This function only sets CHAP params since we only support CHAP for now.
    531  */
    532 IMA_STATUS SUN_IMA_SetTargetAuthParams(
    533     IMA_OID targetOid,
    534     IMA_AUTHMETHOD method,
    535     const IMA_INITIATOR_AUTHPARMS *pParms
    536 )
    537 {
    538 	int fd;
    539 	iscsi_chap_props_t  chap_p;
    540 
    541 	if (method != IMA_AUTHMETHOD_CHAP)
    542 		return (IMA_ERROR_INVALID_PARAMETER);
    543 
    544 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
    545 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
    546 		    ISCSI_DRIVER_DEVCTL, errno);
    547 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    548 	}
    549 
    550 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
    551 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
    552 	chap_p.c_oid = (uint32_t)targetOid.objectSequenceNumber;
    553 
    554 	chap_p.c_user_len =
    555 	    pParms->chapParms.nameLength;
    556 	(void) memcpy(chap_p.c_user,
    557 	    pParms->chapParms.name, chap_p.c_user_len);
    558 
    559 	chap_p.c_secret_len =
    560 	    pParms->chapParms.challengeSecretLength;
    561 	(void) memcpy(chap_p.c_secret,
    562 	    pParms->chapParms.challengeSecret,
    563 	    chap_p.c_secret_len);
    564 
    565 	if (ioctl(fd, ISCSI_CHAP_SET, &chap_p) != 0) {
    566 		syslog(LOG_USER|LOG_DEBUG,
    567 		    "ISCSI_CHAP_SET ioctl failed, errno: %d", errno);
    568 		(void) close(fd);
    569 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    570 	}
    571 
    572 	return (IMA_STATUS_SUCCESS);
    573 }
    574 
    575 IMA_STATUS SUN_IMA_GetTargetAuthMethods(
    576     IMA_OID		lhbaOid,
    577     IMA_OID		targetOid,
    578     IMA_UINT	*pMethodCount,
    579     IMA_AUTHMETHOD *pMethodList
    580 )
    581 {
    582 	if (getAuthMethods(targetOid, pMethodCount, pMethodList)
    583 	    != IMA_STATUS_SUCCESS) {
    584 		return (getAuthMethods(lhbaOid, pMethodCount, pMethodList));
    585 	}
    586 	return (IMA_STATUS_SUCCESS);
    587 }
    588 
    589 IMA_STATUS SUN_IMA_SetInitiatorRadiusConfig(
    590 		IMA_OID	lhbaOid,
    591 		SUN_IMA_RADIUS_CONFIG *config
    592 )
    593 {
    594 	int			af;
    595 	int			fd;
    596 	int			status;
    597 	iscsi_radius_props_t	radius;
    598 	union {
    599 		struct in_addr	u_in4;
    600 		struct in6_addr	u_in6;
    601 	}	radius_in;
    602 
    603 	if ((status = open_driver(&fd))) {
    604 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    605 	}
    606 
    607 	(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
    608 	radius.r_vers = ISCSI_INTERFACE_VERSION;
    609 	radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
    610 	/* Get first because other data fields may already exist */
    611 	if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
    612 		/* EMPTY */
    613 		/* It's fine if other data fields are not there. */
    614 	}
    615 
    616 	if (config->isIpv6 == IMA_TRUE) {
    617 		af = AF_INET6;
    618 	} else {
    619 		af = AF_INET;
    620 	}
    621 
    622 	if (inet_pton(af, config->hostnameIpAddress, &radius_in.u_in4) != 1) {
    623 		return (IMA_ERROR_INVALID_PARAMETER);
    624 	}
    625 
    626 	switch (af) {
    627 		case AF_INET:
    628 			radius.r_addr.u_in4.s_addr = radius_in.u_in4.s_addr;
    629 			radius.r_insize = sizeof (struct in_addr);
    630 			break;
    631 		case AF_INET6:
    632 			(void) memcpy(radius.r_addr.u_in6.s6_addr,
    633 			    radius_in.u_in6.s6_addr, 16);
    634 			radius.r_insize = sizeof (struct in6_addr);
    635 			break;
    636 	}
    637 	radius.r_port = config->port;
    638 	radius.r_radius_config_valid = B_TRUE;
    639 	/* Allow resetting the RADIUS shared secret to NULL */
    640 	if (config->sharedSecretValid == IMA_TRUE) {
    641 		radius.r_shared_secret_len = config->sharedSecretLength;
    642 		(void) memset(&radius.r_shared_secret[0], 0,
    643 		    MAX_RAD_SHARED_SECRET_LEN);
    644 		(void) memcpy(&radius.r_shared_secret[0], config->sharedSecret,
    645 		    config->sharedSecretLength);
    646 	}
    647 
    648 	if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) {
    649 		syslog(LOG_USER|LOG_DEBUG,
    650 		    "ISCSI_RADIUS_SET ioctl failed, errno: %d", errno);
    651 		(void) close(fd);
    652 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    653 	}
    654 
    655 	(void) close(fd);
    656 	return (IMA_STATUS_SUCCESS);
    657 }
    658 
    659 IMA_STATUS SUN_IMA_GetInitiatorRadiusConfig(
    660 		IMA_OID	lhbaOid,
    661 		SUN_IMA_RADIUS_CONFIG *config
    662 )
    663 {
    664 	int			af;
    665 	int			fd;
    666 	int			status;
    667 	iscsi_radius_props_t	radius;
    668 
    669 	if ((status = open_driver(&fd))) {
    670 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    671 	}
    672 
    673 	(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
    674 	radius.r_vers = ISCSI_INTERFACE_VERSION;
    675 	radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
    676 
    677 	if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
    678 		(void) close(fd);
    679 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    680 	}
    681 
    682 	(void) memset(config, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
    683 	if (radius.r_insize == sizeof (struct in_addr)) {
    684 		/* IPv4 */
    685 		af = AF_INET;
    686 	} else if (radius.r_insize == sizeof (struct in6_addr)) {
    687 		/* IPv6 */
    688 		af = AF_INET6;
    689 	} else {
    690 		/*
    691 		 * It's legitimate that the existing RADIUS record does not
    692 		 * have configuration data.
    693 		 */
    694 		config->hostnameIpAddress[0] = '\0';
    695 		config->port = 0;
    696 		(void) close(fd);
    697 		return (IMA_STATUS_SUCCESS);
    698 	}
    699 	(void) inet_ntop(af, (void *)&radius.r_addr.u_in4,
    700 	    config->hostnameIpAddress, 256);
    701 	config->port = radius.r_port;
    702 	(void) memcpy(config->sharedSecret, &radius.r_shared_secret[0],
    703 	    radius.r_shared_secret_len);
    704 	config->sharedSecretLength = radius.r_shared_secret_len;
    705 	config->sharedSecretValid = B_TRUE;
    706 
    707 	(void) close(fd);
    708 	return (IMA_STATUS_SUCCESS);
    709 }
    710 
    711 IMA_STATUS SUN_IMA_SetInitiatorRadiusAccess(
    712     IMA_OID lhbaOid,
    713     IMA_BOOL radiusAccess
    714 )
    715 {
    716 	int			fd;
    717 	int			status;
    718 	iscsi_radius_props_t	radius;
    719 
    720 	if ((status = open_driver(&fd))) {
    721 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    722 	}
    723 
    724 	(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
    725 	radius.r_vers = ISCSI_INTERFACE_VERSION;
    726 	radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
    727 	/* Get first because other data fields may already exist */
    728 	if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
    729 		if (radiusAccess == IMA_TRUE) {
    730 			/*
    731 			 * Cannot enable RADIUS if no RADIUS configuration
    732 			 * can be found.
    733 			 */
    734 			syslog(LOG_USER|LOG_DEBUG,
    735 			    "RADIUS config data not found - "
    736 			    "cannot enable RADIUS, errno: %d", errno);
    737 			(void) close(fd);
    738 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    739 		} else {
    740 			/* EMPTY */
    741 			/* Otherwise it's fine to disable RADIUS */
    742 		}
    743 	}
    744 
    745 	if ((radius.r_insize != sizeof (struct in_addr)) &&
    746 		(radius.r_insize != sizeof (struct in6_addr))) {
    747 		/*
    748 		 * Cannot enable RADIUS if no RADIUS configuration
    749 		 * can be found.
    750 		 */
    751 		if (radiusAccess == IMA_TRUE) {
    752 			syslog(LOG_USER|LOG_DEBUG,
    753 				"RADIUS config data not found - "
    754 				"cannot enable RADIUS");
    755 			(void) close(fd);
    756 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    757 		}
    758 	}
    759 
    760 	radius.r_radius_access = (radiusAccess == IMA_TRUE) ?
    761 	    B_TRUE : B_FALSE;
    762 
    763 	if (ioctl(fd, ISCSI_RADIUS_SET, &radius) != 0) {
    764 		syslog(LOG_USER|LOG_DEBUG,
    765 		    "ISCSI_RADIUS_SET ioctl failed, errno: %d", errno);
    766 		(void) close(fd);
    767 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    768 	}
    769 
    770 	(void) close(fd);
    771 	return (IMA_STATUS_SUCCESS);
    772 }
    773 
    774 IMA_STATUS SUN_IMA_GetInitiatorRadiusAccess(
    775     IMA_OID lhbaOid,
    776     IMA_BOOL *radiusAccess
    777 )
    778 {
    779 	int			fd;
    780 	int			status;
    781 	iscsi_radius_props_t	radius;
    782 
    783 	if ((status = open_driver(&fd))) {
    784 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    785 	}
    786 
    787 	(void) memset(&radius, 0, sizeof (iscsi_radius_props_t));
    788 	radius.r_vers = ISCSI_INTERFACE_VERSION;
    789 	radius.r_oid = (uint32_t)lhbaOid.objectSequenceNumber;
    790 
    791 	if (ioctl(fd, ISCSI_RADIUS_GET, &radius) != 0) {
    792 		(void) close(fd);
    793 		if (errno == ENOENT) {
    794 			return (IMA_ERROR_OBJECT_NOT_FOUND);
    795 		} else {
    796 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    797 		}
    798 	}
    799 
    800 	*radiusAccess = (radius.r_radius_access == B_TRUE) ?
    801 	    IMA_TRUE : IMA_FALSE;
    802 
    803 	(void) close(fd);
    804 	return (IMA_STATUS_SUCCESS);
    805 }
    806 
    807 IMA_STATUS SUN_IMA_SendTargets(
    808     IMA_NODE_NAME nodeName,
    809     IMA_TARGET_ADDRESS address,
    810     SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
    811 )
    812 {
    813 	char	*colonPos;
    814 	char	discAddrStr[256];
    815 	char	nodeNameStr[ISCSI_MAX_NAME_LEN];
    816 	int	fd;
    817 	int	ctr;
    818 	int	stl_sz;
    819 	int status;
    820 	iscsi_sendtgts_list_t	*stl_hdr = NULL;
    821 	IMA_BOOL		retry = IMA_TRUE;
    822 	/* LINTED */
    823 	IMA_IP_ADDRESS	    *ipAddr;
    824 
    825 #define	SENDTGTS_DEFAULT_NUM_TARGETS	10
    826 
    827 	stl_sz = sizeof (*stl_hdr) + ((SENDTGTS_DEFAULT_NUM_TARGETS - 1) *
    828 	    sizeof (iscsi_sendtgts_entry_t));
    829 	stl_hdr = (iscsi_sendtgts_list_t *)calloc(1, stl_sz);
    830 	if (stl_hdr == NULL) {
    831 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
    832 	}
    833 	stl_hdr->stl_entry.e_vers = ISCSI_INTERFACE_VERSION;
    834 	stl_hdr->stl_in_cnt = SENDTGTS_DEFAULT_NUM_TARGETS;
    835 
    836 	(void) wcstombs(nodeNameStr, nodeName, ISCSI_MAX_NAME_LEN);
    837 
    838 	colonPos = strchr(discAddrStr, ':');
    839 	if (colonPos == NULL) {
    840 		/* IPv4 */
    841 		stl_hdr->stl_entry.e_insize = sizeof (struct in_addr);
    842 	} else {
    843 		/* IPv6 */
    844 		stl_hdr->stl_entry.e_insize = sizeof (struct in6_addr);
    845 	}
    846 
    847 	ipAddr = &address.hostnameIpAddress.id.ipAddress;
    848 
    849 	bcopy(address.hostnameIpAddress.id.ipAddress.ipAddress,
    850 	    &stl_hdr->stl_entry.e_u, sizeof (ipAddr->ipAddress));
    851 
    852 	stl_hdr->stl_entry.e_port = address.portNumber;
    853 
    854 	if ((status = open_driver(&fd))) {
    855 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    856 	}
    857 
    858 retry_sendtgts:
    859 	/*
    860 	 * Issue ioctl to obtain the SendTargets list
    861 	 */
    862 	if (ioctl(fd, ISCSI_SENDTGTS_GET, stl_hdr) != 0) {
    863 		syslog(LOG_USER|LOG_DEBUG,
    864 		    "ISCSI_SENDTGTS_GET ioctl failed, errno: %d", errno);
    865 		(void) close(fd);
    866 		free(stl_hdr);
    867 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    868 	}
    869 
    870 	/* check if all targets received */
    871 	if (stl_hdr->stl_in_cnt < stl_hdr->stl_out_cnt) {
    872 		if (retry == IMA_TRUE) {
    873 			stl_sz = sizeof (*stl_hdr) +
    874 			    ((stl_hdr->stl_out_cnt - 1) *
    875 			    sizeof (iscsi_sendtgts_entry_t));
    876 			stl_hdr = (iscsi_sendtgts_list_t *)
    877 			    realloc(stl_hdr, stl_sz);
    878 			if (stl_hdr == NULL) {
    879 				(void) close(fd);
    880 				return (IMA_ERROR_INSUFFICIENT_MEMORY);
    881 			}
    882 			stl_hdr->stl_in_cnt = stl_hdr->stl_out_cnt;
    883 			retry = IMA_FALSE;
    884 			goto retry_sendtgts;
    885 		} else {
    886 			/*
    887 			 * don't retry after 2 attempts.  The target list
    888 			 * shouldn't continue to growing. Justs continue
    889 			 * on and display what was found.
    890 			 */
    891 			syslog(LOG_USER|LOG_DEBUG,
    892 			    "ISCSI_SENDTGTS_GET overflow: "
    893 			    "failed to obtain all targets");
    894 			stl_hdr->stl_out_cnt = stl_hdr->stl_in_cnt;
    895 		}
    896 	}
    897 
    898 	(void) close(fd);
    899 
    900 	/* allocate for caller return buffer */
    901 	*ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1,
    902 	    sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) +
    903 	    stl_hdr->stl_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
    904 	if (*ppList == NULL) {
    905 		free(stl_hdr);
    906 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
    907 	}
    908 
    909 	(*ppList)->keyCount = stl_hdr->stl_out_cnt;
    910 
    911 	for (ctr = 0; ctr < stl_hdr->stl_out_cnt; ctr++) {
    912 		(void) mbstowcs((*ppList)->keys[ctr].name,
    913 		    (char *)stl_hdr->stl_list[ctr].ste_name,
    914 		    IMA_NODE_NAME_LEN);
    915 
    916 		(*ppList)->keys[ctr].tpgt = stl_hdr->stl_list[ctr].ste_tpgt;
    917 
    918 		(*ppList)->keys[ctr].address.portNumber =
    919 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_port;
    920 
    921 		if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
    922 		    sizeof (struct in_addr)) {
    923 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
    924 			    IMA_TRUE;
    925 		} else if (stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize ==
    926 		    sizeof (struct in6_addr)) {
    927 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
    928 			    IMA_FALSE;
    929 		} else {
    930 			free(stl_hdr);
    931 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    932 		}
    933 
    934 		(void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
    935 		    &(stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_addr),
    936 		    stl_hdr->stl_list[ctr].ste_ipaddr.a_addr.i_insize);
    937 	}
    938 	free(stl_hdr);
    939 
    940 	return (IMA_STATUS_SUCCESS);
    941 }
    942 
    943 IMA_STATUS SUN_IMA_SetTargetBidirAuthFlag(
    944     IMA_OID targetOid,
    945     IMA_BOOL *bidirAuthFlag
    946 )
    947 {
    948 	int fd;
    949 	int status;
    950 	iscsi_auth_props_t auth;
    951 
    952 	if ((status = open_driver(&fd))) {
    953 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    954 	}
    955 
    956 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
    957 	auth.a_vers = ISCSI_INTERFACE_VERSION;
    958 	auth.a_oid = (uint32_t)targetOid.objectSequenceNumber;
    959 	/* Get first because other data fields may already exist */
    960 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
    961 		/* EMPTY */
    962 		/* It is fine if there is no other data fields. */
    963 	}
    964 	auth.a_bi_auth = (*bidirAuthFlag == IMA_TRUE) ? B_TRUE : B_FALSE;
    965 	if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
    966 		syslog(LOG_USER|LOG_DEBUG,
    967 		    "ISCSI_AUTH_SET ioctl failed, errno: %d", errno);
    968 		(void) close(fd);
    969 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    970 	}
    971 
    972 	(void) close(fd);
    973 	return (IMA_STATUS_SUCCESS);
    974 }
    975 
    976 IMA_STATUS SUN_IMA_GetTargetBidirAuthFlag(
    977     IMA_OID targetOid,
    978     IMA_BOOL *bidirAuthFlag
    979 )
    980 {
    981 	int fd;
    982 	int status;
    983 	iscsi_auth_props_t auth;
    984 
    985 	if ((status = open_driver(&fd))) {
    986 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
    987 	}
    988 
    989 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
    990 	auth.a_vers = ISCSI_INTERFACE_VERSION;
    991 	auth.a_oid = (uint32_t)targetOid.objectSequenceNumber;
    992 
    993 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
    994 		(void) close(fd);
    995 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
    996 	}
    997 
    998 	*bidirAuthFlag = (auth.a_bi_auth == B_TRUE) ?
    999 	    IMA_TRUE : IMA_FALSE;
   1000 
   1001 	(void) close(fd);
   1002 	return (IMA_STATUS_SUCCESS);
   1003 }
   1004 
   1005 IMA_STATUS SUN_IMA_CreateTargetOid(
   1006     IMA_NODE_NAME targetName,
   1007     IMA_OID *targetOid
   1008 )
   1009 {
   1010 	int	    fd;
   1011 	int		status;
   1012 	iscsi_oid_t oid;
   1013 
   1014 	if ((status = open_driver(&fd))) {
   1015 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1016 	}
   1017 
   1018 	(void) memset(&oid, 0, sizeof (iscsi_oid_t));
   1019 	(void) wcstombs((char *)oid.o_name, targetName, ISCSI_MAX_NAME_LEN);
   1020 	oid.o_tpgt = ISCSI_DEFAULT_TPGT;
   1021 	oid.o_vers = ISCSI_INTERFACE_VERSION;
   1022 	if (ioctl(fd, ISCSI_CREATE_OID, &oid) == -1) {
   1023 		syslog(LOG_USER|LOG_DEBUG,
   1024 		    "ISCSI_CREATE_OID ioctl failed, errno: %d", errno);
   1025 		(void) close(fd);
   1026 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1027 	}
   1028 
   1029 	targetOid->objectType = IMA_OBJECT_TYPE_TARGET;
   1030 	targetOid->ownerId = 1;
   1031 	targetOid->objectSequenceNumber = oid.o_oid;
   1032 
   1033 	(void) close(fd);
   1034 	return (IMA_STATUS_SUCCESS);
   1035 }
   1036 
   1037 IMA_STATUS SUN_IMA_RemoveTargetParam(
   1038 		IMA_OID targetOid
   1039 )
   1040 {
   1041 	entry_t	entry;
   1042 	int	fd;
   1043 	int status;
   1044 	iscsi_auth_props_t auth_p;
   1045 	iscsi_chap_props_t chap_p;
   1046 
   1047 	if ((status = open_driver(&fd))) {
   1048 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1049 	}
   1050 
   1051 	(void) memset(&entry, 0, sizeof (entry_t));
   1052 	entry.e_vers = ISCSI_INTERFACE_VERSION;
   1053 	entry.e_oid = (uint32_t)targetOid.objectSequenceNumber;
   1054 	if (ioctl(fd, ISCSI_TARGET_PARAM_CLEAR, &entry)) {
   1055 		/*
   1056 		 * It could be that the target exists but the associated
   1057 		 * target_param does not, and that is legitimate.
   1058 		 */
   1059 		syslog(LOG_USER|LOG_DEBUG,
   1060 		    "ISCSI_TARGET_PARAM_CLEAR ioctl failed, errno: %d", errno);
   1061 	}
   1062 
   1063 	/* Issue ISCSI_CHAP_CLEAR ioctl */
   1064 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
   1065 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
   1066 	chap_p.c_oid = (uint32_t)targetOid.objectSequenceNumber;
   1067 	if (ioctl(fd, ISCSI_CHAP_CLEAR, &chap_p) != 0) {
   1068 		/*
   1069 		 * It could be that the CHAP of this target has never
   1070 		 * been set.
   1071 		 */
   1072 		syslog(LOG_USER|LOG_DEBUG,
   1073 		    "ISCSI_CHAP_CLEAR ioctl failed, errno: %d", errno);
   1074 	}
   1075 
   1076 	/*
   1077 	 * Issue ISCSI_AUTH_CLEAR ioctl, in which the authentication information
   1078 	 * is removed and the target that is not discovered by initiator
   1079 	 * is removed from the memory. So this ioctl should be called at last
   1080 	 */
   1081 	(void) memset(&auth_p, 0, sizeof (iscsi_auth_props_t));
   1082 	auth_p.a_vers = ISCSI_INTERFACE_VERSION;
   1083 	auth_p.a_oid = (uint32_t)targetOid.objectSequenceNumber;
   1084 	if (ioctl(fd, ISCSI_AUTH_CLEAR, &auth_p) != 0) {
   1085 		/*
   1086 		 * It could be that the auth data of this target has
   1087 		 * never been set.
   1088 		 */
   1089 		syslog(LOG_USER|LOG_DEBUG,
   1090 		    "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
   1091 	}
   1092 
   1093 	(void) close(fd);
   1094 	return (IMA_STATUS_SUCCESS);
   1095 }
   1096 
   1097 IMA_API IMA_STATUS SUN_IMA_SetHeaderDigest(
   1098 	IMA_OID oid,
   1099 	IMA_UINT algorithmCount,
   1100 	const SUN_IMA_DIGEST_ALGORITHM *algorithmList
   1101 )
   1102 {
   1103 	IMA_MIN_MAX_VALUE mv;
   1104 	uint32_t digest_algorithm;
   1105 
   1106 	/* We only support one preference of digest algorithm. */
   1107 	if (algorithmCount > 1) {
   1108 		syslog(LOG_USER|LOG_DEBUG,
   1109 		    "More than one digest algorithm specified.");
   1110 		return (IMA_ERROR_NOT_SUPPORTED);
   1111 	}
   1112 	switch (algorithmList[0]) {
   1113 	case SUN_IMA_DIGEST_NONE:
   1114 		digest_algorithm = ISCSI_DIGEST_NONE;
   1115 		break;
   1116 	case SUN_IMA_DIGEST_CRC32:
   1117 		digest_algorithm = ISCSI_DIGEST_CRC32C;
   1118 		break;
   1119 	default:
   1120 		digest_algorithm = ISCSI_DIGEST_NONE;
   1121 		break;
   1122 	}
   1123 	mv.currentValue = digest_algorithm;
   1124 	return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
   1125 	    ISCSI_LOGIN_PARAM_HEADER_DIGEST));
   1126 }
   1127 
   1128 IMA_API IMA_STATUS SUN_IMA_SetDataDigest(
   1129 	IMA_OID oid,
   1130 	IMA_UINT algorithmCount,
   1131 	const SUN_IMA_DIGEST_ALGORITHM *algorithmList
   1132 )
   1133 {
   1134 	IMA_MIN_MAX_VALUE mv;
   1135 	uint32_t digest_algorithm;
   1136 
   1137 	/* We only support one preference of digest algorithm. */
   1138 	if (algorithmCount > 1) {
   1139 		syslog(LOG_USER|LOG_DEBUG,
   1140 		    "More than one digest algorithm specified.");
   1141 		return (IMA_ERROR_NOT_SUPPORTED);
   1142 	}
   1143 	switch (algorithmList[0]) {
   1144 	case SUN_IMA_DIGEST_NONE:
   1145 		digest_algorithm = ISCSI_DIGEST_NONE;
   1146 		break;
   1147 	case SUN_IMA_DIGEST_CRC32:
   1148 		digest_algorithm = ISCSI_DIGEST_CRC32C;
   1149 		break;
   1150 	default:
   1151 		digest_algorithm = ISCSI_DIGEST_NONE;
   1152 		break;
   1153 	}
   1154 	mv.currentValue = digest_algorithm;
   1155 	return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
   1156 	    ISCSI_LOGIN_PARAM_DATA_DIGEST));
   1157 }
   1158 
   1159 IMA_API IMA_STATUS SUN_IMA_GetHeaderDigest(
   1160 	IMA_OID oid,
   1161 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
   1162 )
   1163 {
   1164 	return (getDigest(oid, ISCSI_LOGIN_PARAM_HEADER_DIGEST, algorithm));
   1165 }
   1166 
   1167 IMA_API IMA_STATUS SUN_IMA_GetDataDigest(
   1168 	IMA_OID oid,
   1169 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
   1170 )
   1171 {
   1172 	return (getDigest(oid, ISCSI_LOGIN_PARAM_DATA_DIGEST, algorithm));
   1173 }
   1174 
   1175 typedef struct walk_devlink {
   1176 	char *path;
   1177 	size_t len;
   1178 	char **linkpp;
   1179 } walk_devlink_t;
   1180 
   1181 IMA_STATUS SUN_IMA_GetLuProperties(
   1182 		IMA_OID luId,
   1183 		SUN_IMA_LU_PROPERTIES *pProps
   1184 )
   1185 {
   1186 	IMA_STATUS		status;
   1187 	iscsi_lun_list_t	*pLunList;
   1188 	int			j;
   1189 	IMA_BOOL		lunMatch = IMA_FALSE;
   1190 	int			fd;
   1191 	int			openStatus;
   1192 	iscsi_lun_props_t	lun;
   1193 	di_devlink_handle_t	hdl;
   1194 	walk_devlink_t		warg;
   1195 	char			*minor_path, *devlinkp, lunpath[MAXPATHLEN];
   1196 
   1197 	if (luId.objectType != IMA_OBJECT_TYPE_LU) {
   1198 		return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
   1199 	}
   1200 
   1201 	/*
   1202 	 * get list of lun oids for all targets
   1203 	 */
   1204 	status = get_target_lun_oid_list(NULL, &pLunList);
   1205 	if (!IMA_SUCCESS(status)) {
   1206 		return (status);
   1207 	}
   1208 	for (j = 0; j < pLunList->ll_out_cnt; j++) {
   1209 		/*
   1210 		 * for each lun, check if match is found
   1211 		 */
   1212 		if (pLunList->ll_luns[j].l_oid == luId.objectSequenceNumber) {
   1213 			/*
   1214 			 * match found, break out of lun loop
   1215 			 */
   1216 			lunMatch = IMA_TRUE;
   1217 			break;
   1218 		}
   1219 	}
   1220 
   1221 	if (lunMatch == IMA_TRUE) {
   1222 		(void) memset(&lun, 0, sizeof (iscsi_lun_props_t));
   1223 		lun.lp_vers = ISCSI_INTERFACE_VERSION;
   1224 		lun.lp_tgt_oid = pLunList->ll_luns[j].l_tgt_oid;
   1225 		lun.lp_oid = pLunList->ll_luns[j].l_oid;
   1226 	}
   1227 
   1228 	free(pLunList);
   1229 
   1230 	if (lunMatch == IMA_FALSE) {
   1231 		return (IMA_ERROR_OBJECT_NOT_FOUND);
   1232 	}
   1233 
   1234 	/*
   1235 	 * get lun properties
   1236 	 */
   1237 	if ((openStatus = open_driver(&fd))) {
   1238 		return (SUN_IMA_ERROR_SYSTEM_ERROR | openStatus);
   1239 	}
   1240 
   1241 	if (ioctl(fd, ISCSI_LUN_PROPS_GET, &lun)) {
   1242 		syslog(LOG_USER|LOG_DEBUG,
   1243 		    "ISCSI_LUN_PROPS_GET ioctl failed, errno: %d", errno);
   1244 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1245 	}
   1246 
   1247 	(void) close(fd);
   1248 
   1249 	/*
   1250 	 * set property values
   1251 	 */
   1252 	pProps->imaProps.associatedTargetOid.objectType =
   1253 	    IMA_OBJECT_TYPE_TARGET;
   1254 	pProps->imaProps.associatedTargetOid.ownerId = 1;
   1255 	pProps->imaProps.associatedTargetOid.objectSequenceNumber = lun.lp_oid;
   1256 	pProps->imaProps.targetLun = (IMA_UINT64)lun.lp_num;
   1257 	(void) strncpy(pProps->vendorId, lun.lp_vid, SUN_IMA_LU_VENDOR_ID_LEN);
   1258 	(void) strncpy(pProps->productId, lun.lp_pid,
   1259 	    SUN_IMA_LU_PRODUCT_ID_LEN);
   1260 	/*
   1261 	 * lun.lp_status is defined as
   1262 	 *	LunValid = 0
   1263 	 *	LunDoesNotExist = 1
   1264 	 * IMA_LU_PROPS.exposedtoOS is defined as an IMA_BOOL
   1265 	 *	IMA_TRUE = 1
   1266 	 *	IMA_FALSE = 0
   1267 	 */
   1268 	pProps->imaProps.exposedToOs = !lun.lp_status;
   1269 	if (gmtime_r(&lun.lp_time_online, &pProps->imaProps.timeExposedToOs)
   1270 	    == NULL) {
   1271 		(void) memset(&pProps->imaProps.timeExposedToOs, 0,
   1272 		    sizeof (pProps->imaProps.timeExposedToOs));
   1273 	}
   1274 
   1275 	if (lun.lp_status == LunValid) {
   1276 		if ((strlen(lun.lp_pathname) + strlen("/devices")) >
   1277 		    (MAXPATHLEN -1)) {
   1278 			/*
   1279 			 * lun.lp_pathname length too long
   1280 			 */
   1281 			pProps->imaProps.osDeviceNameValid = IMA_FALSE;
   1282 			pProps->imaProps.osParallelIdsValid = IMA_FALSE;
   1283 			return (IMA_STATUS_SUCCESS);
   1284 		}
   1285 		if ((strstr(lun.lp_pathname, "st@") != NULL) ||
   1286 		    (strstr(lun.lp_pathname, "tape@") != NULL)) {
   1287 			(void) strlcat(lun.lp_pathname, ":n", MAXPATHLEN);
   1288 		} else if ((strstr(lun.lp_pathname, "sd@") != NULL) ||
   1289 		    (strstr(lun.lp_pathname, "ssd@") != NULL) ||
   1290 		    (strstr(lun.lp_pathname, "disk@") != NULL)) {
   1291 			/*
   1292 			 * modify returned pathname to obtain the 2nd slice
   1293 			 * of the raw disk
   1294 			 */
   1295 			(void) strlcat(lun.lp_pathname, ":c,raw", MAXPATHLEN);
   1296 		} else if ((strstr(lun.lp_pathname, "ses@") != NULL) ||
   1297 		    (strstr(lun.lp_pathname, "enclosure@") != NULL)) {
   1298 			(void) strlcat(lun.lp_pathname, ":0", MAXPATHLEN);
   1299 		}
   1300 
   1301 		(void) snprintf(lunpath, sizeof (lun.lp_pathname),
   1302 		    "/devices%s", lun.lp_pathname);
   1303 		if (strchr(lunpath, ':')) {
   1304 			minor_path = lunpath;
   1305 			if (strstr(minor_path, "/devices") != NULL) {
   1306 				minor_path = lunpath +
   1307 				    strlen("/devices");
   1308 			} else {
   1309 				minor_path = lunpath;
   1310 			}
   1311 			warg.path = NULL;
   1312 		} else {
   1313 			minor_path = NULL;
   1314 			warg.len = strlen(lunpath);
   1315 			warg.path = lunpath;
   1316 		}
   1317 		devlinkp = NULL;
   1318 		warg.linkpp = &devlinkp;
   1319 
   1320 		/*
   1321 		 * Pathname returned by driver is the physical device path.
   1322 		 * This name needs to be converted to the OS device name.
   1323 		 */
   1324 		if (hdl = di_devlink_init(lun.lp_pathname, DI_MAKE_LINK)) {
   1325 			pProps->imaProps.osDeviceName[0] = L'\0';
   1326 			(void) di_devlink_walk(hdl, NULL, minor_path,
   1327 			    DI_PRIMARY_LINK, (void *)&warg, get_lun_devlink);
   1328 			if (devlinkp != NULL) {
   1329 				/* OS device name synchronously made */
   1330 				(void) mbstowcs(pProps->imaProps.osDeviceName,
   1331 				    devlinkp, MAXPATHLEN);
   1332 				free(devlinkp);
   1333 				pProps->imaProps.osDeviceNameValid = IMA_TRUE;
   1334 			} else {
   1335 				pProps->imaProps.osDeviceNameValid = IMA_FALSE;
   1336 			}
   1337 
   1338 			(void) di_devlink_fini(&hdl);
   1339 
   1340 		} else {
   1341 			pProps->imaProps.osDeviceNameValid = IMA_FALSE;
   1342 		}
   1343 
   1344 	} else {
   1345 		pProps->imaProps.osDeviceNameValid = IMA_FALSE;
   1346 	}
   1347 
   1348 	pProps->imaProps.osParallelIdsValid = IMA_FALSE;
   1349 
   1350 	return (IMA_STATUS_SUCCESS);
   1351 }
   1352 
   1353 static int
   1354 get_lun_devlink(di_devlink_t link, void *arg)
   1355 {
   1356 	walk_devlink_t *warg = (walk_devlink_t *)arg;
   1357 	if (warg->path) {
   1358 		char *content = (char *)di_devlink_content(link);
   1359 		char *start = strstr(content, "/devices");
   1360 		if (start == NULL ||
   1361 		    strncmp(start, warg->path, warg->len) != 0 ||
   1362 		    start[warg->len] != ':')
   1363 			return (DI_WALK_CONTINUE);
   1364 	}
   1365 
   1366 	*(warg->linkpp) = strdup(di_devlink_path(link));
   1367 	return (DI_WALK_TERMINATE);
   1368 
   1369 }
   1370 
   1371 /*
   1372  * SUN_IMA_GetConnectionOidList -
   1373  *
   1374  * Non-IMA defined function.
   1375  */
   1376 IMA_API	IMA_STATUS SUN_IMA_GetConnOidList(
   1377 	IMA_OID			*oid,
   1378 	IMA_OID_LIST		**ppList
   1379 )
   1380 {
   1381 	IMA_STATUS		imaStatus;
   1382 	IMA_OID_LIST		*imaOidList;
   1383 	iscsi_conn_list_t	*iscsiConnList = NULL;
   1384 	int			i;
   1385 	size_t			allocLen;
   1386 
   1387 	if ((lhbaObjectId.objectType == oid->objectType) &&
   1388 	    (lhbaObjectId.ownerId == oid->ownerId) &&
   1389 	    (lhbaObjectId.objectSequenceNumber == oid->objectSequenceNumber)) {
   1390 		imaStatus = getConnOidList(NULL, &iscsiConnList);
   1391 	} else {
   1392 		if (oid->objectType == IMA_OBJECT_TYPE_TARGET) {
   1393 			imaStatus = getConnOidList(oid, &iscsiConnList);
   1394 		} else {
   1395 			return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
   1396 		}
   1397 	}
   1398 	if (imaStatus != IMA_STATUS_SUCCESS) {
   1399 		return (imaStatus);
   1400 	}
   1401 
   1402 	/*
   1403 	 * Based on the results a SUN_IMA_CONN_LIST structure is allocated.
   1404 	 */
   1405 	allocLen  = iscsiConnList->cl_out_cnt * sizeof (IMA_OID);
   1406 	allocLen += sizeof (IMA_OID_LIST) - sizeof (IMA_OID);
   1407 	imaOidList = (IMA_OID_LIST *)calloc(1, allocLen);
   1408 
   1409 	if (imaOidList == NULL) {
   1410 		free(iscsiConnList);
   1411 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1412 	}
   1413 
   1414 	/* The data is transfered from iscsiConnList to imaConnList. */
   1415 	imaOidList->oidCount = iscsiConnList->cl_out_cnt;
   1416 	for (i = 0; i < iscsiConnList->cl_out_cnt; i++) {
   1417 		imaOidList->oids[i].objectType = SUN_IMA_OBJECT_TYPE_CONN;
   1418 		imaOidList->oids[i].ownerId = 1;
   1419 		imaOidList->oids[i].objectSequenceNumber =
   1420 		    iscsiConnList->cl_list[i].c_oid;
   1421 	}
   1422 	/* The pointer to the SUN_IMA_CONN_LIST structure is returned. */
   1423 	*ppList = imaOidList;
   1424 
   1425 	free(iscsiConnList);
   1426 	return (IMA_STATUS_SUCCESS);
   1427 }
   1428 
   1429 /*
   1430  * SUN_IMA_GetConnProperties -
   1431  *
   1432  * Non-IMA defined function.
   1433  */
   1434 IMA_API	IMA_STATUS SUN_IMA_GetConnProperties(
   1435 	IMA_OID			*connOid,
   1436 	SUN_IMA_CONN_PROPERTIES	**pProps
   1437 )
   1438 {
   1439 	iscsi_conn_list_t	*pConnList;
   1440 	iscsi_conn_props_t	*pConnProps;
   1441 	/* LINTED */
   1442 	struct sockaddr_in6	*addrIn6;
   1443 	/* LINTED */
   1444 	struct sockaddr_in	*addrIn;
   1445 	SUN_IMA_CONN_PROPERTIES	*pImaConnProps;
   1446 	IMA_STATUS		imaStatus;
   1447 	int			i;
   1448 
   1449 	/* If there is any error *pProps should be set to NULL */
   1450 	*pProps = NULL;
   1451 
   1452 	pImaConnProps = (SUN_IMA_CONN_PROPERTIES *)calloc(1,
   1453 	    sizeof (SUN_IMA_CONN_PROPERTIES));
   1454 
   1455 	if (pImaConnProps == NULL) {
   1456 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1457 	}
   1458 
   1459 	imaStatus = getConnOidList(NULL, &pConnList);
   1460 
   1461 	if (imaStatus != IMA_STATUS_SUCCESS) {
   1462 		free(pImaConnProps);
   1463 		return (imaStatus);
   1464 	}
   1465 
   1466 	/*
   1467 	 * Walk the list returned to find our connection.
   1468 	 */
   1469 	for (i = 0; i < pConnList->cl_out_cnt; i++) {
   1470 
   1471 		if (pConnList->cl_list[i].c_oid ==
   1472 		    (uint32_t)connOid->objectSequenceNumber) {
   1473 
   1474 			/* This is our connection. */
   1475 			imaStatus = getConnProps(&pConnList->cl_list[i],
   1476 			    &pConnProps);
   1477 
   1478 			if (imaStatus != IMA_STATUS_SUCCESS) {
   1479 				free(pConnList);
   1480 				free(pImaConnProps);
   1481 				return (imaStatus);
   1482 			}
   1483 			pImaConnProps->connectionID = pConnProps->cp_cid;
   1484 
   1485 			/*
   1486 			 * Local Propeties
   1487 			 */
   1488 			if (pConnProps->cp_local.soa4.sin_family == AF_INET) {
   1489 
   1490 				pImaConnProps->local.ipAddress.ipv4Address =
   1491 				    IMA_TRUE;
   1492 				pImaConnProps->local.portNumber =
   1493 				    pConnProps->cp_local.soa4.sin_port;
   1494 				addrIn = &(pConnProps->cp_local.soa4);
   1495 				bcopy(&pConnProps->cp_local.soa4.sin_addr,
   1496 				    pImaConnProps->local.ipAddress.ipAddress,
   1497 				    sizeof (addrIn->sin_addr));
   1498 
   1499 			} else {
   1500 				pImaConnProps->local.ipAddress.ipv4Address =
   1501 				    IMA_FALSE;
   1502 				pImaConnProps->local.portNumber =
   1503 				    pConnProps->cp_local.soa6.sin6_port;
   1504 				addrIn6 = &(pConnProps->cp_local.soa6);
   1505 				bcopy(&pConnProps->cp_local.soa6.sin6_addr,
   1506 				    pImaConnProps->local.ipAddress.ipAddress,
   1507 				    sizeof (addrIn6->sin6_addr));
   1508 
   1509 			}
   1510 
   1511 			/*
   1512 			 * Peer Propeties
   1513 			 */
   1514 			if (pConnProps->cp_peer.soa4.sin_family == AF_INET) {
   1515 
   1516 				pImaConnProps->peer.ipAddress.ipv4Address =
   1517 				    IMA_TRUE;
   1518 				pImaConnProps->peer.portNumber =
   1519 				    pConnProps->cp_peer.soa4.sin_port;
   1520 				addrIn = &(pConnProps->cp_local.soa4);
   1521 				bcopy(&pConnProps->cp_peer.soa4.sin_addr,
   1522 				    pImaConnProps->peer.ipAddress.ipAddress,
   1523 				    sizeof (addrIn->sin_addr));
   1524 
   1525 			} else {
   1526 				pImaConnProps->peer.ipAddress.ipv4Address =
   1527 				    IMA_FALSE;
   1528 				pImaConnProps->peer.portNumber =
   1529 				    pConnProps->cp_peer.soa6.sin6_port;
   1530 
   1531 				addrIn6 = &pConnProps->cp_local.soa6;
   1532 				bcopy(&pConnProps->cp_peer.soa6.sin6_addr,
   1533 				    pImaConnProps->peer.ipAddress.ipAddress,
   1534 				    sizeof (addrIn6->sin6_addr));
   1535 			}
   1536 
   1537 
   1538 			pImaConnProps->valuesValid =
   1539 			    pConnProps->cp_params_valid;
   1540 			pImaConnProps->defaultTime2Retain =
   1541 			    pConnProps->cp_params.default_time_to_retain;
   1542 			pImaConnProps->defaultTime2Wait =
   1543 			    pConnProps->cp_params.default_time_to_wait;
   1544 			pImaConnProps->errorRecoveryLevel =
   1545 			    pConnProps->cp_params.error_recovery_level;
   1546 			pImaConnProps->firstBurstLength =
   1547 			    pConnProps->cp_params.first_burst_length;
   1548 			pImaConnProps->maxBurstLength =
   1549 			    pConnProps->cp_params.max_burst_length;
   1550 			pImaConnProps->maxConnections =
   1551 			    pConnProps->cp_params.max_connections;
   1552 			pImaConnProps->maxOutstandingR2T =
   1553 			    pConnProps->cp_params.max_outstanding_r2t;
   1554 			pImaConnProps->maxRecvDataSegmentLength =
   1555 			    pConnProps->cp_params.max_recv_data_seg_len;
   1556 
   1557 			pImaConnProps->dataPduInOrder =
   1558 			    pConnProps->cp_params.data_pdu_in_order;
   1559 			pImaConnProps->dataSequenceInOrder =
   1560 			    pConnProps->cp_params.data_sequence_in_order;
   1561 			pImaConnProps->immediateData =
   1562 			    pConnProps->cp_params.immediate_data;
   1563 			pImaConnProps->initialR2T =
   1564 			    pConnProps->cp_params.initial_r2t;
   1565 
   1566 			pImaConnProps->headerDigest =
   1567 			    pConnProps->cp_params.header_digest;
   1568 			pImaConnProps->dataDigest =
   1569 			    pConnProps->cp_params.data_digest;
   1570 
   1571 			free(pConnProps);
   1572 			break;
   1573 		}
   1574 	}
   1575 	free(pConnList);
   1576 	*pProps = pImaConnProps;
   1577 	return (IMA_STATUS_SUCCESS);
   1578 }
   1579 
   1580 
   1581 /*
   1582  * SUN_IMA_GetConfigSessions -
   1583  *
   1584  * Non-IMA defined function.
   1585  */
   1586 IMA_API IMA_STATUS SUN_IMA_GetConfigSessions(
   1587     IMA_OID targetOid,
   1588     SUN_IMA_CONFIG_SESSIONS **pConfigSessions
   1589 )
   1590 {
   1591 	int			fd;
   1592 	int			status;
   1593 	iscsi_config_sess_t	*ics;
   1594 	int			size, idx;
   1595 
   1596 	/* Allocate and setup initial buffer */
   1597 	size = sizeof (*ics);
   1598 	ics = (iscsi_config_sess_t *)calloc(1, size);
   1599 	if (ics == NULL) {
   1600 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1601 	}
   1602 	ics->ics_ver = ISCSI_INTERFACE_VERSION;
   1603 	ics->ics_oid = targetOid.objectSequenceNumber;
   1604 	ics->ics_in  = 1;
   1605 
   1606 	/* Open driver devctl for ioctl */
   1607 	if ((status = open_driver(&fd))) {
   1608 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1609 	}
   1610 
   1611 	/* Issue ioctl request */
   1612 	if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
   1613 		syslog(LOG_USER|LOG_DEBUG,
   1614 		    "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
   1615 		    errno);
   1616 		(void) close(fd);
   1617 		free(ics);
   1618 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1619 	}
   1620 
   1621 	/* Check if we need to collect more information */
   1622 	idx = ics->ics_out;
   1623 	if (idx > 1) {
   1624 
   1625 		/* Free old buffer and reallocate re-sized buffer */
   1626 		free(ics);
   1627 		size = ISCSI_SESSION_CONFIG_SIZE(idx);
   1628 		ics = (iscsi_config_sess_t *)calloc(1, size);
   1629 		if (ics == NULL) {
   1630 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1631 		}
   1632 		ics->ics_ver = ISCSI_INTERFACE_VERSION;
   1633 		ics->ics_oid = targetOid.objectSequenceNumber;
   1634 		ics->ics_in = idx;
   1635 
   1636 		/* Issue ioctl request */
   1637 		if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
   1638 			syslog(LOG_USER|LOG_DEBUG,
   1639 			    "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
   1640 			    errno);
   1641 			(void) close(fd);
   1642 			free(ics);
   1643 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1644 		}
   1645 	}
   1646 	(void) close(fd);
   1647 
   1648 	/* Allocate output buffer */
   1649 	size = sizeof (SUN_IMA_CONFIG_SESSIONS) +
   1650 	    ((ics->ics_out - 1) * sizeof (IMA_ADDRESS_KEY));
   1651 	*pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
   1652 	if ((*pConfigSessions) == NULL) {
   1653 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1654 	}
   1655 
   1656 	/* Copy output information */
   1657 	(*pConfigSessions)->bound =
   1658 	    (ics->ics_bound == B_TRUE ?  IMA_TRUE : IMA_FALSE);
   1659 	(*pConfigSessions)->in = ics->ics_in;
   1660 	(*pConfigSessions)->out = ics->ics_out;
   1661 	for (idx = 0; idx < ics->ics_in; idx++) {
   1662 		if (ics->ics_bindings[idx].i_insize ==
   1663 		    sizeof (struct in_addr)) {
   1664 			(*pConfigSessions)->bindings[idx].ipAddress.
   1665 			    ipv4Address = IMA_TRUE;
   1666 			bcopy(&ics->ics_bindings[idx].i_addr.in4,
   1667 			    (*pConfigSessions)->bindings[idx].ipAddress.
   1668 			    ipAddress, sizeof (struct in_addr));
   1669 		} else {
   1670 			(*pConfigSessions)->bindings[idx].ipAddress.
   1671 			    ipv4Address = IMA_FALSE;
   1672 			bcopy(&ics->ics_bindings[idx].i_addr.in6,
   1673 			    (*pConfigSessions)->bindings[idx].ipAddress.
   1674 			    ipAddress, sizeof (struct in6_addr));
   1675 		}
   1676 	}
   1677 
   1678 	free(ics);
   1679 	return (IMA_STATUS_SUCCESS);
   1680 }
   1681 
   1682 /*
   1683  * SUN_IMA_SetConfigSessions -
   1684  *
   1685  * Non-IMA defined function.
   1686  */
   1687 IMA_API IMA_STATUS SUN_IMA_SetConfigSessions(
   1688     IMA_OID targetOid,
   1689     SUN_IMA_CONFIG_SESSIONS *pConfigSessions
   1690 )
   1691 {
   1692 	int		    fd;
   1693 	int		    status;
   1694 	iscsi_config_sess_t *ics;
   1695 	int		    idx, size;
   1696 
   1697 	/* verify allowed range of sessions */
   1698 	if ((pConfigSessions->in < ISCSI_MIN_CONFIG_SESSIONS) ||
   1699 	    (pConfigSessions->in > ISCSI_MAX_CONFIG_SESSIONS)) {
   1700 		return (IMA_ERROR_INVALID_PARAMETER);
   1701 	}
   1702 
   1703 	/* allocate record config_sess size */
   1704 	size = ISCSI_SESSION_CONFIG_SIZE(pConfigSessions->in);
   1705 	ics = (iscsi_config_sess_t *)malloc(size);
   1706 
   1707 	/* setup config_sess information */
   1708 	(void) memset(ics, 0, sizeof (iscsi_config_sess_t));
   1709 	ics->ics_ver = ISCSI_INTERFACE_VERSION;
   1710 	ics->ics_oid = targetOid.objectSequenceNumber;
   1711 	ics->ics_bound =
   1712 	    (pConfigSessions->bound == IMA_TRUE ?  B_TRUE : B_FALSE);
   1713 	ics->ics_in  = pConfigSessions->in;
   1714 	for (idx = 0; idx < ics->ics_in; idx++) {
   1715 		if (pConfigSessions->bindings[idx].ipAddress.
   1716 		    ipv4Address == IMA_TRUE) {
   1717 			ics->ics_bindings[idx].i_insize =
   1718 			    sizeof (struct in_addr);
   1719 			bcopy(pConfigSessions->bindings[idx].
   1720 			    ipAddress.ipAddress,
   1721 			    &ics->ics_bindings[idx].i_addr.in4,
   1722 			    sizeof (struct in_addr));
   1723 		} else {
   1724 			ics->ics_bindings[idx].i_insize =
   1725 			    sizeof (struct in6_addr);
   1726 			bcopy(pConfigSessions->bindings[idx].
   1727 			    ipAddress.ipAddress,
   1728 			    &ics->ics_bindings[idx].i_addr.in6,
   1729 			    sizeof (struct in6_addr));
   1730 		}
   1731 	}
   1732 
   1733 	/* open driver */
   1734 	if ((status = open_driver(&fd))) {
   1735 		free(ics);
   1736 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1737 	}
   1738 
   1739 	/* issue ioctl request */
   1740 	if (ioctl(fd, ISCSI_SET_CONFIG_SESSIONS, ics) != 0) {
   1741 		syslog(LOG_USER|LOG_DEBUG,
   1742 		    "ISCSI_SET_CONFIG_SESSIONS ioctl failed, errno: %d",
   1743 		    errno);
   1744 		(void) close(fd);
   1745 		free(ics);
   1746 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1747 	}
   1748 	(void) close(fd);
   1749 	free(ics);
   1750 	return (IMA_STATUS_SUCCESS);
   1751 }
   1752 
   1753 /* A helper function to obtain iSCSI node parameters. */
   1754 static IMA_STATUS
   1755 getISCSINodeParameter(
   1756     int paramType,
   1757     IMA_OID *oid,
   1758     void *pProps,
   1759     uint32_t paramIndex
   1760 )
   1761 {
   1762 	int		    fd;
   1763 	int 		status;
   1764 	iscsi_param_get_t   pg;
   1765 
   1766 	if ((status = open_driver(&fd))) {
   1767 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1768 	}
   1769 
   1770 	(void) memset(&pg, 0, sizeof (iscsi_param_get_t));
   1771 	pg.g_vers = ISCSI_INTERFACE_VERSION;
   1772 	pg.g_oid = (uint32_t)oid->objectSequenceNumber;
   1773 	pg.g_param = paramIndex;
   1774 	pg.g_param_type = ISCSI_SESS_PARAM;
   1775 
   1776 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
   1777 		syslog(LOG_USER|LOG_DEBUG,
   1778 		    "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
   1779 		(void) close(fd);
   1780 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1781 	}
   1782 
   1783 	switch (paramType) {
   1784 		IMA_BOOL_VALUE *bp;
   1785 		IMA_MIN_MAX_VALUE *mp;
   1786 
   1787 		case MIN_MAX_PARAM:
   1788 			mp = (IMA_MIN_MAX_VALUE *)pProps;
   1789 
   1790 			mp->currentValueValid =
   1791 			    (pg.g_value.v_valid == B_TRUE) ?
   1792 			    IMA_TRUE : IMA_FALSE;
   1793 			mp->currentValue = pg.g_value.v_integer.i_current;
   1794 			mp->defaultValue = pg.g_value.v_integer.i_default;
   1795 			mp->minimumValue = pg.g_value.v_integer.i_min;
   1796 			mp->maximumValue = pg.g_value.v_integer.i_max;
   1797 			mp->incrementValue = pg.g_value.v_integer.i_incr;
   1798 			break;
   1799 
   1800 		case BOOL_PARAM:
   1801 			bp = (IMA_BOOL_VALUE *)pProps;
   1802 			bp->currentValueValid =
   1803 			    (pg.g_value.v_valid == B_TRUE) ?
   1804 			    IMA_TRUE : IMA_FALSE;
   1805 			bp->currentValue = pg.g_value.v_bool.b_current;
   1806 			bp->defaultValue = pg.g_value.v_bool.b_default;
   1807 			break;
   1808 
   1809 		default:
   1810 			break;
   1811 	}
   1812 
   1813 	/* Issue ISCSI_PARAM_GET ioctl again to obtain connection parameters. */
   1814 	pg.g_param_type = ISCSI_CONN_PARAM;
   1815 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
   1816 		syslog(LOG_USER|LOG_DEBUG,
   1817 		    "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
   1818 		(void) close(fd);
   1819 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1820 	}
   1821 
   1822 	(void) close(fd);
   1823 	return (IMA_STATUS_SUCCESS);
   1824 }
   1825 
   1826 /* A helper function to set iSCSI node parameters. */
   1827 static IMA_STATUS
   1828 setISCSINodeParameter(
   1829     int paramType,
   1830     IMA_OID *oid,
   1831     void *pProp,
   1832     uint32_t paramIndex
   1833 )
   1834 {
   1835 	int		    fd;
   1836 	int			status;
   1837 	iscsi_param_set_t   ps;
   1838 
   1839 	if ((status = open_driver(&fd))) {
   1840 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1841 	}
   1842 
   1843 	(void) memset(&ps, 0, sizeof (iscsi_param_set_t));
   1844 	ps.s_vers = ISCSI_INTERFACE_VERSION;
   1845 	ps.s_oid = (uint32_t)oid->objectSequenceNumber;
   1846 	ps.s_param = paramIndex;
   1847 
   1848 	switch (paramType) {
   1849 		IMA_BOOL_VALUE *bp;
   1850 		IMA_MIN_MAX_VALUE *mp;
   1851 
   1852 		case MIN_MAX_PARAM:
   1853 			mp = (IMA_MIN_MAX_VALUE *)pProp;
   1854 			ps.s_value.v_integer = mp->currentValue;
   1855 			break;
   1856 		case BOOL_PARAM:
   1857 			bp = (IMA_BOOL_VALUE *)pProp;
   1858 			ps.s_value.v_bool =
   1859 			    (bp->currentValue == IMA_TRUE) ?
   1860 			    B_TRUE : B_FALSE;
   1861 			break;
   1862 
   1863 		default:
   1864 			break;
   1865 	}
   1866 	if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
   1867 		(void) close(fd);
   1868 		syslog(LOG_USER|LOG_DEBUG,
   1869 		    "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
   1870 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1871 	}
   1872 
   1873 	(void) close(fd);
   1874 	return (IMA_STATUS_SUCCESS);
   1875 }
   1876 
   1877 static int
   1878 prepare_discovery_entry(
   1879     SUN_IMA_TARGET_ADDRESS discoveryAddress,
   1880     entry_t *entry
   1881 )
   1882 {
   1883 	return (prepare_discovery_entry_IMA(discoveryAddress.imaStruct, entry));
   1884 }
   1885 
   1886 static int
   1887 prepare_discovery_entry_IMA(
   1888     IMA_TARGET_ADDRESS discoveryAddress,
   1889     entry_t *entry
   1890 )
   1891 {
   1892 	(void) memset(entry, 0, sizeof (entry_t));
   1893 	entry->e_vers = ISCSI_INTERFACE_VERSION;
   1894 	entry->e_oid = ISCSI_OID_NOTSET;
   1895 
   1896 	if (discoveryAddress.hostnameIpAddress.id.ipAddress.
   1897 	    ipv4Address == IMA_FALSE) {
   1898 
   1899 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.
   1900 		    ipAddress, entry->e_u.u_in6.s6_addr,
   1901 		    sizeof (entry->e_u.u_in6.s6_addr));
   1902 
   1903 		entry->e_insize = sizeof (struct in6_addr);
   1904 	} else {
   1905 
   1906 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.
   1907 		    ipAddress, &entry->e_u.u_in4.s_addr,
   1908 		    sizeof (entry->e_u.u_in4.s_addr));
   1909 
   1910 		entry->e_insize = sizeof (struct in_addr);
   1911 	}
   1912 
   1913 	entry->e_port = discoveryAddress.portNumber;
   1914 	entry->e_tpgt = 0;
   1915 	return (DISC_ADDR_OK);
   1916 }
   1917 
   1918 static IMA_STATUS configure_discovery_method(
   1919     IMA_BOOL enable,
   1920     iSCSIDiscoveryMethod_t method
   1921 )
   1922 {
   1923 	int	fd, status;
   1924 
   1925 	if ((status = open_driver(&fd))) {
   1926 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1927 	}
   1928 
   1929 	if (enable == IMA_FALSE) {
   1930 		if (ioctl(fd, ISCSI_DISCOVERY_CLEAR, &method)) {
   1931 			status = errno;
   1932 			(void) close(fd);
   1933 			syslog(LOG_USER|LOG_DEBUG,
   1934 			    "ISCSI_DISCOVERY_CLEAR ioctl failed, errno: %d",
   1935 			    status);
   1936 			if (status == EBUSY) {
   1937 				return (IMA_ERROR_LU_IN_USE);
   1938 			} else {
   1939 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1940 			}
   1941 		}
   1942 
   1943 		(void) close(fd);
   1944 		return (IMA_STATUS_SUCCESS);
   1945 	} else {
   1946 		/* Set the discovery method */
   1947 		if (ioctl(fd, ISCSI_DISCOVERY_SET, &method)) {
   1948 			status = errno;
   1949 			(void) close(fd);
   1950 			syslog(LOG_USER|LOG_DEBUG,
   1951 			    "ISCSI_DISCOVERY_SET ioctl failed, errno: %d",
   1952 			    status);
   1953 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   1954 		}
   1955 
   1956 		(void) close(fd);
   1957 		return (IMA_STATUS_SUCCESS);
   1958 	}
   1959 }
   1960 
   1961 /* LINTED E_STATIC_UNUSED */
   1962 static IMA_BOOL authMethodMatch(
   1963     IMA_AUTHMETHOD matchingMethod,
   1964     IMA_AUTHMETHOD *methodList,
   1965     IMA_UINT maxEntries
   1966 )
   1967 {
   1968 	IMA_UINT i;
   1969 
   1970 	for (i = 0; i < maxEntries; i++) {
   1971 		if (methodList[i] == matchingMethod) {
   1972 			return (IMA_TRUE);
   1973 		}
   1974 	}
   1975 
   1976 	return (IMA_FALSE);
   1977 }
   1978 
   1979 static IMA_STATUS get_target_oid_list(
   1980     uint32_t targetListType,
   1981     IMA_OID_LIST **ppList)
   1982 {
   1983 	int		    fd;
   1984 	int		    i;
   1985 	int		    target_list_size;
   1986 	int		    status;
   1987 	int		    out_cnt;
   1988 	iscsi_target_list_t *idlp;
   1989 
   1990 	if ((status = open_driver(&fd))) {
   1991 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   1992 	}
   1993 
   1994 	idlp = (iscsi_target_list_t *)calloc(1, sizeof (iscsi_target_list_t));
   1995 	if (idlp == NULL) {
   1996 		(void) close(fd);
   1997 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   1998 	}
   1999 	idlp->tl_vers = ISCSI_INTERFACE_VERSION;
   2000 	idlp->tl_in_cnt = idlp->tl_out_cnt = 1;
   2001 	idlp->tl_tgt_list_type = targetListType;
   2002 
   2003 	/*
   2004 	 * Issue ioctl.  Space has been allocted for one entry.
   2005 	 * If more than one entry should be returned, we will re-issue the
   2006 	 * entry with the right amount of space allocted
   2007 	 */
   2008 	if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
   2009 		(void) close(fd);
   2010 		syslog(LOG_USER|LOG_DEBUG,
   2011 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
   2012 		    targetListType, errno);
   2013 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2014 	}
   2015 	if (idlp->tl_out_cnt > 1) {
   2016 		out_cnt = idlp->tl_out_cnt;
   2017 		free(idlp);
   2018 
   2019 		target_list_size = sizeof (iscsi_target_list_t);
   2020 		target_list_size += (sizeof (uint32_t) * out_cnt - 1);
   2021 		idlp = (iscsi_target_list_t *)calloc(1, target_list_size);
   2022 		if (idlp == NULL) {
   2023 			(void) close(fd);
   2024 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2025 		}
   2026 		idlp->tl_vers = ISCSI_INTERFACE_VERSION;
   2027 		idlp->tl_in_cnt = out_cnt;
   2028 		idlp->tl_tgt_list_type = targetListType;
   2029 
   2030 		/* Issue the same ioctl again to obtain all the OIDs. */
   2031 		if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
   2032 #define	ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d"
   2033 			free(idlp);
   2034 			(void) close(fd);
   2035 			syslog(LOG_USER|LOG_DEBUG,
   2036 			    ERROR_STR, targetListType, errno);
   2037 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2038 #undef ERROR_STR
   2039 
   2040 		}
   2041 	}
   2042 
   2043 	*ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
   2044 	    idlp->tl_out_cnt * sizeof (IMA_OID));
   2045 	(*ppList)->oidCount = idlp->tl_out_cnt;
   2046 	for (i = 0; i < idlp->tl_out_cnt; i++) {
   2047 		(*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET;
   2048 		(*ppList)->oids[i].ownerId = 1;
   2049 		(*ppList)->oids[i].objectSequenceNumber = idlp->tl_oid_list[i];
   2050 	}
   2051 
   2052 	free(idlp);
   2053 	(void) close(fd);
   2054 	return (IMA_STATUS_SUCCESS);
   2055 }
   2056 
   2057 static IMA_STATUS get_target_lun_oid_list(
   2058     IMA_OID * targetOid,
   2059     iscsi_lun_list_t  **ppLunList)
   2060 {
   2061 	int			fd;
   2062 	iscsi_lun_list_t	*illp, *illp_saved;
   2063 	int			lun_list_size;
   2064 	int			status;
   2065 
   2066 	if ((status = open_driver(&fd))) {
   2067 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2068 	}
   2069 
   2070 	illp = (iscsi_lun_list_t *)calloc(1, sizeof (iscsi_lun_list_t));
   2071 	if (illp == NULL) {
   2072 		(void) close(fd);
   2073 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2074 	}
   2075 	illp->ll_vers = ISCSI_INTERFACE_VERSION;
   2076 	if (targetOid == NULL) {
   2077 		/* get lun oid list for all targets */
   2078 		illp->ll_all_tgts = B_TRUE;
   2079 	} else {
   2080 		/* get lun oid list for single target */
   2081 		illp->ll_all_tgts = B_FALSE;
   2082 		illp->ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber;
   2083 	}
   2084 	illp->ll_in_cnt = illp->ll_out_cnt = 1;
   2085 
   2086 	/*
   2087 	 * Issue ioctl to retrieve the target luns.  Space has been allocted
   2088 	 * for one entry.  If more than one entry should be returned, we
   2089 	 * will re-issue the entry with the right amount of space allocted
   2090 	 */
   2091 	if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
   2092 		(void) close(fd);
   2093 		syslog(LOG_USER|LOG_DEBUG,
   2094 		    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
   2095 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2096 	}
   2097 
   2098 	if (illp->ll_out_cnt > 1) {
   2099 		illp_saved = illp;
   2100 		lun_list_size = sizeof (iscsi_lun_list_t);
   2101 		lun_list_size += (sizeof (iscsi_if_lun_t) *
   2102 		    (illp->ll_out_cnt - 1));
   2103 		illp = (iscsi_lun_list_t *)calloc(1, lun_list_size);
   2104 		if (illp == NULL) {
   2105 			(void) close(fd);
   2106 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2107 		}
   2108 		illp->ll_vers = ISCSI_INTERFACE_VERSION;
   2109 		illp->ll_all_tgts = illp_saved->ll_all_tgts;
   2110 		illp->ll_tgt_oid = illp_saved->ll_tgt_oid;
   2111 		illp->ll_in_cnt = illp_saved->ll_out_cnt;
   2112 
   2113 		free(illp_saved);
   2114 
   2115 		/* Issue the same ioctl again to get all the target LUN list */
   2116 		if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
   2117 			free(illp);
   2118 			(void) close(fd);
   2119 			syslog(LOG_USER|LOG_DEBUG,
   2120 			    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d",
   2121 			    errno);
   2122 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2123 
   2124 		}
   2125 	}
   2126 	*ppLunList = illp;
   2127 
   2128 
   2129 	(void) close(fd);
   2130 	return (IMA_STATUS_SUCCESS);
   2131 }
   2132 
   2133 /* A helper function to obtain digest algorithms. */
   2134 static IMA_STATUS
   2135 getDigest(
   2136     IMA_OID oid,
   2137     int ioctlCmd,
   2138     SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
   2139 )
   2140 {
   2141 	IMA_MIN_MAX_VALUE pProps;
   2142 	IMA_STATUS status;
   2143 
   2144 	if ((status = getISCSINodeParameter(MIN_MAX_PARAM, &oid, &pProps,
   2145 	    ioctlCmd)) != IMA_STATUS_SUCCESS) {
   2146 		return (status);
   2147 	}
   2148 
   2149 	switch (pProps.defaultValue) {
   2150 		case ISCSI_DIGEST_NONE:
   2151 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
   2152 			algorithm->defaultAlgorithmCount = 1;
   2153 			break;
   2154 		case ISCSI_DIGEST_CRC32C:
   2155 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
   2156 			algorithm->defaultAlgorithmCount = 1;
   2157 			break;
   2158 
   2159 		case ISCSI_DIGEST_CRC32C_NONE:
   2160 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
   2161 			algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_NONE;
   2162 			algorithm->defaultAlgorithmCount = 2;
   2163 			break;
   2164 		case ISCSI_DIGEST_NONE_CRC32C:
   2165 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
   2166 			algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_CRC32C;
   2167 			algorithm->defaultAlgorithmCount = 2;
   2168 			break;
   2169 		default:
   2170 			/* Error */
   2171 			syslog(LOG_USER|LOG_DEBUG,
   2172 			    "Invalid default digest: %d", pProps.defaultValue);
   2173 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2174 	}
   2175 
   2176 	/* The configured value */
   2177 	if (pProps.currentValueValid == IMA_TRUE) {
   2178 		algorithm->currentValid = IMA_TRUE;
   2179 
   2180 		switch (pProps.currentValue) {
   2181 			case ISCSI_DIGEST_NONE:
   2182 				algorithm->currentAlgorithms[0] =
   2183 				    ISCSI_DIGEST_NONE;
   2184 				algorithm->currentAlgorithmCount = 1;
   2185 				break;
   2186 			case ISCSI_DIGEST_CRC32C:
   2187 				algorithm->currentAlgorithms[0] =
   2188 				    ISCSI_DIGEST_CRC32C;
   2189 				algorithm->currentAlgorithmCount = 1;
   2190 				break;
   2191 
   2192 			case ISCSI_DIGEST_CRC32C_NONE:
   2193 				algorithm->currentAlgorithms[0] =
   2194 				    ISCSI_DIGEST_CRC32C;
   2195 				algorithm->currentAlgorithms[1] =
   2196 				    ISCSI_DIGEST_NONE;
   2197 				algorithm->currentAlgorithmCount = 2;
   2198 				break;
   2199 			case ISCSI_DIGEST_NONE_CRC32C:
   2200 				algorithm->currentAlgorithms[0] =
   2201 				    ISCSI_DIGEST_NONE;
   2202 				algorithm->currentAlgorithms[1] =
   2203 				    ISCSI_DIGEST_CRC32C;
   2204 				algorithm->currentAlgorithmCount = 2;
   2205 				break;
   2206 			default:
   2207 				/* Error */
   2208 				syslog(LOG_USER|LOG_DEBUG,
   2209 				    "Invalid configured digest: %d",
   2210 				    pProps.defaultValue);
   2211 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2212 		}
   2213 
   2214 	} else {
   2215 		algorithm->currentValid = IMA_FALSE;
   2216 	}
   2217 
   2218 	return (IMA_STATUS_SUCCESS);
   2219 }
   2220 
   2221 /*
   2222  * getConnOidList -
   2223  */
   2224 static IMA_STATUS getConnOidList(
   2225 	IMA_OID			*sessOid,
   2226 	iscsi_conn_list_t	**ppConnList
   2227 )
   2228 {
   2229 	iscsi_conn_list_t	*iscsiConnList = NULL;
   2230 	size_t			allocLen;
   2231 	int			fd;
   2232 	int			status;
   2233 	int			out_cnt;
   2234 
   2235 	/* Preset it to NULL to prepare for the case of failure */
   2236 	*ppConnList = NULL;
   2237 
   2238 	/* We try to open the driver now. */
   2239 	if ((status = open_driver(&fd))) {
   2240 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2241 	}
   2242 
   2243 	iscsiConnList = (iscsi_conn_list_t *)calloc(1,
   2244 	    sizeof (iscsi_conn_list_t));
   2245 	if (iscsiConnList == NULL) {
   2246 		(void) close(fd);
   2247 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2248 	}
   2249 	iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
   2250 	iscsiConnList->cl_in_cnt = iscsiConnList->cl_out_cnt = 1;
   2251 	if (sessOid == NULL) {
   2252 		iscsiConnList->cl_all_sess = B_TRUE;
   2253 	} else {
   2254 		iscsiConnList->cl_all_sess = B_FALSE;
   2255 		iscsiConnList->cl_sess_oid =
   2256 		    (uint32_t)sessOid->objectSequenceNumber;
   2257 	}
   2258 	/*
   2259 	 * Issue ioctl to retrieve the connection OIDs.  Space has been
   2260 	 * allocated for one entry.  If more than one entry should be
   2261 	 * returned, we will re-issue the entry with the right amount of
   2262 	 * space allocted
   2263 	 */
   2264 	if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
   2265 		syslog(LOG_USER|LOG_DEBUG,
   2266 		    "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d", errno);
   2267 		*ppConnList = NULL;
   2268 		(void) close(fd);
   2269 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2270 	}
   2271 	if (iscsiConnList->cl_out_cnt > 1) {
   2272 		out_cnt = iscsiConnList->cl_out_cnt;
   2273 		free(iscsiConnList);
   2274 
   2275 		allocLen = sizeof (iscsi_conn_list_t);
   2276 		allocLen += (sizeof (iscsi_if_conn_t) * out_cnt - 1);
   2277 		iscsiConnList = (iscsi_conn_list_t *)calloc(1, allocLen);
   2278 		if (iscsiConnList == NULL) {
   2279 			*ppConnList = NULL;
   2280 			(void) close(fd);
   2281 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2282 		}
   2283 		iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
   2284 		iscsiConnList->cl_in_cnt = out_cnt;
   2285 		if (sessOid == NULL) {
   2286 			iscsiConnList->cl_all_sess = B_TRUE;
   2287 		} else {
   2288 			iscsiConnList->cl_all_sess = B_FALSE;
   2289 			iscsiConnList->cl_sess_oid =
   2290 			    (uint32_t)sessOid->objectSequenceNumber;
   2291 		}
   2292 		/* Issue the same ioctl again to obtain all the OIDs */
   2293 		if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
   2294 
   2295 			syslog(LOG_USER|LOG_DEBUG,
   2296 			    "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d",
   2297 			    errno);
   2298 			*ppConnList = NULL;
   2299 			free(iscsiConnList);
   2300 			(void) close(fd);
   2301 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2302 
   2303 		}
   2304 
   2305 		if (out_cnt < iscsiConnList->cl_out_cnt) {
   2306 			/*
   2307 			 * The connection list grew between the first and second
   2308 			 * ioctls.
   2309 			 */
   2310 			syslog(LOG_USER|LOG_DEBUG,
   2311 			    "The connection list has grown. There could be "
   2312 			    "more connections than listed.");
   2313 		}
   2314 	}
   2315 
   2316 
   2317 	(void) close(fd);
   2318 	*ppConnList = iscsiConnList;
   2319 	return (IMA_STATUS_SUCCESS);
   2320 }
   2321 
   2322 /*
   2323  * getConnProps -
   2324  */
   2325 static IMA_STATUS getConnProps(
   2326 	iscsi_if_conn_t		*pConn,
   2327 	iscsi_conn_props_t	**ppConnProps
   2328 )
   2329 {
   2330 	iscsi_conn_props_t	*iscsiConnProps;
   2331 	int			fd;
   2332 	int			status;
   2333 
   2334 	/* We try to open the driver. */
   2335 	if ((status = open_driver(&fd))) {
   2336 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2337 	}
   2338 
   2339 	iscsiConnProps = (iscsi_conn_props_t *)calloc(1,
   2340 	    sizeof (*iscsiConnProps));
   2341 
   2342 	if (iscsiConnProps == NULL) {
   2343 		(void) close(fd);
   2344 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2345 	}
   2346 
   2347 	iscsiConnProps->cp_vers = ISCSI_INTERFACE_VERSION;
   2348 	iscsiConnProps->cp_oid = pConn->c_oid;
   2349 	iscsiConnProps->cp_cid = pConn->c_cid;
   2350 	iscsiConnProps->cp_sess_oid = pConn->c_sess_oid;
   2351 
   2352 	/* The IOCTL is submitted. */
   2353 	if (ioctl(fd, ISCSI_CONN_PROPS_GET, iscsiConnProps) != 0) {
   2354 		/* IOCTL failed */
   2355 		syslog(LOG_USER|LOG_DEBUG,
   2356 		    "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
   2357 		free(iscsiConnProps);
   2358 		(void) close(fd);
   2359 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2360 	}
   2361 	(void) close(fd);
   2362 	*ppConnProps = iscsiConnProps;
   2363 	return (IMA_STATUS_SUCCESS);
   2364 }
   2365 
   2366 /* A helper function to set authentication method. */
   2367 static IMA_STATUS
   2368 setAuthMethods(
   2369     IMA_OID oid,
   2370     IMA_UINT *pMethodCount,
   2371     const IMA_AUTHMETHOD *pMethodList
   2372 )
   2373 {
   2374 	int fd;
   2375 	int i;
   2376 	int status;
   2377 	iscsi_auth_props_t auth;
   2378 
   2379 	if ((status = open_driver(&fd))) {
   2380 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2381 	}
   2382 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
   2383 	auth.a_vers = ISCSI_INTERFACE_VERSION;
   2384 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
   2385 
   2386 	/*
   2387 	 * Get the current auth fields so they don't need to be reset
   2388 	 * here.
   2389 	 */
   2390 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
   2391 	    /* EMPTY */
   2392 	    /* Initializing auth structure with current settings */
   2393 	}
   2394 	auth.a_auth_method = authMethodNone;
   2395 
   2396 	for (i = 0; i < *pMethodCount; i++) {
   2397 		switch (pMethodList[i]) {
   2398 			case IMA_AUTHMETHOD_CHAP:
   2399 				auth.a_auth_method |= authMethodCHAP;
   2400 				break;
   2401 			default:
   2402 				break;
   2403 		}
   2404 	}
   2405 
   2406 	if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
   2407 		syslog(LOG_USER|LOG_DEBUG,
   2408 		    "ISCSI_AUTH_SET failed, errno: %d", errno);
   2409 		(void) close(fd);
   2410 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2411 	}
   2412 
   2413 	(void) close(fd);
   2414 	return (IMA_STATUS_SUCCESS);
   2415 }
   2416 
   2417 /* A helper function to set authentication method. */
   2418 static IMA_STATUS getAuthMethods(
   2419     IMA_OID oid,
   2420     IMA_UINT	*pMethodCount,
   2421     IMA_AUTHMETHOD *pMethodList
   2422 )
   2423 {
   2424 	int fd;
   2425 	int status;
   2426 	iscsi_auth_props_t auth;
   2427 
   2428 	if ((status = open_driver(&fd))) {
   2429 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2430 	}
   2431 
   2432 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
   2433 	auth.a_vers = ISCSI_INTERFACE_VERSION;
   2434 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
   2435 
   2436 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
   2437 		syslog(LOG_USER|LOG_DEBUG,
   2438 		    "ISCSI_AUTH_GET failed, errno: %d", errno);
   2439 		(void) close(fd);
   2440 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2441 	}
   2442 
   2443 	if (auth.a_auth_method == authMethodNone) {
   2444 		pMethodList[0] = IMA_AUTHMETHOD_NONE;
   2445 		*pMethodCount = 1;
   2446 	} else {
   2447 		int i = 0;
   2448 		if (!((auth.a_auth_method & authMethodCHAP)^authMethodCHAP)) {
   2449 			pMethodList[i++] = IMA_AUTHMETHOD_CHAP;
   2450 		}
   2451 		*pMethodCount = i;
   2452 	}
   2453 
   2454 	(void) close(fd);
   2455 	return (IMA_STATUS_SUCCESS);
   2456 }
   2457 
   2458 /* Helper function to open driver */
   2459 int open_driver(
   2460 	int *fd
   2461 )
   2462 {
   2463 	int ret = 0;
   2464 	if ((*fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   2465 		ret = errno;
   2466 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
   2467 		    ISCSI_DRIVER_DEVCTL, ret);
   2468 	}
   2469 	return (ret);
   2470 }
   2471 
   2472 /*
   2473  * Iscsi driver does not support OID for discovery address. Create
   2474  * a modified version of IMA_RemoveDiscoveryAddress that takes
   2475  * discoveryAddress (instead of an OID) as input argument.
   2476  */
   2477 IMA_API	IMA_STATUS SUN_IMA_RemoveDiscoveryAddress(
   2478     SUN_IMA_TARGET_ADDRESS discoveryAddress
   2479 )
   2480 {
   2481 	entry_t	entry;
   2482 	int	fd;
   2483 	int status, i, addr_list_size, insize;
   2484 	iscsi_addr_list_t *idlp, al_info;
   2485 	iscsi_addr_t *matched_addr = NULL;
   2486 
   2487 	if ((status = open_driver(&fd))) {
   2488 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2489 	}
   2490 
   2491 	if (prepare_discovery_entry(discoveryAddress, &entry) !=
   2492 	    DISC_ADDR_OK) {
   2493 		(void) close(fd);
   2494 		return (IMA_ERROR_INVALID_PARAMETER);
   2495 	}
   2496 
   2497 	(void) memset(&al_info, 0, sizeof (al_info));
   2498 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
   2499 	al_info.al_in_cnt = 0;
   2500 	/*
   2501 	 * Issue ioctl to get the number of discovery address.
   2502 	 */
   2503 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
   2504 		syslog(LOG_USER|LOG_DEBUG,
   2505 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
   2506 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
   2507 		(void) close(fd);
   2508 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2509 	}
   2510 
   2511 	if (al_info.al_out_cnt == 0) {
   2512 		(void) close(fd);
   2513 		return (IMA_ERROR_OBJECT_NOT_FOUND);
   2514 	}
   2515 
   2516 	addr_list_size = sizeof (iscsi_addr_list_t);
   2517 	if (al_info.al_out_cnt > 1) {
   2518 		addr_list_size += (sizeof (iscsi_addr_t) *
   2519 		    (al_info.al_out_cnt - 1));
   2520 	}
   2521 
   2522 	idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
   2523 	if (idlp == NULL) {
   2524 		(void) close(fd);
   2525 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2526 	}
   2527 
   2528 	idlp->al_vers = ISCSI_INTERFACE_VERSION;
   2529 	idlp->al_in_cnt = al_info.al_out_cnt;
   2530 
   2531 	/* issue the same ioctl to get all the discovery addresses */
   2532 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
   2533 		syslog(LOG_USER|LOG_DEBUG,
   2534 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
   2535 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
   2536 		free(idlp);
   2537 		(void) close(fd);
   2538 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2539 	}
   2540 
   2541 	/*
   2542 	 * find the matched discovery address
   2543 	 */
   2544 	for (i = 0; i < idlp->al_out_cnt; i++) {
   2545 		insize = idlp->al_addrs[i].a_addr.i_insize;
   2546 		if (insize != entry.e_insize) {
   2547 			continue;
   2548 		}
   2549 		if (insize == sizeof (struct in_addr)) {
   2550 			if (idlp->al_addrs[i].a_addr.i_addr.in4.s_addr ==
   2551 			    entry.e_u.u_in4.s_addr) {
   2552 				matched_addr = &(idlp->al_addrs[i]);
   2553 				break;
   2554 			}
   2555 		}
   2556 		if (insize == sizeof (struct in6_addr)) {
   2557 			if (bcmp(entry.e_u.u_in6.s6_addr,
   2558 			    idlp->al_addrs[i].a_addr.i_addr.in6.s6_addr,
   2559 			    insize) == 0) {
   2560 				matched_addr = &(idlp->al_addrs[i]);
   2561 				break;
   2562 			}
   2563 		}
   2564 	}
   2565 
   2566 	free(idlp);
   2567 
   2568 	if (matched_addr == NULL) {
   2569 		(void) close(fd);
   2570 		return (IMA_ERROR_OBJECT_NOT_FOUND);
   2571 	}
   2572 
   2573 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_CLEAR, &entry)) {
   2574 		status = errno;
   2575 		(void) close(fd);
   2576 		syslog(LOG_USER|LOG_DEBUG,
   2577 		    "ISCSI_DISCOVERY_ADDR_CLEAR ioctl failed, errno: %d",
   2578 		    errno);
   2579 		if (status == EBUSY) {
   2580 			return (IMA_ERROR_LU_IN_USE);
   2581 		} else {
   2582 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2583 		}
   2584 	}
   2585 
   2586 	(void) close(fd);
   2587 	return (IMA_STATUS_SUCCESS);
   2588 }
   2589 
   2590 IMA_STATUS SUN_IMA_SetTargetAuthMethods(
   2591 		IMA_OID targetOid,
   2592 		IMA_UINT *methodCount,
   2593 		const IMA_AUTHMETHOD *pMethodList
   2594 )
   2595 {
   2596 	return (setAuthMethods(targetOid, methodCount, pMethodList));
   2597 }
   2598 
   2599 IMA_STATUS getNegotiatedDigest(
   2600 	int digestType,
   2601 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
   2602 	SUN_IMA_CONN_PROPERTIES *connProps) {
   2603 
   2604 	IMA_UINT digest;
   2605 
   2606 	if (connProps->valuesValid == IMA_TRUE) {
   2607 		algorithm->negotiatedValid = IMA_TRUE;
   2608 
   2609 		if (digestType == ISCSI_LOGIN_PARAM_HEADER_DIGEST) {
   2610 			digest = connProps->headerDigest;
   2611 		} else {
   2612 			digest = connProps->dataDigest;
   2613 		}
   2614 
   2615 		switch (digest) {
   2616 			case ISCSI_DIGEST_NONE:
   2617 				algorithm->negotiatedAlgorithms[0] =
   2618 				    ISCSI_DIGEST_NONE;
   2619 				algorithm->negotiatedAlgorithmCount = 1;
   2620 				break;
   2621 			case ISCSI_DIGEST_CRC32C:
   2622 				algorithm->negotiatedAlgorithms[0] =
   2623 				    ISCSI_DIGEST_CRC32C;
   2624 				algorithm->negotiatedAlgorithmCount = 1;
   2625 				break;
   2626 
   2627 			case ISCSI_DIGEST_CRC32C_NONE:
   2628 				algorithm->negotiatedAlgorithms[0] =
   2629 				    ISCSI_DIGEST_CRC32C;
   2630 				algorithm->negotiatedAlgorithms[1] =
   2631 				    ISCSI_DIGEST_NONE;
   2632 				algorithm->negotiatedAlgorithmCount = 2;
   2633 				break;
   2634 			case ISCSI_DIGEST_NONE_CRC32C:
   2635 				algorithm->negotiatedAlgorithms[0] =
   2636 				    ISCSI_DIGEST_NONE;
   2637 				algorithm->negotiatedAlgorithms[1] =
   2638 				    ISCSI_DIGEST_CRC32C;
   2639 				algorithm->negotiatedAlgorithmCount = 2;
   2640 				break;
   2641 			default:
   2642 				syslog(LOG_USER|LOG_DEBUG,
   2643 				    "Invalid negotiated digest: %d",
   2644 				    digest);
   2645 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2646 		}
   2647 	} else {
   2648 		algorithm->negotiatedValid = IMA_FALSE;
   2649 	}
   2650 	return (IMA_STATUS_SUCCESS);
   2651 }
   2652 
   2653 /*
   2654  * Non-IMA defined function.
   2655  */
   2656 IMA_API	IMA_STATUS SUN_IMA_GetISNSServerAddressPropertiesList(
   2657     SUN_IMA_DISC_ADDR_PROP_LIST	**ppList
   2658 )
   2659 {
   2660 	char		    isns_server_addr_str[256];
   2661 	int		    fd;
   2662 	int		    i;
   2663 	int		    isns_server_addr_list_size;
   2664 	int		    status;
   2665 	int		    out_cnt;
   2666 	iscsi_addr_list_t   *ialp;
   2667 	/* LINTED */
   2668 	IMA_IP_ADDRESS	    *ipAddr;
   2669 
   2670 	if ((status = open_driver(&fd))) {
   2671 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2672 	}
   2673 
   2674 	ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t));
   2675 	if (ialp == NULL) {
   2676 		(void) close(fd);
   2677 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2678 	}
   2679 	ialp->al_vers = ISCSI_INTERFACE_VERSION;
   2680 	ialp->al_in_cnt = ialp->al_out_cnt = 1;
   2681 
   2682 	/*
   2683 	 * Issue ioctl to retrieve the isns server addresses.  Space has been
   2684 	 * allocted for one entry.  If more than one entry should be returned,
   2685 	 * we will re-issue the entry with the right amount of space allocted
   2686 	 */
   2687 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
   2688 		(void) close(fd);
   2689 		syslog(LOG_USER|LOG_DEBUG,
   2690 		    "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, errno: %d",
   2691 		    errno);
   2692 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2693 	}
   2694 
   2695 	isns_server_addr_list_size = sizeof (iscsi_addr_list_t);
   2696 	if (ialp->al_out_cnt > 1) {
   2697 		out_cnt = ialp->al_out_cnt;
   2698 		free(ialp);
   2699 
   2700 		isns_server_addr_list_size += (sizeof (iscsi_addr_t) *
   2701 		    out_cnt - 1);
   2702 		ialp = (iscsi_addr_list_t *)calloc(1,
   2703 		    isns_server_addr_list_size);
   2704 		if (ialp == NULL) {
   2705 			(void) close(fd);
   2706 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2707 		}
   2708 		ialp->al_vers = ISCSI_INTERFACE_VERSION;
   2709 		ialp->al_in_cnt = out_cnt;
   2710 
   2711 		/*
   2712 		 * Issue ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl again to obtain
   2713 		 * the list of all the iSNS server addresses
   2714 		 */
   2715 		if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
   2716 			free(ialp);
   2717 			(void) close(fd);
   2718 			syslog(LOG_USER|LOG_DEBUG,
   2719 			    "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, "
   2720 			    "errno: %d", errno);
   2721 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2722 
   2723 		}
   2724 	}
   2725 
   2726 	*ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)calloc(1,
   2727 	    sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) +
   2728 	    ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES));
   2729 	if (*ppList == NULL) {
   2730 		free(ialp);
   2731 		(void) close(fd);
   2732 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2733 	}
   2734 	(*ppList)->discAddrCount = ialp->al_out_cnt;
   2735 
   2736 	for (i = 0; i < ialp->al_out_cnt; i++) {
   2737 		if (ialp->al_addrs[i].a_addr.i_insize ==
   2738 		    sizeof (struct in_addr)) {
   2739 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
   2740 			id.ipAddress.ipv4Address = IMA_TRUE;
   2741 		} else if (ialp->al_addrs[i].a_addr.i_insize ==
   2742 		    sizeof (struct in6_addr)) {
   2743 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
   2744 			    id.ipAddress.ipv4Address = IMA_FALSE;
   2745 		} else {
   2746 			(void) strlcpy(isns_server_addr_str, "unknown",
   2747 			    sizeof (isns_server_addr_str));
   2748 		}
   2749 
   2750 		ipAddr = &(*ppList)->props[i].discoveryAddress.
   2751 		    hostnameIpAddress.id.ipAddress;
   2752 		bcopy(&ialp->al_addrs[i].a_addr.i_addr,
   2753 		    (*ppList)->props[i].discoveryAddress.hostnameIpAddress.id.
   2754 		    ipAddress.ipAddress,
   2755 		    sizeof (ipAddr->ipAddress));
   2756 		(*ppList)->props[i].discoveryAddress.portNumber =
   2757 		    ialp->al_addrs[i].a_port;
   2758 	}
   2759 
   2760 	free(ialp);
   2761 	(void) close(fd);
   2762 	return (IMA_STATUS_SUCCESS);
   2763 }
   2764 
   2765 /*ARGSUSED*/
   2766 /*
   2767  * Remove iSNS Server Address
   2768  */
   2769 IMA_API	IMA_STATUS SUN_IMA_RemoveISNSServerAddress(
   2770     SUN_IMA_TARGET_ADDRESS isnsServerAddress
   2771 )
   2772 {
   2773 	entry_t	entry;
   2774 	int	fd, status;
   2775 
   2776 	if ((status = open_driver(&fd))) {
   2777 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2778 	}
   2779 
   2780 	if (prepare_discovery_entry(isnsServerAddress, &entry) !=
   2781 	    DISC_ADDR_OK) {
   2782 		(void) close(fd);
   2783 		return (IMA_ERROR_INVALID_PARAMETER);
   2784 	}
   2785 
   2786 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_CLEAR, &entry)) {
   2787 		status = errno;
   2788 		(void) close(fd);
   2789 		syslog(LOG_USER|LOG_DEBUG,
   2790 		    "ISCSI_ISNS_SERVER_ADDR_CLEAR ioctl failed, errno: %d",
   2791 		    status);
   2792 		if (status == EBUSY) {
   2793 			return (IMA_ERROR_LU_IN_USE);
   2794 		} else {
   2795 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2796 		}
   2797 	}
   2798 
   2799 	(void) close(fd);
   2800 	return (IMA_STATUS_SUCCESS);
   2801 }
   2802 
   2803 /*ARGSUSED*/
   2804 IMA_API IMA_STATUS SUN_IMA_AddISNSServerAddress(
   2805 		const SUN_IMA_TARGET_ADDRESS isnsServerAddress
   2806 )
   2807 {
   2808 	entry_t			    entry;
   2809 	int			    fd;
   2810 	int			    status;
   2811 
   2812 	if ((status = open_driver(&fd))) {
   2813 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2814 	}
   2815 
   2816 	if (prepare_discovery_entry(isnsServerAddress, &entry) !=
   2817 	    DISC_ADDR_OK) {
   2818 		(void) close(fd);
   2819 		return (IMA_ERROR_INVALID_PARAMETER);
   2820 	}
   2821 
   2822 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_SET, &entry)) {
   2823 		/*
   2824 		 * Encountered problem setting the discovery address.
   2825 		 */
   2826 		(void) close(fd);
   2827 		syslog(LOG_USER|LOG_DEBUG,
   2828 		    "ISCSI_ISNS_SERVER_ADDR_SET ioctl failed, errno: %d",
   2829 		    errno);
   2830 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2831 	}
   2832 
   2833 	(void) close(fd);
   2834 	return (IMA_STATUS_SUCCESS);
   2835 }
   2836 
   2837 IMA_STATUS SUN_IMA_RetrieveISNSServerTargets(
   2838     IMA_TARGET_ADDRESS serverAddress,
   2839     SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
   2840 )
   2841 {
   2842 	int				    fd;
   2843 	int				    ctr;
   2844 	int				    server_pg_list_sz;
   2845 	int				    status;
   2846 	isns_server_portal_group_list_t	    *server_pg_list = NULL;
   2847 	isns_portal_group_list_t	    *pg_list = NULL;
   2848 	IMA_BOOL			    retry = IMA_TRUE;
   2849 	entry_t				    entry;
   2850 
   2851 #define	ISNS_SERVER_DEFAULT_NUM_TARGETS	50
   2852 
   2853 	server_pg_list_sz = sizeof (*server_pg_list) +
   2854 	    ((ISNS_SERVER_DEFAULT_NUM_TARGETS - 1) *
   2855 	    sizeof (isns_portal_group_t));
   2856 
   2857 	server_pg_list = (isns_server_portal_group_list_t *)calloc(1,
   2858 	    server_pg_list_sz);
   2859 	if (server_pg_list == NULL) {
   2860 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2861 	}
   2862 	server_pg_list->addr_port_list.pg_in_cnt =
   2863 	    ISNS_SERVER_DEFAULT_NUM_TARGETS;
   2864 
   2865 	if ((prepare_discovery_entry_IMA(serverAddress, &entry)
   2866 	    != DISC_ADDR_OK)) {
   2867 		free(server_pg_list);
   2868 		return (IMA_ERROR_INVALID_PARAMETER);
   2869 	}
   2870 	server_pg_list->addr.a_port = entry.e_port;
   2871 	server_pg_list->addr.a_addr.i_insize = entry.e_insize;
   2872 	if (entry.e_insize == sizeof (struct in_addr)) {
   2873 		server_pg_list->addr.a_addr.i_addr.in4.s_addr =
   2874 		    (entry.e_u.u_in4.s_addr);
   2875 	} else if (entry.e_insize == sizeof (struct in6_addr)) {
   2876 		bcopy(&entry.e_u.u_in6.s6_addr,
   2877 		    server_pg_list->addr.a_addr.i_addr.in6.s6_addr, 16);
   2878 	}
   2879 
   2880 	if ((status = open_driver(&fd))) {
   2881 		free(server_pg_list);
   2882 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
   2883 	}
   2884 
   2885 retry_isns:
   2886 	/*
   2887 	 * Issue ioctl to obtain the ISNS Portal Group List list
   2888 	 */
   2889 	if (ioctl(fd, ISCSI_ISNS_SERVER_GET, server_pg_list) != 0) {
   2890 		int tmp_errno = errno;
   2891 		IMA_STATUS return_status;
   2892 
   2893 		syslog(LOG_USER|LOG_DEBUG,
   2894 		    "ISCSI_ISNS_SERVER_GET ioctl failed, errno: %d", tmp_errno);
   2895 		if (tmp_errno == EACCES) {
   2896 			return_status = IMA_ERROR_OBJECT_NOT_FOUND;
   2897 		} else {
   2898 			return_status = IMA_ERROR_UNEXPECTED_OS_ERROR;
   2899 		}
   2900 		(void) close(fd);
   2901 		free(server_pg_list);
   2902 		return (return_status);
   2903 	}
   2904 	pg_list = &server_pg_list->addr_port_list;
   2905 
   2906 	/* check if all targets received */
   2907 	if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) {
   2908 		if (retry == IMA_TRUE) {
   2909 			server_pg_list_sz = sizeof (*server_pg_list) +
   2910 			    ((pg_list->pg_out_cnt - 1) *
   2911 			    sizeof (isns_server_portal_group_list_t));
   2912 			server_pg_list = (isns_server_portal_group_list_t *)
   2913 			    realloc(server_pg_list, server_pg_list_sz);
   2914 			if (server_pg_list == NULL) {
   2915 				(void) close(fd);
   2916 				return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2917 			}
   2918 			pg_list = &server_pg_list->addr_port_list;
   2919 			pg_list->pg_in_cnt = pg_list->pg_out_cnt;
   2920 			retry = IMA_FALSE;
   2921 			goto retry_isns;
   2922 		} else {
   2923 			/*
   2924 			 * don't retry after 2 attempts.  The target list
   2925 			 * shouldn't continue growing. Just continue
   2926 			 * on and display what was found.
   2927 			 */
   2928 			syslog(LOG_USER|LOG_DEBUG,
   2929 			    "ISCSI_SENDTGTS_GET overflow: "
   2930 			    "failed to obtain all targets");
   2931 			pg_list->pg_out_cnt = pg_list->pg_in_cnt;
   2932 		}
   2933 	}
   2934 
   2935 	(void) close(fd);
   2936 
   2937 	/* allocate for caller return buffer */
   2938 	*ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1,
   2939 	    sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) +
   2940 	    pg_list->pg_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
   2941 	if (*ppList == NULL) {
   2942 		free(server_pg_list);
   2943 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
   2944 	}
   2945 
   2946 	(*ppList)->keyCount = pg_list->pg_out_cnt;
   2947 
   2948 	for (ctr = 0; ctr < pg_list->pg_out_cnt; ctr++) {
   2949 		(void) mbstowcs((*ppList)->keys[ctr].name,
   2950 		    (char *)pg_list->pg_list[ctr].pg_iscsi_name,
   2951 		    IMA_NODE_NAME_LEN);
   2952 
   2953 		(*ppList)->keys[ctr].tpgt = pg_list->pg_list[ctr].pg_tag;
   2954 
   2955 		(*ppList)->keys[ctr].address.portNumber =
   2956 		    pg_list->pg_list[ctr].pg_port;
   2957 
   2958 		if (pg_list->pg_list[ctr].insize == sizeof (struct in_addr)) {
   2959 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
   2960 			    IMA_TRUE;
   2961 		} else if (pg_list->pg_list[ctr].insize ==
   2962 		    sizeof (struct in6_addr)) {
   2963 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
   2964 			    IMA_FALSE;
   2965 		} else {
   2966 			free(pg_list);
   2967 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   2968 		}
   2969 
   2970 		(void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
   2971 		    &(pg_list->pg_list[ctr].pg_ip_addr),
   2972 		    pg_list->pg_list[ctr].insize);
   2973 	}
   2974 	free(server_pg_list);
   2975 
   2976 	return (IMA_STATUS_SUCCESS);
   2977 }
   2978 
   2979 /* ARGSUSED */
   2980 IMA_STATUS SUN_IMA_GetSessionOidList(
   2981     IMA_OID initiatorOid,
   2982     IMA_OID_LIST **ppList
   2983 )
   2984 {
   2985 	return (get_target_oid_list(ISCSI_TGT_OID_LIST, ppList));
   2986 }
   2987 
   2988 /*ARGSUSED*/
   2989 IMA_API	IMA_STATUS SUN_IMA_GetTargetAuthParms(
   2990 	IMA_OID oid,
   2991 	IMA_AUTHMETHOD method,
   2992 	IMA_INITIATOR_AUTHPARMS *pParms
   2993 )
   2994 {
   2995 	int fd;
   2996 	iscsi_chap_props_t  chap_p;
   2997 
   2998 	if (pParms == NULL) {
   2999 		return (IMA_ERROR_INVALID_PARAMETER);
   3000 	}
   3001 
   3002 	if (oid.objectType != IMA_OBJECT_TYPE_TARGET) {
   3003 		return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
   3004 	}
   3005 
   3006 	if (method != IMA_AUTHMETHOD_CHAP) {
   3007 		return (IMA_ERROR_INVALID_PARAMETER);
   3008 	}
   3009 
   3010 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3011 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
   3012 		    ISCSI_DRIVER_DEVCTL, errno);
   3013 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3014 	}
   3015 
   3016 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
   3017 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
   3018 	chap_p.c_oid = (uint32_t)oid.objectSequenceNumber;
   3019 
   3020 	if (ioctl(fd, ISCSI_CHAP_GET, &chap_p) != 0) {
   3021 		syslog(LOG_USER|LOG_DEBUG,
   3022 
   3023 		    "ISCSI_CHAP_GET ioctl failed, errno: %d",
   3024 		    errno);
   3025 		(void) close(fd);
   3026 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3027 	}
   3028 
   3029 	(void) memcpy(pParms->chapParms.name, chap_p.c_user,
   3030 	    chap_p.c_user_len);
   3031 
   3032 	pParms->chapParms.nameLength = chap_p.c_user_len;
   3033 	(void) memcpy(pParms->chapParms.challengeSecret, chap_p.c_secret,
   3034 	    chap_p.c_secret_len);
   3035 
   3036 	pParms->chapParms.challengeSecretLength = chap_p.c_secret_len;
   3037 
   3038 	return (IMA_STATUS_SUCCESS);
   3039 }
   3040 
   3041 IMA_API IMA_STATUS SUN_IMA_GetBootTargetName(
   3042     IMA_NODE_NAME tgtName
   3043 )
   3044 {
   3045 	int fd;
   3046 	IMA_STATUS rtn;
   3047 	iscsi_boot_property_t bootProp;
   3048 
   3049 	bootProp.tgt_name.n_name[0] = '\0';
   3050 	bootProp.tgt_chap.c_user[0] = '\0';
   3051 	tgtName[0] = L'\0';
   3052 	rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
   3053 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3054 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
   3055 		    ISCSI_DRIVER_DEVCTL, errno);
   3056 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3057 	}
   3058 
   3059 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
   3060 		syslog(LOG_USER|LOG_DEBUG,
   3061 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
   3062 		    errno);
   3063 		(void) close(fd);
   3064 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3065 	}
   3066 
   3067 	if ((bootProp.tgt_name.n_name[0] != '\0') && (tgtName != NULL)) {
   3068 		if (mbstowcs(tgtName, (const char *)bootProp.tgt_name.n_name,
   3069 		    IMA_NODE_NAME_LEN) == (size_t)-1) {
   3070 			syslog(LOG_USER|LOG_DEBUG,
   3071 			    "ISCSI Target name covert to WCHAR fail");
   3072 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3073 		} else {
   3074 			rtn = IMA_STATUS_SUCCESS;
   3075 		}
   3076 	}
   3077 
   3078 	return (rtn);
   3079 }
   3080 
   3081 IMA_API IMA_STATUS SUN_IMA_GetBootTargetAuthParams(
   3082     IMA_INITIATOR_AUTHPARMS *pTgtCHAP
   3083 )
   3084 {
   3085 	int fd;
   3086 	IMA_STATUS rtn;
   3087 	iscsi_boot_property_t bootProp;
   3088 
   3089 	bootProp.tgt_name.n_name[0] = '\0';
   3090 	bootProp.tgt_chap.c_user[0] = '\0';
   3091 	bootProp.tgt_chap.c_secret[0] = '\0';
   3092 	rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
   3093 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3094 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
   3095 		    ISCSI_DRIVER_DEVCTL, errno);
   3096 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3097 	}
   3098 
   3099 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
   3100 		syslog(LOG_USER|LOG_DEBUG,
   3101 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
   3102 		    errno);
   3103 		(void) close(fd);
   3104 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3105 	}
   3106 
   3107 	if (pTgtCHAP != NULL) {
   3108 		if (bootProp.tgt_chap.c_user[0] != '\0') {
   3109 			(void) memcpy(pTgtCHAP->chapParms.name,
   3110 			    bootProp.tgt_chap.c_user, ISCSI_MAX_NAME_LEN);
   3111 		} else {
   3112 			pTgtCHAP->chapParms.name[0] = '\0';
   3113 		}
   3114 		if (bootProp.tgt_chap.c_secret[0] != '\0') {
   3115 			(void) memcpy(pTgtCHAP->chapParms.challengeSecret,
   3116 			    bootProp.tgt_chap.c_secret, MAX_CHAP_SECRET_LEN);
   3117 		} else {
   3118 			pTgtCHAP->chapParms.challengeSecret[0] = '\0';
   3119 		}
   3120 		rtn = IMA_STATUS_SUCCESS;
   3121 	}
   3122 	return (rtn);
   3123 }
   3124 
   3125 IMA_STATUS SUN_IMA_GetBootMpxio(
   3126     IMA_BOOL *pMpxioEnabled
   3127 )
   3128 {
   3129 	int fd;
   3130 	iscsi_boot_property_t bootProp;
   3131 
   3132 	bootProp.hba_mpxio_enabled = B_FALSE;
   3133 	*pMpxioEnabled = IMA_UNKNOWN;
   3134 
   3135 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3136 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
   3137 		    ISCSI_DRIVER_DEVCTL, errno);
   3138 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3139 	}
   3140 
   3141 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
   3142 		syslog(LOG_USER|LOG_DEBUG,
   3143 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
   3144 		    errno);
   3145 		(void) close(fd);
   3146 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3147 	}
   3148 
   3149 	if (bootProp.hba_mpxio_enabled) {
   3150 		*pMpxioEnabled = IMA_TRUE;
   3151 	} else {
   3152 		*pMpxioEnabled = IMA_FALSE;
   3153 	}
   3154 
   3155 	(void) close(fd);
   3156 	return (IMA_STATUS_SUCCESS);
   3157 }
   3158 
   3159 IMA_STATUS SUN_IMA_GetBootIscsi(
   3160     IMA_BOOL *pIscsiBoot
   3161 )
   3162 {
   3163 	int fd;
   3164 	iscsi_boot_property_t bootProp;
   3165 
   3166 	bootProp.iscsiboot = 0;
   3167 	*pIscsiBoot = 0;
   3168 
   3169 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3170 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
   3171 		    ISCSI_DRIVER_DEVCTL, errno);
   3172 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3173 	}
   3174 
   3175 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
   3176 		syslog(LOG_USER|LOG_DEBUG,
   3177 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
   3178 		    errno);
   3179 		(void) close(fd);
   3180 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3181 	}
   3182 
   3183 	*pIscsiBoot = bootProp.iscsiboot;
   3184 
   3185 	(void) close(fd);
   3186 	return (IMA_STATUS_SUCCESS);
   3187 }
   3188 
   3189 IMA_STATUS SUN_IMA_GetSvcStatus(
   3190     IMA_BOOL *pSvcEnabled)
   3191 {
   3192 	int		fd;
   3193 	uint32_t	status = ISCSI_SERVICE_DISABLED;
   3194 
   3195 	if (pSvcEnabled == NULL)
   3196 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3197 	*pSvcEnabled = 0;
   3198 
   3199 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
   3200 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
   3201 		    ISCSI_DRIVER_DEVCTL, errno);
   3202 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3203 	}
   3204 
   3205 	if (ioctl(fd, ISCSI_SMF_GET, &status) != 0) {
   3206 		syslog(LOG_USER|LOG_DEBUG,
   3207 		    "ISCSI_SVC_GET ioctl failed, errno: %d",
   3208 		    errno);
   3209 		(void) close(fd);
   3210 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
   3211 	}
   3212 
   3213 	if (status == ISCSI_SERVICE_ENABLED) {
   3214 		*pSvcEnabled = 1;
   3215 	}
   3216 
   3217 	(void) close(fd);
   3218 	return (IMA_STATUS_SUCCESS);
   3219 }
   3220