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