xref: /illumos-gate/usr/src/cmd/iscsiadm/sun_ima.c (revision c9eab9d4e096bb9b983e9b007577edfa73c32eff)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <arpa/inet.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <syslog.h>
35 #include <errno.h>
36 
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <time.h>
40 #include <libdevinfo.h>
41 
42 #include <sys/scsi/adapters/iscsi_if.h>
43 #include <sys/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 *arg);
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 	/*
1076 	 * Issue ISCSI_AUTH_CLEAR ioctl, in which the authentication information
1077 	 * is removed and the target that is not discovered by initiator
1078 	 * is removed from the memory. So this ioctl should be called at last
1079 	 */
1080 	(void) memset(&auth_p, 0, sizeof (iscsi_auth_props_t));
1081 	auth_p.a_vers = ISCSI_INTERFACE_VERSION;
1082 	auth_p.a_oid = (uint32_t)targetOid.objectSequenceNumber;
1083 	if (ioctl(fd, ISCSI_AUTH_CLEAR, &auth_p) != 0) {
1084 		/*
1085 		 * It could be that the auth data of this target has
1086 		 * never been set.
1087 		 */
1088 		syslog(LOG_USER|LOG_DEBUG,
1089 		    "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
1090 	}
1091 
1092 	(void) close(fd);
1093 	return (IMA_STATUS_SUCCESS);
1094 }
1095 
1096 IMA_API IMA_STATUS SUN_IMA_SetHeaderDigest(
1097 	IMA_OID oid,
1098 	IMA_UINT algorithmCount,
1099 	const SUN_IMA_DIGEST_ALGORITHM *algorithmList
1100 )
1101 {
1102 	IMA_MIN_MAX_VALUE mv;
1103 	uint32_t digest_algorithm;
1104 
1105 	/* We only support one preference of digest algorithm. */
1106 	if (algorithmCount > 1) {
1107 		syslog(LOG_USER|LOG_DEBUG,
1108 		    "More than one digest algorithm specified.");
1109 		return (IMA_ERROR_NOT_SUPPORTED);
1110 	}
1111 	switch (algorithmList[0]) {
1112 	case SUN_IMA_DIGEST_NONE:
1113 		digest_algorithm = ISCSI_DIGEST_NONE;
1114 		break;
1115 	case SUN_IMA_DIGEST_CRC32:
1116 		digest_algorithm = ISCSI_DIGEST_CRC32C;
1117 		break;
1118 	default:
1119 		digest_algorithm = ISCSI_DIGEST_NONE;
1120 		break;
1121 	}
1122 	mv.currentValue = digest_algorithm;
1123 	return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
1124 	    ISCSI_LOGIN_PARAM_HEADER_DIGEST));
1125 }
1126 
1127 IMA_API IMA_STATUS SUN_IMA_SetDataDigest(
1128 	IMA_OID oid,
1129 	IMA_UINT algorithmCount,
1130 	const SUN_IMA_DIGEST_ALGORITHM *algorithmList
1131 )
1132 {
1133 	IMA_MIN_MAX_VALUE mv;
1134 	uint32_t digest_algorithm;
1135 
1136 	/* We only support one preference of digest algorithm. */
1137 	if (algorithmCount > 1) {
1138 		syslog(LOG_USER|LOG_DEBUG,
1139 		    "More than one digest algorithm specified.");
1140 		return (IMA_ERROR_NOT_SUPPORTED);
1141 	}
1142 	switch (algorithmList[0]) {
1143 	case SUN_IMA_DIGEST_NONE:
1144 		digest_algorithm = ISCSI_DIGEST_NONE;
1145 		break;
1146 	case SUN_IMA_DIGEST_CRC32:
1147 		digest_algorithm = ISCSI_DIGEST_CRC32C;
1148 		break;
1149 	default:
1150 		digest_algorithm = ISCSI_DIGEST_NONE;
1151 		break;
1152 	}
1153 	mv.currentValue = digest_algorithm;
1154 	return (setISCSINodeParameter(MIN_MAX_PARAM, &oid, &mv,
1155 	    ISCSI_LOGIN_PARAM_DATA_DIGEST));
1156 }
1157 
1158 IMA_API IMA_STATUS SUN_IMA_GetHeaderDigest(
1159 	IMA_OID oid,
1160 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
1161 )
1162 {
1163 	return (getDigest(oid, ISCSI_LOGIN_PARAM_HEADER_DIGEST, algorithm));
1164 }
1165 
1166 IMA_API IMA_STATUS SUN_IMA_GetDataDigest(
1167 	IMA_OID oid,
1168 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
1169 )
1170 {
1171 	return (getDigest(oid, ISCSI_LOGIN_PARAM_DATA_DIGEST, algorithm));
1172 }
1173 
1174 typedef struct walk_devlink {
1175 	char *path;
1176 	size_t len;
1177 	char **linkpp;
1178 } walk_devlink_t;
1179 
1180 IMA_STATUS SUN_IMA_GetLuProperties(
1181 		IMA_OID luId,
1182 		SUN_IMA_LU_PROPERTIES *pProps
1183 )
1184 {
1185 	IMA_STATUS		status;
1186 	iscsi_lun_list_t	*pLunList;
1187 	int			j;
1188 	IMA_BOOL		lunMatch = IMA_FALSE;
1189 	int			fd;
1190 	int			openStatus;
1191 	iscsi_lun_props_t	lun;
1192 	di_devlink_handle_t	hdl;
1193 	walk_devlink_t		warg;
1194 	char			*minor_path, *devlinkp, lunpath[MAXPATHLEN];
1195 
1196 	if (luId.objectType != IMA_OBJECT_TYPE_LU) {
1197 		return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
1198 	}
1199 
1200 	/*
1201 	 * get list of lun oids for all targets
1202 	 */
1203 	status = get_target_lun_oid_list(NULL, &pLunList);
1204 	if (!IMA_SUCCESS(status)) {
1205 		return (status);
1206 	}
1207 	for (j = 0; j < pLunList->ll_out_cnt; j++) {
1208 		/*
1209 		 * for each lun, check if match is found
1210 		 */
1211 		if (pLunList->ll_luns[j].l_oid == luId.objectSequenceNumber) {
1212 			/*
1213 			 * match found, break out of lun loop
1214 			 */
1215 			lunMatch = IMA_TRUE;
1216 			break;
1217 		}
1218 	}
1219 
1220 	if (lunMatch == IMA_TRUE) {
1221 		(void) memset(&lun, 0, sizeof (iscsi_lun_props_t));
1222 		lun.lp_vers = ISCSI_INTERFACE_VERSION;
1223 		lun.lp_tgt_oid = pLunList->ll_luns[j].l_tgt_oid;
1224 		lun.lp_oid = pLunList->ll_luns[j].l_oid;
1225 	}
1226 
1227 	free(pLunList);
1228 
1229 	if (lunMatch == IMA_FALSE) {
1230 		return (IMA_ERROR_OBJECT_NOT_FOUND);
1231 	}
1232 
1233 	/*
1234 	 * get lun properties
1235 	 */
1236 	if ((openStatus = open_driver(&fd))) {
1237 		return (SUN_IMA_ERROR_SYSTEM_ERROR | openStatus);
1238 	}
1239 
1240 	if (ioctl(fd, ISCSI_LUN_PROPS_GET, &lun)) {
1241 		syslog(LOG_USER|LOG_DEBUG,
1242 		    "ISCSI_LUN_PROPS_GET ioctl failed, errno: %d", errno);
1243 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1244 	}
1245 
1246 	(void) close(fd);
1247 
1248 	/*
1249 	 * set property values
1250 	 */
1251 	pProps->imaProps.associatedTargetOid.objectType =
1252 	    IMA_OBJECT_TYPE_TARGET;
1253 	pProps->imaProps.associatedTargetOid.ownerId = 1;
1254 	pProps->imaProps.associatedTargetOid.objectSequenceNumber = lun.lp_oid;
1255 	pProps->imaProps.targetLun = (IMA_UINT64)lun.lp_num;
1256 	(void) strncpy(pProps->vendorId, lun.lp_vid, SUN_IMA_LU_VENDOR_ID_LEN);
1257 	(void) strncpy(pProps->productId, lun.lp_pid,
1258 	    SUN_IMA_LU_PRODUCT_ID_LEN);
1259 	/*
1260 	 * lun.lp_status is defined as
1261 	 *	LunValid = 0
1262 	 *	LunDoesNotExist = 1
1263 	 * IMA_LU_PROPS.exposedtoOS is defined as an IMA_BOOL
1264 	 *	IMA_TRUE = 1
1265 	 *	IMA_FALSE = 0
1266 	 */
1267 	pProps->imaProps.exposedToOs = !lun.lp_status;
1268 	if (gmtime_r(&lun.lp_time_online, &pProps->imaProps.timeExposedToOs)
1269 	    == NULL) {
1270 		(void) memset(&pProps->imaProps.timeExposedToOs, 0,
1271 		    sizeof (pProps->imaProps.timeExposedToOs));
1272 	}
1273 
1274 	if (lun.lp_status == LunValid) {
1275 		if ((strlen(lun.lp_pathname) + strlen("/devices")) >
1276 		    (MAXPATHLEN -1)) {
1277 			/*
1278 			 * lun.lp_pathname length too long
1279 			 */
1280 			pProps->imaProps.osDeviceNameValid = IMA_FALSE;
1281 			pProps->imaProps.osParallelIdsValid = IMA_FALSE;
1282 			return (IMA_STATUS_SUCCESS);
1283 		}
1284 		if ((strstr(lun.lp_pathname, "st@") != NULL) ||
1285 		    (strstr(lun.lp_pathname, "tape@") != NULL)) {
1286 			(void) strlcat(lun.lp_pathname, ":n", MAXPATHLEN);
1287 		} else if ((strstr(lun.lp_pathname, "sd@") != NULL) ||
1288 		    (strstr(lun.lp_pathname, "ssd@") != NULL) ||
1289 		    (strstr(lun.lp_pathname, "disk@") != NULL)) {
1290 			/*
1291 			 * modify returned pathname to obtain the 2nd slice
1292 			 * of the raw disk
1293 			 */
1294 			(void) strlcat(lun.lp_pathname, ":c,raw", MAXPATHLEN);
1295 		} else if ((strstr(lun.lp_pathname, "ses@") != NULL) ||
1296 		    (strstr(lun.lp_pathname, "enclosure@") != NULL)) {
1297 			(void) strlcat(lun.lp_pathname, ":0", MAXPATHLEN);
1298 		}
1299 
1300 		(void) snprintf(lunpath, sizeof (lun.lp_pathname),
1301 		    "/devices%s", lun.lp_pathname);
1302 		if (strchr(lunpath, ':')) {
1303 			minor_path = lunpath;
1304 			if (strstr(minor_path, "/devices") != NULL) {
1305 				minor_path = lunpath +
1306 				    strlen("/devices");
1307 			} else {
1308 				minor_path = lunpath;
1309 			}
1310 			warg.path = NULL;
1311 		} else {
1312 			minor_path = NULL;
1313 			warg.len = strlen(lunpath);
1314 			warg.path = lunpath;
1315 		}
1316 		devlinkp = NULL;
1317 		warg.linkpp = &devlinkp;
1318 
1319 		/*
1320 		 * Pathname returned by driver is the physical device path.
1321 		 * This name needs to be converted to the OS device name.
1322 		 */
1323 		if (hdl = di_devlink_init(lun.lp_pathname, DI_MAKE_LINK)) {
1324 			pProps->imaProps.osDeviceName[0] = L'\0';
1325 			(void) di_devlink_walk(hdl, NULL, minor_path,
1326 			    DI_PRIMARY_LINK, (void *)&warg, get_lun_devlink);
1327 			if (devlinkp != NULL) {
1328 				/* OS device name synchronously made */
1329 				(void) mbstowcs(pProps->imaProps.osDeviceName,
1330 				    devlinkp, MAXPATHLEN);
1331 				free(devlinkp);
1332 				pProps->imaProps.osDeviceNameValid = IMA_TRUE;
1333 			} else {
1334 				pProps->imaProps.osDeviceNameValid = IMA_FALSE;
1335 			}
1336 
1337 			(void) di_devlink_fini(&hdl);
1338 
1339 		} else {
1340 			pProps->imaProps.osDeviceNameValid = IMA_FALSE;
1341 		}
1342 
1343 	} else {
1344 		pProps->imaProps.osDeviceNameValid = IMA_FALSE;
1345 	}
1346 
1347 	pProps->imaProps.osParallelIdsValid = IMA_FALSE;
1348 
1349 	return (IMA_STATUS_SUCCESS);
1350 }
1351 
1352 static int
1353 get_lun_devlink(di_devlink_t link, void *arg)
1354 {
1355 	walk_devlink_t *warg = (walk_devlink_t *)arg;
1356 	if (warg->path) {
1357 		char *content = (char *)di_devlink_content(link);
1358 		char *start = strstr(content, "/devices");
1359 		if (start == NULL ||
1360 		    strncmp(start, warg->path, warg->len) != 0 ||
1361 		    start[warg->len] != ':')
1362 			return (DI_WALK_CONTINUE);
1363 	}
1364 
1365 	*(warg->linkpp) = strdup(di_devlink_path(link));
1366 	return (DI_WALK_TERMINATE);
1367 
1368 }
1369 
1370 /*
1371  * SUN_IMA_GetConnectionOidList -
1372  *
1373  * Non-IMA defined function.
1374  */
1375 IMA_API	IMA_STATUS SUN_IMA_GetConnOidList(
1376 	IMA_OID			*oid,
1377 	IMA_OID_LIST		**ppList
1378 )
1379 {
1380 	IMA_STATUS		imaStatus;
1381 	IMA_OID_LIST		*imaOidList;
1382 	iscsi_conn_list_t	*iscsiConnList = NULL;
1383 	int			i;
1384 	size_t			allocLen;
1385 
1386 	if ((lhbaObjectId.objectType == oid->objectType) &&
1387 	    (lhbaObjectId.ownerId == oid->ownerId) &&
1388 	    (lhbaObjectId.objectSequenceNumber == oid->objectSequenceNumber)) {
1389 		imaStatus = getConnOidList(NULL, &iscsiConnList);
1390 	} else {
1391 		if (oid->objectType == IMA_OBJECT_TYPE_TARGET) {
1392 			imaStatus = getConnOidList(oid, &iscsiConnList);
1393 		} else {
1394 			return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
1395 		}
1396 	}
1397 	if (imaStatus != IMA_STATUS_SUCCESS) {
1398 		return (imaStatus);
1399 	}
1400 
1401 	/*
1402 	 * Based on the results a SUN_IMA_CONN_LIST structure is allocated.
1403 	 */
1404 	allocLen  = iscsiConnList->cl_out_cnt * sizeof (IMA_OID);
1405 	allocLen += sizeof (IMA_OID_LIST) - sizeof (IMA_OID);
1406 	imaOidList = (IMA_OID_LIST *)calloc(1, allocLen);
1407 
1408 	if (imaOidList == NULL) {
1409 		free(iscsiConnList);
1410 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1411 	}
1412 
1413 	/* The data is transfered from iscsiConnList to imaConnList. */
1414 	imaOidList->oidCount = iscsiConnList->cl_out_cnt;
1415 	for (i = 0; i < iscsiConnList->cl_out_cnt; i++) {
1416 		imaOidList->oids[i].objectType = SUN_IMA_OBJECT_TYPE_CONN;
1417 		imaOidList->oids[i].ownerId = 1;
1418 		imaOidList->oids[i].objectSequenceNumber =
1419 		    iscsiConnList->cl_list[i].c_oid;
1420 	}
1421 	/* The pointer to the SUN_IMA_CONN_LIST structure is returned. */
1422 	*ppList = imaOidList;
1423 
1424 	free(iscsiConnList);
1425 	return (IMA_STATUS_SUCCESS);
1426 }
1427 
1428 /*
1429  * SUN_IMA_GetConnProperties -
1430  *
1431  * Non-IMA defined function.
1432  */
1433 IMA_API	IMA_STATUS SUN_IMA_GetConnProperties(
1434 	IMA_OID			*connOid,
1435 	SUN_IMA_CONN_PROPERTIES	**pProps
1436 )
1437 {
1438 	iscsi_conn_list_t	*pConnList;
1439 	iscsi_conn_props_t	*pConnProps;
1440 	/* LINTED */
1441 	struct sockaddr_in6	*addrIn6;
1442 	/* LINTED */
1443 	struct sockaddr_in	*addrIn;
1444 	SUN_IMA_CONN_PROPERTIES	*pImaConnProps;
1445 	IMA_STATUS		imaStatus;
1446 	int			i;
1447 
1448 	/* If there is any error *pProps should be set to NULL */
1449 	*pProps = NULL;
1450 
1451 	pImaConnProps = (SUN_IMA_CONN_PROPERTIES *)calloc(1,
1452 	    sizeof (SUN_IMA_CONN_PROPERTIES));
1453 
1454 	if (pImaConnProps == NULL) {
1455 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1456 	}
1457 
1458 	imaStatus = getConnOidList(NULL, &pConnList);
1459 
1460 	if (imaStatus != IMA_STATUS_SUCCESS) {
1461 		free(pImaConnProps);
1462 		return (imaStatus);
1463 	}
1464 
1465 	/*
1466 	 * Walk the list returned to find our connection.
1467 	 */
1468 	for (i = 0; i < pConnList->cl_out_cnt; i++) {
1469 
1470 		if (pConnList->cl_list[i].c_oid ==
1471 		    (uint32_t)connOid->objectSequenceNumber) {
1472 
1473 			/* This is our connection. */
1474 			imaStatus = getConnProps(&pConnList->cl_list[i],
1475 			    &pConnProps);
1476 
1477 			if (imaStatus != IMA_STATUS_SUCCESS) {
1478 				free(pConnList);
1479 				free(pImaConnProps);
1480 				return (imaStatus);
1481 			}
1482 			pImaConnProps->connectionID = pConnProps->cp_cid;
1483 
1484 			/*
1485 			 * Local Propeties
1486 			 */
1487 			if (pConnProps->cp_local.soa4.sin_family == AF_INET) {
1488 
1489 				pImaConnProps->local.ipAddress.ipv4Address =
1490 				    IMA_TRUE;
1491 				pImaConnProps->local.portNumber =
1492 				    pConnProps->cp_local.soa4.sin_port;
1493 				addrIn = &(pConnProps->cp_local.soa4);
1494 				bcopy(&pConnProps->cp_local.soa4.sin_addr,
1495 				    pImaConnProps->local.ipAddress.ipAddress,
1496 				    sizeof (addrIn->sin_addr));
1497 
1498 			} else {
1499 				pImaConnProps->local.ipAddress.ipv4Address =
1500 				    IMA_FALSE;
1501 				pImaConnProps->local.portNumber =
1502 				    pConnProps->cp_local.soa6.sin6_port;
1503 				addrIn6 = &(pConnProps->cp_local.soa6);
1504 				bcopy(&pConnProps->cp_local.soa6.sin6_addr,
1505 				    pImaConnProps->local.ipAddress.ipAddress,
1506 				    sizeof (addrIn6->sin6_addr));
1507 
1508 			}
1509 
1510 			/*
1511 			 * Peer Propeties
1512 			 */
1513 			if (pConnProps->cp_peer.soa4.sin_family == AF_INET) {
1514 
1515 				pImaConnProps->peer.ipAddress.ipv4Address =
1516 				    IMA_TRUE;
1517 				pImaConnProps->peer.portNumber =
1518 				    pConnProps->cp_peer.soa4.sin_port;
1519 				addrIn = &(pConnProps->cp_local.soa4);
1520 				bcopy(&pConnProps->cp_peer.soa4.sin_addr,
1521 				    pImaConnProps->peer.ipAddress.ipAddress,
1522 				    sizeof (addrIn->sin_addr));
1523 
1524 			} else {
1525 				pImaConnProps->peer.ipAddress.ipv4Address =
1526 				    IMA_FALSE;
1527 				pImaConnProps->peer.portNumber =
1528 				    pConnProps->cp_peer.soa6.sin6_port;
1529 
1530 				addrIn6 = &pConnProps->cp_local.soa6;
1531 				bcopy(&pConnProps->cp_peer.soa6.sin6_addr,
1532 				    pImaConnProps->peer.ipAddress.ipAddress,
1533 				    sizeof (addrIn6->sin6_addr));
1534 			}
1535 
1536 
1537 			pImaConnProps->valuesValid =
1538 			    pConnProps->cp_params_valid;
1539 			pImaConnProps->defaultTime2Retain =
1540 			    pConnProps->cp_params.default_time_to_retain;
1541 			pImaConnProps->defaultTime2Wait =
1542 			    pConnProps->cp_params.default_time_to_wait;
1543 			pImaConnProps->errorRecoveryLevel =
1544 			    pConnProps->cp_params.error_recovery_level;
1545 			pImaConnProps->firstBurstLength =
1546 			    pConnProps->cp_params.first_burst_length;
1547 			pImaConnProps->maxBurstLength =
1548 			    pConnProps->cp_params.max_burst_length;
1549 			pImaConnProps->maxConnections =
1550 			    pConnProps->cp_params.max_connections;
1551 			pImaConnProps->maxOutstandingR2T =
1552 			    pConnProps->cp_params.max_outstanding_r2t;
1553 			pImaConnProps->maxRecvDataSegmentLength =
1554 			    pConnProps->cp_params.max_recv_data_seg_len;
1555 
1556 			pImaConnProps->dataPduInOrder =
1557 			    pConnProps->cp_params.data_pdu_in_order;
1558 			pImaConnProps->dataSequenceInOrder =
1559 			    pConnProps->cp_params.data_sequence_in_order;
1560 			pImaConnProps->immediateData =
1561 			    pConnProps->cp_params.immediate_data;
1562 			pImaConnProps->initialR2T =
1563 			    pConnProps->cp_params.initial_r2t;
1564 
1565 			pImaConnProps->headerDigest =
1566 			    pConnProps->cp_params.header_digest;
1567 			pImaConnProps->dataDigest =
1568 			    pConnProps->cp_params.data_digest;
1569 
1570 			free(pConnProps);
1571 			break;
1572 		}
1573 	}
1574 	free(pConnList);
1575 	*pProps = pImaConnProps;
1576 	return (IMA_STATUS_SUCCESS);
1577 }
1578 
1579 
1580 /*
1581  * SUN_IMA_GetConfigSessions -
1582  *
1583  * Non-IMA defined function.
1584  */
1585 IMA_API IMA_STATUS SUN_IMA_GetConfigSessions(
1586     IMA_OID targetOid,
1587     SUN_IMA_CONFIG_SESSIONS **pConfigSessions
1588 )
1589 {
1590 	int			fd;
1591 	int			status;
1592 	iscsi_config_sess_t	*ics;
1593 	int			size, idx;
1594 
1595 	/* Allocate and setup initial buffer */
1596 	size = sizeof (*ics);
1597 	ics = (iscsi_config_sess_t *)calloc(1, size);
1598 	if (ics == NULL) {
1599 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1600 	}
1601 	ics->ics_ver = ISCSI_INTERFACE_VERSION;
1602 	ics->ics_oid = targetOid.objectSequenceNumber;
1603 	ics->ics_in  = 1;
1604 
1605 	/* Open driver devctl for ioctl */
1606 	if ((status = open_driver(&fd))) {
1607 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1608 	}
1609 
1610 	/* Issue ioctl request */
1611 	if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
1612 		syslog(LOG_USER|LOG_DEBUG,
1613 		    "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
1614 		    errno);
1615 		(void) close(fd);
1616 		free(ics);
1617 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1618 	}
1619 
1620 	/* Check if we need to collect more information */
1621 	idx = ics->ics_out;
1622 	if (idx > 1) {
1623 
1624 		/* Free old buffer and reallocate re-sized buffer */
1625 		free(ics);
1626 		size = ISCSI_SESSION_CONFIG_SIZE(idx);
1627 		ics = (iscsi_config_sess_t *)calloc(1, size);
1628 		if (ics == NULL) {
1629 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
1630 		}
1631 		ics->ics_ver = ISCSI_INTERFACE_VERSION;
1632 		ics->ics_oid = targetOid.objectSequenceNumber;
1633 		ics->ics_in = idx;
1634 
1635 		/* Issue ioctl request */
1636 		if (ioctl(fd, ISCSI_GET_CONFIG_SESSIONS, ics) != 0) {
1637 			syslog(LOG_USER|LOG_DEBUG,
1638 			    "ISCSI_GET_CONFIG_SESSIONS ioctl failed, errno: %d",
1639 			    errno);
1640 			(void) close(fd);
1641 			free(ics);
1642 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1643 		}
1644 	}
1645 	(void) close(fd);
1646 
1647 	/* Allocate output buffer */
1648 	size = sizeof (SUN_IMA_CONFIG_SESSIONS) +
1649 	    ((ics->ics_out - 1) * sizeof (IMA_ADDRESS_KEY));
1650 	*pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
1651 	if ((*pConfigSessions) == NULL) {
1652 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1653 	}
1654 
1655 	/* Copy output information */
1656 	(*pConfigSessions)->bound =
1657 	    (ics->ics_bound == B_TRUE ?  IMA_TRUE : IMA_FALSE);
1658 	(*pConfigSessions)->in = ics->ics_in;
1659 	(*pConfigSessions)->out = ics->ics_out;
1660 	for (idx = 0; idx < ics->ics_in; idx++) {
1661 		if (ics->ics_bindings[idx].i_insize ==
1662 		    sizeof (struct in_addr)) {
1663 			(*pConfigSessions)->bindings[idx].ipAddress.
1664 			    ipv4Address = IMA_TRUE;
1665 			bcopy(&ics->ics_bindings[idx].i_addr.in4,
1666 			    (*pConfigSessions)->bindings[idx].ipAddress.
1667 			    ipAddress, sizeof (struct in_addr));
1668 		} else {
1669 			(*pConfigSessions)->bindings[idx].ipAddress.
1670 			    ipv4Address = IMA_FALSE;
1671 			bcopy(&ics->ics_bindings[idx].i_addr.in6,
1672 			    (*pConfigSessions)->bindings[idx].ipAddress.
1673 			    ipAddress, sizeof (struct in6_addr));
1674 		}
1675 	}
1676 
1677 	free(ics);
1678 	return (IMA_STATUS_SUCCESS);
1679 }
1680 
1681 /*
1682  * SUN_IMA_SetConfigSessions -
1683  *
1684  * Non-IMA defined function.
1685  */
1686 IMA_API IMA_STATUS SUN_IMA_SetConfigSessions(
1687     IMA_OID targetOid,
1688     SUN_IMA_CONFIG_SESSIONS *pConfigSessions
1689 )
1690 {
1691 	int		    fd;
1692 	int		    status;
1693 	iscsi_config_sess_t *ics;
1694 	int		    idx, size;
1695 
1696 	/* verify allowed range of sessions */
1697 	if ((pConfigSessions->in < ISCSI_MIN_CONFIG_SESSIONS) ||
1698 	    (pConfigSessions->in > ISCSI_MAX_CONFIG_SESSIONS)) {
1699 		return (IMA_ERROR_INVALID_PARAMETER);
1700 	}
1701 
1702 	/* allocate record config_sess size */
1703 	size = ISCSI_SESSION_CONFIG_SIZE(pConfigSessions->in);
1704 	ics = (iscsi_config_sess_t *)malloc(size);
1705 
1706 	/* setup config_sess information */
1707 	(void) memset(ics, 0, sizeof (iscsi_config_sess_t));
1708 	ics->ics_ver = ISCSI_INTERFACE_VERSION;
1709 	ics->ics_oid = targetOid.objectSequenceNumber;
1710 	ics->ics_bound =
1711 	    (pConfigSessions->bound == IMA_TRUE ?  B_TRUE : B_FALSE);
1712 	ics->ics_in  = pConfigSessions->in;
1713 	for (idx = 0; idx < ics->ics_in; idx++) {
1714 		if (pConfigSessions->bindings[idx].ipAddress.
1715 		    ipv4Address == IMA_TRUE) {
1716 			ics->ics_bindings[idx].i_insize =
1717 			    sizeof (struct in_addr);
1718 			bcopy(pConfigSessions->bindings[idx].
1719 			    ipAddress.ipAddress,
1720 			    &ics->ics_bindings[idx].i_addr.in4,
1721 			    sizeof (struct in_addr));
1722 		} else {
1723 			ics->ics_bindings[idx].i_insize =
1724 			    sizeof (struct in6_addr);
1725 			bcopy(pConfigSessions->bindings[idx].
1726 			    ipAddress.ipAddress,
1727 			    &ics->ics_bindings[idx].i_addr.in6,
1728 			    sizeof (struct in6_addr));
1729 		}
1730 	}
1731 
1732 	/* open driver */
1733 	if ((status = open_driver(&fd))) {
1734 		free(ics);
1735 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1736 	}
1737 
1738 	/* issue ioctl request */
1739 	if (ioctl(fd, ISCSI_SET_CONFIG_SESSIONS, ics) != 0) {
1740 		syslog(LOG_USER|LOG_DEBUG,
1741 		    "ISCSI_SET_CONFIG_SESSIONS ioctl failed, errno: %d",
1742 		    errno);
1743 		(void) close(fd);
1744 		free(ics);
1745 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1746 	}
1747 	(void) close(fd);
1748 	free(ics);
1749 	return (IMA_STATUS_SUCCESS);
1750 }
1751 
1752 /* A helper function to obtain iSCSI node parameters. */
1753 static IMA_STATUS
1754 getISCSINodeParameter(
1755     int paramType,
1756     IMA_OID *oid,
1757     void *pProps,
1758     uint32_t paramIndex
1759 )
1760 {
1761 	int		    fd;
1762 	int 		status;
1763 	iscsi_param_get_t   pg;
1764 
1765 	if ((status = open_driver(&fd))) {
1766 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1767 	}
1768 
1769 	(void) memset(&pg, 0, sizeof (iscsi_param_get_t));
1770 	pg.g_vers = ISCSI_INTERFACE_VERSION;
1771 	pg.g_oid = (uint32_t)oid->objectSequenceNumber;
1772 	pg.g_param = paramIndex;
1773 	pg.g_param_type = ISCSI_SESS_PARAM;
1774 
1775 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
1776 		syslog(LOG_USER|LOG_DEBUG,
1777 		    "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
1778 		(void) close(fd);
1779 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1780 	}
1781 
1782 	switch (paramType) {
1783 		IMA_BOOL_VALUE *bp;
1784 		IMA_MIN_MAX_VALUE *mp;
1785 
1786 		case MIN_MAX_PARAM:
1787 			mp = (IMA_MIN_MAX_VALUE *)pProps;
1788 
1789 			mp->currentValueValid =
1790 			    (pg.g_value.v_valid == B_TRUE) ?
1791 			    IMA_TRUE : IMA_FALSE;
1792 			mp->currentValue = pg.g_value.v_integer.i_current;
1793 			mp->defaultValue = pg.g_value.v_integer.i_default;
1794 			mp->minimumValue = pg.g_value.v_integer.i_min;
1795 			mp->maximumValue = pg.g_value.v_integer.i_max;
1796 			mp->incrementValue = pg.g_value.v_integer.i_incr;
1797 			break;
1798 
1799 		case BOOL_PARAM:
1800 			bp = (IMA_BOOL_VALUE *)pProps;
1801 			bp->currentValueValid =
1802 			    (pg.g_value.v_valid == B_TRUE) ?
1803 			    IMA_TRUE : IMA_FALSE;
1804 			bp->currentValue = pg.g_value.v_bool.b_current;
1805 			bp->defaultValue = pg.g_value.v_bool.b_default;
1806 			break;
1807 
1808 		default:
1809 			break;
1810 	}
1811 
1812 	/* Issue ISCSI_PARAM_GET ioctl again to obtain connection parameters. */
1813 	pg.g_param_type = ISCSI_CONN_PARAM;
1814 	if (ioctl(fd, ISCSI_PARAM_GET, &pg) != 0) {
1815 		syslog(LOG_USER|LOG_DEBUG,
1816 		    "ISCSI_PARAM_GET ioctl failed, errno: %d", errno);
1817 		(void) close(fd);
1818 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1819 	}
1820 
1821 	(void) close(fd);
1822 	return (IMA_STATUS_SUCCESS);
1823 }
1824 
1825 /* A helper function to set iSCSI node parameters. */
1826 static IMA_STATUS
1827 setISCSINodeParameter(
1828     int paramType,
1829     IMA_OID *oid,
1830     void *pProp,
1831     uint32_t paramIndex
1832 )
1833 {
1834 	int		    fd;
1835 	int			status;
1836 	iscsi_param_set_t   ps;
1837 
1838 	if ((status = open_driver(&fd))) {
1839 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1840 	}
1841 
1842 	(void) memset(&ps, 0, sizeof (iscsi_param_set_t));
1843 	ps.s_vers = ISCSI_INTERFACE_VERSION;
1844 	ps.s_oid = (uint32_t)oid->objectSequenceNumber;
1845 	ps.s_param = paramIndex;
1846 
1847 	switch (paramType) {
1848 		IMA_BOOL_VALUE *bp;
1849 		IMA_MIN_MAX_VALUE *mp;
1850 
1851 		case MIN_MAX_PARAM:
1852 			mp = (IMA_MIN_MAX_VALUE *)pProp;
1853 			ps.s_value.v_integer = mp->currentValue;
1854 			break;
1855 		case BOOL_PARAM:
1856 			bp = (IMA_BOOL_VALUE *)pProp;
1857 			ps.s_value.v_bool =
1858 			    (bp->currentValue == IMA_TRUE) ?
1859 			    B_TRUE : B_FALSE;
1860 			break;
1861 
1862 		default:
1863 			break;
1864 	}
1865 	if (ioctl(fd, ISCSI_PARAM_SET, &ps)) {
1866 		(void) close(fd);
1867 		syslog(LOG_USER|LOG_DEBUG,
1868 		    "ISCSI_PARAM_SET ioctl failed, errno: %d", errno);
1869 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1870 	}
1871 
1872 	(void) close(fd);
1873 	return (IMA_STATUS_SUCCESS);
1874 }
1875 
1876 static int
1877 prepare_discovery_entry(
1878     SUN_IMA_TARGET_ADDRESS discoveryAddress,
1879     entry_t *entry
1880 )
1881 {
1882 	return (prepare_discovery_entry_IMA(discoveryAddress.imaStruct, entry));
1883 }
1884 
1885 static int
1886 prepare_discovery_entry_IMA(
1887     IMA_TARGET_ADDRESS discoveryAddress,
1888     entry_t *entry
1889 )
1890 {
1891 	(void) memset(entry, 0, sizeof (entry_t));
1892 	entry->e_vers = ISCSI_INTERFACE_VERSION;
1893 	entry->e_oid = ISCSI_OID_NOTSET;
1894 
1895 	if (discoveryAddress.hostnameIpAddress.id.ipAddress.
1896 	    ipv4Address == IMA_FALSE) {
1897 
1898 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.
1899 		    ipAddress, entry->e_u.u_in6.s6_addr,
1900 		    sizeof (entry->e_u.u_in6.s6_addr));
1901 
1902 		entry->e_insize = sizeof (struct in6_addr);
1903 	} else {
1904 
1905 		bcopy(discoveryAddress.hostnameIpAddress.id.ipAddress.
1906 		    ipAddress, &entry->e_u.u_in4.s_addr,
1907 		    sizeof (entry->e_u.u_in4.s_addr));
1908 
1909 		entry->e_insize = sizeof (struct in_addr);
1910 	}
1911 
1912 	entry->e_port = discoveryAddress.portNumber;
1913 	entry->e_tpgt = 0;
1914 	return (DISC_ADDR_OK);
1915 }
1916 
1917 static IMA_STATUS configure_discovery_method(
1918     IMA_BOOL enable,
1919     iSCSIDiscoveryMethod_t method
1920 )
1921 {
1922 	int	fd, status;
1923 
1924 	if ((status = open_driver(&fd))) {
1925 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1926 	}
1927 
1928 	if (enable == IMA_FALSE) {
1929 		if (ioctl(fd, ISCSI_DISCOVERY_CLEAR, &method)) {
1930 			status = errno;
1931 			(void) close(fd);
1932 			syslog(LOG_USER|LOG_DEBUG,
1933 			    "ISCSI_DISCOVERY_CLEAR ioctl failed, errno: %d",
1934 			    status);
1935 			if (status == EBUSY) {
1936 				return (IMA_ERROR_LU_IN_USE);
1937 			} else {
1938 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1939 			}
1940 		}
1941 
1942 		(void) close(fd);
1943 		return (IMA_STATUS_SUCCESS);
1944 	} else {
1945 		/* Set the discovery method */
1946 		if (ioctl(fd, ISCSI_DISCOVERY_SET, &method)) {
1947 			status = errno;
1948 			(void) close(fd);
1949 			syslog(LOG_USER|LOG_DEBUG,
1950 			    "ISCSI_DISCOVERY_SET ioctl failed, errno: %d",
1951 			    status);
1952 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
1953 		}
1954 
1955 		(void) close(fd);
1956 		return (IMA_STATUS_SUCCESS);
1957 	}
1958 }
1959 
1960 /* LINTED E_STATIC_UNUSED */
1961 static IMA_BOOL authMethodMatch(
1962     IMA_AUTHMETHOD matchingMethod,
1963     IMA_AUTHMETHOD *methodList,
1964     IMA_UINT maxEntries
1965 )
1966 {
1967 	IMA_UINT i;
1968 
1969 	for (i = 0; i < maxEntries; i++) {
1970 		if (methodList[i] == matchingMethod) {
1971 			return (IMA_TRUE);
1972 		}
1973 	}
1974 
1975 	return (IMA_FALSE);
1976 }
1977 
1978 static IMA_STATUS get_target_oid_list(
1979     uint32_t targetListType,
1980     IMA_OID_LIST **ppList)
1981 {
1982 	int		    fd;
1983 	int		    i;
1984 	int		    target_list_size;
1985 	int		    status;
1986 	int		    out_cnt;
1987 	iscsi_target_list_t *idlp;
1988 
1989 	if ((status = open_driver(&fd))) {
1990 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
1991 	}
1992 
1993 	idlp = (iscsi_target_list_t *)calloc(1, sizeof (iscsi_target_list_t));
1994 	if (idlp == NULL) {
1995 		(void) close(fd);
1996 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
1997 	}
1998 	idlp->tl_vers = ISCSI_INTERFACE_VERSION;
1999 	idlp->tl_in_cnt = idlp->tl_out_cnt = 1;
2000 	idlp->tl_tgt_list_type = targetListType;
2001 
2002 	/*
2003 	 * Issue ioctl.  Space has been allocted for one entry.
2004 	 * If more than one entry should be returned, we will re-issue the
2005 	 * entry with the right amount of space allocted
2006 	 */
2007 	if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
2008 		(void) close(fd);
2009 		syslog(LOG_USER|LOG_DEBUG,
2010 		    "ISCSI_TARGET_OID_LIST_GET ioctl %d failed, errno: %d",
2011 		    targetListType, errno);
2012 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2013 	}
2014 	if (idlp->tl_out_cnt > 1) {
2015 		out_cnt = idlp->tl_out_cnt;
2016 		free(idlp);
2017 
2018 		target_list_size = sizeof (iscsi_target_list_t);
2019 		target_list_size += (sizeof (uint32_t) * out_cnt - 1);
2020 		idlp = (iscsi_target_list_t *)calloc(1, target_list_size);
2021 		if (idlp == NULL) {
2022 			(void) close(fd);
2023 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
2024 		}
2025 		idlp->tl_vers = ISCSI_INTERFACE_VERSION;
2026 		idlp->tl_in_cnt = out_cnt;
2027 		idlp->tl_tgt_list_type = targetListType;
2028 
2029 		/* Issue the same ioctl again to obtain all the OIDs. */
2030 		if (ioctl(fd, ISCSI_TARGET_OID_LIST_GET, idlp) != 0) {
2031 #define	ERROR_STR "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl failed, errno :%d"
2032 			free(idlp);
2033 			(void) close(fd);
2034 			syslog(LOG_USER|LOG_DEBUG,
2035 			    ERROR_STR, targetListType, errno);
2036 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2037 #undef ERROR_STR
2038 
2039 		}
2040 	}
2041 
2042 	*ppList = (IMA_OID_LIST *)calloc(1, sizeof (IMA_OID_LIST) +
2043 	    idlp->tl_out_cnt * sizeof (IMA_OID));
2044 	(*ppList)->oidCount = idlp->tl_out_cnt;
2045 	for (i = 0; i < idlp->tl_out_cnt; i++) {
2046 		(*ppList)->oids[i].objectType = IMA_OBJECT_TYPE_TARGET;
2047 		(*ppList)->oids[i].ownerId = 1;
2048 		(*ppList)->oids[i].objectSequenceNumber = idlp->tl_oid_list[i];
2049 	}
2050 
2051 	free(idlp);
2052 	(void) close(fd);
2053 	return (IMA_STATUS_SUCCESS);
2054 }
2055 
2056 static IMA_STATUS get_target_lun_oid_list(
2057     IMA_OID * targetOid,
2058     iscsi_lun_list_t  **ppLunList)
2059 {
2060 	int			fd;
2061 	iscsi_lun_list_t	*illp, *illp_saved;
2062 	int			lun_list_size;
2063 	int			status;
2064 
2065 	if ((status = open_driver(&fd))) {
2066 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2067 	}
2068 
2069 	illp = (iscsi_lun_list_t *)calloc(1, sizeof (iscsi_lun_list_t));
2070 	if (illp == NULL) {
2071 		(void) close(fd);
2072 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2073 	}
2074 	illp->ll_vers = ISCSI_INTERFACE_VERSION;
2075 	if (targetOid == NULL) {
2076 		/* get lun oid list for all targets */
2077 		illp->ll_all_tgts = B_TRUE;
2078 	} else {
2079 		/* get lun oid list for single target */
2080 		illp->ll_all_tgts = B_FALSE;
2081 		illp->ll_tgt_oid = (uint32_t)targetOid->objectSequenceNumber;
2082 	}
2083 	illp->ll_in_cnt = illp->ll_out_cnt = 1;
2084 
2085 	/*
2086 	 * Issue ioctl to retrieve the target luns.  Space has been allocted
2087 	 * for one entry.  If more than one entry should be returned, we
2088 	 * will re-issue the entry with the right amount of space allocted
2089 	 */
2090 	if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
2091 		(void) close(fd);
2092 		syslog(LOG_USER|LOG_DEBUG,
2093 		    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d", errno);
2094 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2095 	}
2096 
2097 	if (illp->ll_out_cnt > 1) {
2098 		illp_saved = illp;
2099 		lun_list_size = sizeof (iscsi_lun_list_t);
2100 		lun_list_size += (sizeof (iscsi_if_lun_t) *
2101 		    (illp->ll_out_cnt - 1));
2102 		illp = (iscsi_lun_list_t *)calloc(1, lun_list_size);
2103 		if (illp == NULL) {
2104 			(void) close(fd);
2105 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
2106 		}
2107 		illp->ll_vers = ISCSI_INTERFACE_VERSION;
2108 		illp->ll_all_tgts = illp_saved->ll_all_tgts;
2109 		illp->ll_tgt_oid = illp_saved->ll_tgt_oid;
2110 		illp->ll_in_cnt = illp_saved->ll_out_cnt;
2111 
2112 		free(illp_saved);
2113 
2114 		/* Issue the same ioctl again to get all the target LUN list */
2115 		if (ioctl(fd, ISCSI_LUN_OID_LIST_GET, illp) != 0) {
2116 			free(illp);
2117 			(void) close(fd);
2118 			syslog(LOG_USER|LOG_DEBUG,
2119 			    "ISCSI_LUN_LIST_GET ioctl failed, errno: %d",
2120 			    errno);
2121 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2122 
2123 		}
2124 	}
2125 	*ppLunList = illp;
2126 
2127 
2128 	(void) close(fd);
2129 	return (IMA_STATUS_SUCCESS);
2130 }
2131 
2132 /* A helper function to obtain digest algorithms. */
2133 static IMA_STATUS
2134 getDigest(
2135     IMA_OID oid,
2136     int ioctlCmd,
2137     SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm
2138 )
2139 {
2140 	IMA_MIN_MAX_VALUE pProps;
2141 	IMA_STATUS status;
2142 
2143 	if ((status = getISCSINodeParameter(MIN_MAX_PARAM, &oid, &pProps,
2144 	    ioctlCmd)) != IMA_STATUS_SUCCESS) {
2145 		return (status);
2146 	}
2147 
2148 	switch (pProps.defaultValue) {
2149 		case ISCSI_DIGEST_NONE:
2150 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
2151 			algorithm->defaultAlgorithmCount = 1;
2152 			break;
2153 		case ISCSI_DIGEST_CRC32C:
2154 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
2155 			algorithm->defaultAlgorithmCount = 1;
2156 			break;
2157 
2158 		case ISCSI_DIGEST_CRC32C_NONE:
2159 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_CRC32C;
2160 			algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_NONE;
2161 			algorithm->defaultAlgorithmCount = 2;
2162 			break;
2163 		case ISCSI_DIGEST_NONE_CRC32C:
2164 			algorithm->defaultAlgorithms[0] = ISCSI_DIGEST_NONE;
2165 			algorithm->defaultAlgorithms[1] = ISCSI_DIGEST_CRC32C;
2166 			algorithm->defaultAlgorithmCount = 2;
2167 			break;
2168 		default:
2169 			/* Error */
2170 			syslog(LOG_USER|LOG_DEBUG,
2171 			    "Invalid default digest: %d", pProps.defaultValue);
2172 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2173 	}
2174 
2175 	/* The configured value */
2176 	if (pProps.currentValueValid == IMA_TRUE) {
2177 		algorithm->currentValid = IMA_TRUE;
2178 
2179 		switch (pProps.currentValue) {
2180 			case ISCSI_DIGEST_NONE:
2181 				algorithm->currentAlgorithms[0] =
2182 				    ISCSI_DIGEST_NONE;
2183 				algorithm->currentAlgorithmCount = 1;
2184 				break;
2185 			case ISCSI_DIGEST_CRC32C:
2186 				algorithm->currentAlgorithms[0] =
2187 				    ISCSI_DIGEST_CRC32C;
2188 				algorithm->currentAlgorithmCount = 1;
2189 				break;
2190 
2191 			case ISCSI_DIGEST_CRC32C_NONE:
2192 				algorithm->currentAlgorithms[0] =
2193 				    ISCSI_DIGEST_CRC32C;
2194 				algorithm->currentAlgorithms[1] =
2195 				    ISCSI_DIGEST_NONE;
2196 				algorithm->currentAlgorithmCount = 2;
2197 				break;
2198 			case ISCSI_DIGEST_NONE_CRC32C:
2199 				algorithm->currentAlgorithms[0] =
2200 				    ISCSI_DIGEST_NONE;
2201 				algorithm->currentAlgorithms[1] =
2202 				    ISCSI_DIGEST_CRC32C;
2203 				algorithm->currentAlgorithmCount = 2;
2204 				break;
2205 			default:
2206 				/* Error */
2207 				syslog(LOG_USER|LOG_DEBUG,
2208 				    "Invalid configured digest: %d",
2209 				    pProps.defaultValue);
2210 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2211 		}
2212 
2213 	} else {
2214 		algorithm->currentValid = IMA_FALSE;
2215 	}
2216 
2217 	return (IMA_STATUS_SUCCESS);
2218 }
2219 
2220 /*
2221  * getConnOidList -
2222  */
2223 static IMA_STATUS getConnOidList(
2224 	IMA_OID			*sessOid,
2225 	iscsi_conn_list_t	**ppConnList
2226 )
2227 {
2228 	iscsi_conn_list_t	*iscsiConnList = NULL;
2229 	size_t			allocLen;
2230 	int			fd;
2231 	int			status;
2232 	int			out_cnt;
2233 
2234 	/* Preset it to NULL to prepare for the case of failure */
2235 	*ppConnList = NULL;
2236 
2237 	/* We try to open the driver now. */
2238 	if ((status = open_driver(&fd))) {
2239 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2240 	}
2241 
2242 	iscsiConnList = (iscsi_conn_list_t *)calloc(1,
2243 	    sizeof (iscsi_conn_list_t));
2244 	if (iscsiConnList == NULL) {
2245 		(void) close(fd);
2246 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2247 	}
2248 	iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
2249 	iscsiConnList->cl_in_cnt = iscsiConnList->cl_out_cnt = 1;
2250 	if (sessOid == NULL) {
2251 		iscsiConnList->cl_all_sess = B_TRUE;
2252 	} else {
2253 		iscsiConnList->cl_all_sess = B_FALSE;
2254 		iscsiConnList->cl_sess_oid =
2255 		    (uint32_t)sessOid->objectSequenceNumber;
2256 	}
2257 	/*
2258 	 * Issue ioctl to retrieve the connection OIDs.  Space has been
2259 	 * allocated for one entry.  If more than one entry should be
2260 	 * returned, we will re-issue the entry with the right amount of
2261 	 * space allocted
2262 	 */
2263 	if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
2264 		syslog(LOG_USER|LOG_DEBUG,
2265 		    "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d", errno);
2266 		*ppConnList = NULL;
2267 		(void) close(fd);
2268 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2269 	}
2270 	if (iscsiConnList->cl_out_cnt > 1) {
2271 		out_cnt = iscsiConnList->cl_out_cnt;
2272 		free(iscsiConnList);
2273 
2274 		allocLen = sizeof (iscsi_conn_list_t);
2275 		allocLen += (sizeof (iscsi_if_conn_t) * out_cnt - 1);
2276 		iscsiConnList = (iscsi_conn_list_t *)calloc(1, allocLen);
2277 		if (iscsiConnList == NULL) {
2278 			*ppConnList = NULL;
2279 			(void) close(fd);
2280 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
2281 		}
2282 		iscsiConnList->cl_vers = ISCSI_INTERFACE_VERSION;
2283 		iscsiConnList->cl_in_cnt = out_cnt;
2284 		if (sessOid == NULL) {
2285 			iscsiConnList->cl_all_sess = B_TRUE;
2286 		} else {
2287 			iscsiConnList->cl_all_sess = B_FALSE;
2288 			iscsiConnList->cl_sess_oid =
2289 			    (uint32_t)sessOid->objectSequenceNumber;
2290 		}
2291 		/* Issue the same ioctl again to obtain all the OIDs */
2292 		if (ioctl(fd, ISCSI_CONN_OID_LIST_GET, iscsiConnList) != 0) {
2293 
2294 			syslog(LOG_USER|LOG_DEBUG,
2295 			    "ISCSI_CONN_OID_LIST_GET ioctl failed, errno: %d",
2296 			    errno);
2297 			*ppConnList = NULL;
2298 			free(iscsiConnList);
2299 			(void) close(fd);
2300 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2301 
2302 		}
2303 
2304 		if (out_cnt < iscsiConnList->cl_out_cnt) {
2305 			/*
2306 			 * The connection list grew between the first and second
2307 			 * ioctls.
2308 			 */
2309 			syslog(LOG_USER|LOG_DEBUG,
2310 			    "The connection list has grown. There could be "
2311 			    "more connections than listed.");
2312 		}
2313 	}
2314 
2315 
2316 	(void) close(fd);
2317 	*ppConnList = iscsiConnList;
2318 	return (IMA_STATUS_SUCCESS);
2319 }
2320 
2321 /*
2322  * getConnProps -
2323  */
2324 static IMA_STATUS getConnProps(
2325 	iscsi_if_conn_t		*pConn,
2326 	iscsi_conn_props_t	**ppConnProps
2327 )
2328 {
2329 	iscsi_conn_props_t	*iscsiConnProps;
2330 	int			fd;
2331 	int			status;
2332 
2333 	/* We try to open the driver. */
2334 	if ((status = open_driver(&fd))) {
2335 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2336 	}
2337 
2338 	iscsiConnProps = (iscsi_conn_props_t *)calloc(1,
2339 	    sizeof (*iscsiConnProps));
2340 
2341 	if (iscsiConnProps == NULL) {
2342 		(void) close(fd);
2343 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2344 	}
2345 
2346 	iscsiConnProps->cp_vers = ISCSI_INTERFACE_VERSION;
2347 	iscsiConnProps->cp_oid = pConn->c_oid;
2348 	iscsiConnProps->cp_cid = pConn->c_cid;
2349 	iscsiConnProps->cp_sess_oid = pConn->c_sess_oid;
2350 
2351 	/* The IOCTL is submitted. */
2352 	if (ioctl(fd, ISCSI_CONN_PROPS_GET, iscsiConnProps) != 0) {
2353 		/* IOCTL failed */
2354 		syslog(LOG_USER|LOG_DEBUG,
2355 		    "ISCSI_AUTH_CLEAR ioctl failed, errno: %d", errno);
2356 		free(iscsiConnProps);
2357 		(void) close(fd);
2358 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2359 	}
2360 	(void) close(fd);
2361 	*ppConnProps = iscsiConnProps;
2362 	return (IMA_STATUS_SUCCESS);
2363 }
2364 
2365 /* A helper function to set authentication method. */
2366 static IMA_STATUS
2367 setAuthMethods(
2368     IMA_OID oid,
2369     IMA_UINT *pMethodCount,
2370     const IMA_AUTHMETHOD *pMethodList
2371 )
2372 {
2373 	int fd;
2374 	int i;
2375 	int status;
2376 	iscsi_auth_props_t auth;
2377 
2378 	if ((status = open_driver(&fd))) {
2379 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2380 	}
2381 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
2382 	auth.a_vers = ISCSI_INTERFACE_VERSION;
2383 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
2384 
2385 	/*
2386 	 * Get the current auth fields so they don't need to be reset
2387 	 * here.
2388 	 */
2389 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
2390 	    /* EMPTY */
2391 	    /* Initializing auth structure with current settings */
2392 	}
2393 	auth.a_auth_method = authMethodNone;
2394 
2395 	for (i = 0; i < *pMethodCount; i++) {
2396 		switch (pMethodList[i]) {
2397 			case IMA_AUTHMETHOD_CHAP:
2398 				auth.a_auth_method |= authMethodCHAP;
2399 				break;
2400 			default:
2401 				break;
2402 		}
2403 	}
2404 
2405 	if (ioctl(fd, ISCSI_AUTH_SET, &auth) != 0) {
2406 		syslog(LOG_USER|LOG_DEBUG,
2407 		    "ISCSI_AUTH_SET failed, errno: %d", errno);
2408 		(void) close(fd);
2409 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2410 	}
2411 
2412 	(void) close(fd);
2413 	return (IMA_STATUS_SUCCESS);
2414 }
2415 
2416 /* A helper function to set authentication method. */
2417 static IMA_STATUS getAuthMethods(
2418     IMA_OID oid,
2419     IMA_UINT	*pMethodCount,
2420     IMA_AUTHMETHOD *pMethodList
2421 )
2422 {
2423 	int fd;
2424 	int status;
2425 	iscsi_auth_props_t auth;
2426 
2427 	if ((status = open_driver(&fd))) {
2428 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2429 	}
2430 
2431 	(void) memset(&auth, 0, sizeof (iscsi_auth_props_t));
2432 	auth.a_vers = ISCSI_INTERFACE_VERSION;
2433 	auth.a_oid = (uint32_t)oid.objectSequenceNumber;
2434 
2435 	if (ioctl(fd, ISCSI_AUTH_GET, &auth) != 0) {
2436 		syslog(LOG_USER|LOG_DEBUG,
2437 		    "ISCSI_AUTH_GET failed, errno: %d", errno);
2438 		(void) close(fd);
2439 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2440 	}
2441 
2442 	if (auth.a_auth_method == authMethodNone) {
2443 		pMethodList[0] = IMA_AUTHMETHOD_NONE;
2444 		*pMethodCount = 1;
2445 	} else {
2446 		int i = 0;
2447 		if (!((auth.a_auth_method & authMethodCHAP)^authMethodCHAP)) {
2448 			pMethodList[i++] = IMA_AUTHMETHOD_CHAP;
2449 		}
2450 		*pMethodCount = i;
2451 	}
2452 
2453 	(void) close(fd);
2454 	return (IMA_STATUS_SUCCESS);
2455 }
2456 
2457 /* Helper function to open driver */
2458 int open_driver(
2459 	int *fd
2460 )
2461 {
2462 	int ret = 0;
2463 	if ((*fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
2464 		ret = errno;
2465 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
2466 		    ISCSI_DRIVER_DEVCTL, ret);
2467 	}
2468 	return (ret);
2469 }
2470 
2471 /*
2472  * Iscsi driver does not support OID for discovery address. Create
2473  * a modified version of IMA_RemoveDiscoveryAddress that takes
2474  * discoveryAddress (instead of an OID) as input argument.
2475  */
2476 IMA_API	IMA_STATUS SUN_IMA_RemoveDiscoveryAddress(
2477     SUN_IMA_TARGET_ADDRESS discoveryAddress
2478 )
2479 {
2480 	entry_t	entry;
2481 	int	fd;
2482 	int status, i, addr_list_size, insize;
2483 	iscsi_addr_list_t *idlp, al_info;
2484 	iscsi_addr_t *matched_addr = NULL;
2485 
2486 	if ((status = open_driver(&fd))) {
2487 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2488 	}
2489 
2490 	if (prepare_discovery_entry(discoveryAddress, &entry) !=
2491 	    DISC_ADDR_OK) {
2492 		(void) close(fd);
2493 		return (IMA_ERROR_INVALID_PARAMETER);
2494 	}
2495 
2496 	(void) memset(&al_info, 0, sizeof (al_info));
2497 	al_info.al_vers = ISCSI_INTERFACE_VERSION;
2498 	al_info.al_in_cnt = 0;
2499 	/*
2500 	 * Issue ioctl to get the number of discovery address.
2501 	 */
2502 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, &al_info) != 0) {
2503 		syslog(LOG_USER|LOG_DEBUG,
2504 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
2505 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
2506 		(void) close(fd);
2507 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2508 	}
2509 
2510 	if (al_info.al_out_cnt == 0) {
2511 		(void) close(fd);
2512 		return (IMA_ERROR_OBJECT_NOT_FOUND);
2513 	}
2514 
2515 	addr_list_size = sizeof (iscsi_addr_list_t);
2516 	if (al_info.al_out_cnt > 1) {
2517 		addr_list_size += (sizeof (iscsi_addr_t) *
2518 		    (al_info.al_out_cnt - 1));
2519 	}
2520 
2521 	idlp = (iscsi_addr_list_t *)calloc(1, addr_list_size);
2522 	if (idlp == NULL) {
2523 		(void) close(fd);
2524 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2525 	}
2526 
2527 	idlp->al_vers = ISCSI_INTERFACE_VERSION;
2528 	idlp->al_in_cnt = al_info.al_out_cnt;
2529 
2530 	/* issue the same ioctl to get all the discovery addresses */
2531 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_LIST_GET, idlp) != 0) {
2532 		syslog(LOG_USER|LOG_DEBUG,
2533 		    "ISCSI_DISCOVERY_ADDR_LIST_GET ioctl %d failed, errno: %d",
2534 		    ISCSI_DISCOVERY_ADDR_LIST_GET, errno);
2535 		free(idlp);
2536 		(void) close(fd);
2537 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2538 	}
2539 
2540 	/*
2541 	 * find the matched discovery address
2542 	 */
2543 	for (i = 0; i < idlp->al_out_cnt; i++) {
2544 		insize = idlp->al_addrs[i].a_addr.i_insize;
2545 		if (insize != entry.e_insize) {
2546 			continue;
2547 		}
2548 		if (insize == sizeof (struct in_addr)) {
2549 			if (idlp->al_addrs[i].a_addr.i_addr.in4.s_addr ==
2550 			    entry.e_u.u_in4.s_addr) {
2551 				matched_addr = &(idlp->al_addrs[i]);
2552 				break;
2553 			}
2554 		}
2555 		if (insize == sizeof (struct in6_addr)) {
2556 			if (bcmp(entry.e_u.u_in6.s6_addr,
2557 			    idlp->al_addrs[i].a_addr.i_addr.in6.s6_addr,
2558 			    insize) == 0) {
2559 				matched_addr = &(idlp->al_addrs[i]);
2560 				break;
2561 			}
2562 		}
2563 	}
2564 
2565 	free(idlp);
2566 
2567 	if (matched_addr == NULL) {
2568 		(void) close(fd);
2569 		return (IMA_ERROR_OBJECT_NOT_FOUND);
2570 	}
2571 
2572 	if (ioctl(fd, ISCSI_DISCOVERY_ADDR_CLEAR, &entry)) {
2573 		status = errno;
2574 		(void) close(fd);
2575 		syslog(LOG_USER|LOG_DEBUG,
2576 		    "ISCSI_DISCOVERY_ADDR_CLEAR ioctl failed, errno: %d",
2577 		    errno);
2578 		if (status == EBUSY) {
2579 			return (IMA_ERROR_LU_IN_USE);
2580 		} else {
2581 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2582 		}
2583 	}
2584 
2585 	(void) close(fd);
2586 	return (IMA_STATUS_SUCCESS);
2587 }
2588 
2589 IMA_STATUS SUN_IMA_SetTargetAuthMethods(
2590 		IMA_OID targetOid,
2591 		IMA_UINT *methodCount,
2592 		const IMA_AUTHMETHOD *pMethodList
2593 )
2594 {
2595 	return (setAuthMethods(targetOid, methodCount, pMethodList));
2596 }
2597 
2598 IMA_STATUS getNegotiatedDigest(
2599 	int digestType,
2600 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
2601 	SUN_IMA_CONN_PROPERTIES *connProps) {
2602 
2603 	IMA_UINT digest;
2604 
2605 	if (connProps->valuesValid == IMA_TRUE) {
2606 		algorithm->negotiatedValid = IMA_TRUE;
2607 
2608 		if (digestType == ISCSI_LOGIN_PARAM_HEADER_DIGEST) {
2609 			digest = connProps->headerDigest;
2610 		} else {
2611 			digest = connProps->dataDigest;
2612 		}
2613 
2614 		switch (digest) {
2615 			case ISCSI_DIGEST_NONE:
2616 				algorithm->negotiatedAlgorithms[0] =
2617 				    ISCSI_DIGEST_NONE;
2618 				algorithm->negotiatedAlgorithmCount = 1;
2619 				break;
2620 			case ISCSI_DIGEST_CRC32C:
2621 				algorithm->negotiatedAlgorithms[0] =
2622 				    ISCSI_DIGEST_CRC32C;
2623 				algorithm->negotiatedAlgorithmCount = 1;
2624 				break;
2625 
2626 			case ISCSI_DIGEST_CRC32C_NONE:
2627 				algorithm->negotiatedAlgorithms[0] =
2628 				    ISCSI_DIGEST_CRC32C;
2629 				algorithm->negotiatedAlgorithms[1] =
2630 				    ISCSI_DIGEST_NONE;
2631 				algorithm->negotiatedAlgorithmCount = 2;
2632 				break;
2633 			case ISCSI_DIGEST_NONE_CRC32C:
2634 				algorithm->negotiatedAlgorithms[0] =
2635 				    ISCSI_DIGEST_NONE;
2636 				algorithm->negotiatedAlgorithms[1] =
2637 				    ISCSI_DIGEST_CRC32C;
2638 				algorithm->negotiatedAlgorithmCount = 2;
2639 				break;
2640 			default:
2641 				syslog(LOG_USER|LOG_DEBUG,
2642 				    "Invalid negotiated digest: %d",
2643 				    digest);
2644 				return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2645 		}
2646 	} else {
2647 		algorithm->negotiatedValid = IMA_FALSE;
2648 	}
2649 	return (IMA_STATUS_SUCCESS);
2650 }
2651 
2652 /*
2653  * Non-IMA defined function.
2654  */
2655 IMA_API	IMA_STATUS SUN_IMA_GetISNSServerAddressPropertiesList(
2656     SUN_IMA_DISC_ADDR_PROP_LIST	**ppList
2657 )
2658 {
2659 	char		    isns_server_addr_str[256];
2660 	int		    fd;
2661 	int		    i;
2662 	int		    isns_server_addr_list_size;
2663 	int		    status;
2664 	int		    out_cnt;
2665 	iscsi_addr_list_t   *ialp;
2666 	/* LINTED */
2667 	IMA_IP_ADDRESS	    *ipAddr;
2668 
2669 	if ((status = open_driver(&fd))) {
2670 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2671 	}
2672 
2673 	ialp = (iscsi_addr_list_t *)calloc(1, sizeof (iscsi_addr_list_t));
2674 	if (ialp == NULL) {
2675 		(void) close(fd);
2676 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2677 	}
2678 	ialp->al_vers = ISCSI_INTERFACE_VERSION;
2679 	ialp->al_in_cnt = ialp->al_out_cnt = 1;
2680 
2681 	/*
2682 	 * Issue ioctl to retrieve the isns server addresses.  Space has been
2683 	 * allocted for one entry.  If more than one entry should be returned,
2684 	 * we will re-issue the entry with the right amount of space allocted
2685 	 */
2686 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
2687 		(void) close(fd);
2688 		syslog(LOG_USER|LOG_DEBUG,
2689 		    "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, errno: %d",
2690 		    errno);
2691 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2692 	}
2693 
2694 	isns_server_addr_list_size = sizeof (iscsi_addr_list_t);
2695 	if (ialp->al_out_cnt > 1) {
2696 		out_cnt = ialp->al_out_cnt;
2697 		free(ialp);
2698 
2699 		isns_server_addr_list_size += (sizeof (iscsi_addr_t) *
2700 		    out_cnt - 1);
2701 		ialp = (iscsi_addr_list_t *)calloc(1,
2702 		    isns_server_addr_list_size);
2703 		if (ialp == NULL) {
2704 			(void) close(fd);
2705 			return (IMA_ERROR_INSUFFICIENT_MEMORY);
2706 		}
2707 		ialp->al_vers = ISCSI_INTERFACE_VERSION;
2708 		ialp->al_in_cnt = out_cnt;
2709 
2710 		/*
2711 		 * Issue ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl again to obtain
2712 		 * the list of all the iSNS server addresses
2713 		 */
2714 		if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_LIST_GET, ialp) != 0) {
2715 			free(ialp);
2716 			(void) close(fd);
2717 			syslog(LOG_USER|LOG_DEBUG,
2718 			    "ISCSI_ISNS_SERVER_ADDR_LIST_GET ioctl failed, "
2719 			    "errno: %d", errno);
2720 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2721 
2722 		}
2723 	}
2724 
2725 	*ppList = (SUN_IMA_DISC_ADDR_PROP_LIST *)calloc(1,
2726 	    sizeof (SUN_IMA_DISC_ADDR_PROP_LIST) +
2727 	    ialp->al_out_cnt * sizeof (IMA_DISCOVERY_ADDRESS_PROPERTIES));
2728 	if (*ppList == NULL) {
2729 		free(ialp);
2730 		(void) close(fd);
2731 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2732 	}
2733 	(*ppList)->discAddrCount = ialp->al_out_cnt;
2734 
2735 	for (i = 0; i < ialp->al_out_cnt; i++) {
2736 		if (ialp->al_addrs[i].a_addr.i_insize ==
2737 		    sizeof (struct in_addr)) {
2738 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
2739 			id.ipAddress.ipv4Address = IMA_TRUE;
2740 		} else if (ialp->al_addrs[i].a_addr.i_insize ==
2741 		    sizeof (struct in6_addr)) {
2742 			(*ppList)->props[i].discoveryAddress.hostnameIpAddress.
2743 			    id.ipAddress.ipv4Address = IMA_FALSE;
2744 		} else {
2745 			(void) strlcpy(isns_server_addr_str, "unknown",
2746 			    sizeof (isns_server_addr_str));
2747 		}
2748 
2749 		ipAddr = &(*ppList)->props[i].discoveryAddress.
2750 		    hostnameIpAddress.id.ipAddress;
2751 		bcopy(&ialp->al_addrs[i].a_addr.i_addr,
2752 		    (*ppList)->props[i].discoveryAddress.hostnameIpAddress.id.
2753 		    ipAddress.ipAddress,
2754 		    sizeof (ipAddr->ipAddress));
2755 		(*ppList)->props[i].discoveryAddress.portNumber =
2756 		    ialp->al_addrs[i].a_port;
2757 	}
2758 
2759 	free(ialp);
2760 	(void) close(fd);
2761 	return (IMA_STATUS_SUCCESS);
2762 }
2763 
2764 /*ARGSUSED*/
2765 /*
2766  * Remove iSNS Server Address
2767  */
2768 IMA_API	IMA_STATUS SUN_IMA_RemoveISNSServerAddress(
2769     SUN_IMA_TARGET_ADDRESS isnsServerAddress
2770 )
2771 {
2772 	entry_t	entry;
2773 	int	fd, status;
2774 
2775 	if ((status = open_driver(&fd))) {
2776 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2777 	}
2778 
2779 	if (prepare_discovery_entry(isnsServerAddress, &entry) !=
2780 	    DISC_ADDR_OK) {
2781 		(void) close(fd);
2782 		return (IMA_ERROR_INVALID_PARAMETER);
2783 	}
2784 
2785 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_CLEAR, &entry)) {
2786 		status = errno;
2787 		(void) close(fd);
2788 		syslog(LOG_USER|LOG_DEBUG,
2789 		    "ISCSI_ISNS_SERVER_ADDR_CLEAR ioctl failed, errno: %d",
2790 		    status);
2791 		if (status == EBUSY) {
2792 			return (IMA_ERROR_LU_IN_USE);
2793 		} else {
2794 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2795 		}
2796 	}
2797 
2798 	(void) close(fd);
2799 	return (IMA_STATUS_SUCCESS);
2800 }
2801 
2802 /*ARGSUSED*/
2803 IMA_API IMA_STATUS SUN_IMA_AddISNSServerAddress(
2804 		const SUN_IMA_TARGET_ADDRESS isnsServerAddress
2805 )
2806 {
2807 	entry_t			    entry;
2808 	int			    fd;
2809 	int			    status;
2810 
2811 	if ((status = open_driver(&fd))) {
2812 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2813 	}
2814 
2815 	if (prepare_discovery_entry(isnsServerAddress, &entry) !=
2816 	    DISC_ADDR_OK) {
2817 		(void) close(fd);
2818 		return (IMA_ERROR_INVALID_PARAMETER);
2819 	}
2820 
2821 	if (ioctl(fd, ISCSI_ISNS_SERVER_ADDR_SET, &entry)) {
2822 		/*
2823 		 * Encountered problem setting the discovery address.
2824 		 */
2825 		(void) close(fd);
2826 		syslog(LOG_USER|LOG_DEBUG,
2827 		    "ISCSI_ISNS_SERVER_ADDR_SET ioctl failed, errno: %d",
2828 		    errno);
2829 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2830 	}
2831 
2832 	(void) close(fd);
2833 	return (IMA_STATUS_SUCCESS);
2834 }
2835 
2836 IMA_STATUS SUN_IMA_RetrieveISNSServerTargets(
2837     IMA_TARGET_ADDRESS serverAddress,
2838     SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES **ppList
2839 )
2840 {
2841 	int				    fd;
2842 	int				    ctr;
2843 	int				    server_pg_list_sz;
2844 	int				    status;
2845 	isns_server_portal_group_list_t	    *server_pg_list = NULL;
2846 	isns_portal_group_list_t	    *pg_list = NULL;
2847 	IMA_BOOL			    retry = IMA_TRUE;
2848 	entry_t				    entry;
2849 
2850 #define	ISNS_SERVER_DEFAULT_NUM_TARGETS	50
2851 
2852 	server_pg_list_sz = sizeof (*server_pg_list) +
2853 	    ((ISNS_SERVER_DEFAULT_NUM_TARGETS - 1) *
2854 	    sizeof (isns_portal_group_t));
2855 
2856 	server_pg_list = (isns_server_portal_group_list_t *)calloc(1,
2857 	    server_pg_list_sz);
2858 	if (server_pg_list == NULL) {
2859 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2860 	}
2861 	server_pg_list->addr_port_list.pg_in_cnt =
2862 	    ISNS_SERVER_DEFAULT_NUM_TARGETS;
2863 
2864 	if ((prepare_discovery_entry_IMA(serverAddress, &entry)
2865 	    != DISC_ADDR_OK)) {
2866 		free(server_pg_list);
2867 		return (IMA_ERROR_INVALID_PARAMETER);
2868 	}
2869 	server_pg_list->addr.a_port = entry.e_port;
2870 	server_pg_list->addr.a_addr.i_insize = entry.e_insize;
2871 	if (entry.e_insize == sizeof (struct in_addr)) {
2872 		server_pg_list->addr.a_addr.i_addr.in4.s_addr =
2873 		    (entry.e_u.u_in4.s_addr);
2874 	} else if (entry.e_insize == sizeof (struct in6_addr)) {
2875 		bcopy(&entry.e_u.u_in6.s6_addr,
2876 		    server_pg_list->addr.a_addr.i_addr.in6.s6_addr, 16);
2877 	}
2878 
2879 	if ((status = open_driver(&fd))) {
2880 		free(server_pg_list);
2881 		return (SUN_IMA_ERROR_SYSTEM_ERROR | status);
2882 	}
2883 
2884 retry_isns:
2885 	/*
2886 	 * Issue ioctl to obtain the ISNS Portal Group List list
2887 	 */
2888 	if (ioctl(fd, ISCSI_ISNS_SERVER_GET, server_pg_list) != 0) {
2889 		int tmp_errno = errno;
2890 		IMA_STATUS return_status;
2891 
2892 		syslog(LOG_USER|LOG_DEBUG,
2893 		    "ISCSI_ISNS_SERVER_GET ioctl failed, errno: %d", tmp_errno);
2894 		if (tmp_errno == EACCES) {
2895 			return_status = IMA_ERROR_OBJECT_NOT_FOUND;
2896 		} else {
2897 			return_status = IMA_ERROR_UNEXPECTED_OS_ERROR;
2898 		}
2899 		(void) close(fd);
2900 		free(server_pg_list);
2901 		return (return_status);
2902 	}
2903 	pg_list = &server_pg_list->addr_port_list;
2904 
2905 	/* check if all targets received */
2906 	if (pg_list->pg_in_cnt < pg_list->pg_out_cnt) {
2907 		if (retry == IMA_TRUE) {
2908 			server_pg_list_sz = sizeof (*server_pg_list) +
2909 			    ((pg_list->pg_out_cnt - 1) *
2910 			    sizeof (isns_server_portal_group_list_t));
2911 			server_pg_list = (isns_server_portal_group_list_t *)
2912 			    realloc(server_pg_list, server_pg_list_sz);
2913 			if (server_pg_list == NULL) {
2914 				(void) close(fd);
2915 				return (IMA_ERROR_INSUFFICIENT_MEMORY);
2916 			}
2917 			pg_list = &server_pg_list->addr_port_list;
2918 			pg_list->pg_in_cnt = pg_list->pg_out_cnt;
2919 			retry = IMA_FALSE;
2920 			goto retry_isns;
2921 		} else {
2922 			/*
2923 			 * don't retry after 2 attempts.  The target list
2924 			 * shouldn't continue growing. Just continue
2925 			 * on and display what was found.
2926 			 */
2927 			syslog(LOG_USER|LOG_DEBUG,
2928 			    "ISCSI_SENDTGTS_GET overflow: "
2929 			    "failed to obtain all targets");
2930 			pg_list->pg_out_cnt = pg_list->pg_in_cnt;
2931 		}
2932 	}
2933 
2934 	(void) close(fd);
2935 
2936 	/* allocate for caller return buffer */
2937 	*ppList = (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *)calloc(1,
2938 	    sizeof (SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES) +
2939 	    pg_list->pg_out_cnt * sizeof (SUN_IMA_DISC_ADDRESS_KEY));
2940 	if (*ppList == NULL) {
2941 		free(server_pg_list);
2942 		return (IMA_ERROR_INSUFFICIENT_MEMORY);
2943 	}
2944 
2945 	(*ppList)->keyCount = pg_list->pg_out_cnt;
2946 
2947 	for (ctr = 0; ctr < pg_list->pg_out_cnt; ctr++) {
2948 		(void) mbstowcs((*ppList)->keys[ctr].name,
2949 		    (char *)pg_list->pg_list[ctr].pg_iscsi_name,
2950 		    IMA_NODE_NAME_LEN);
2951 
2952 		(*ppList)->keys[ctr].tpgt = pg_list->pg_list[ctr].pg_tag;
2953 
2954 		(*ppList)->keys[ctr].address.portNumber =
2955 		    pg_list->pg_list[ctr].pg_port;
2956 
2957 		if (pg_list->pg_list[ctr].insize == sizeof (struct in_addr)) {
2958 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
2959 			    IMA_TRUE;
2960 		} else if (pg_list->pg_list[ctr].insize ==
2961 		    sizeof (struct in6_addr)) {
2962 			(*ppList)->keys[ctr].address.ipAddress.ipv4Address =
2963 			    IMA_FALSE;
2964 		} else {
2965 			free(pg_list);
2966 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
2967 		}
2968 
2969 		(void) memcpy(&(*ppList)->keys[ctr].address.ipAddress.ipAddress,
2970 		    &(pg_list->pg_list[ctr].pg_ip_addr),
2971 		    pg_list->pg_list[ctr].insize);
2972 	}
2973 	free(server_pg_list);
2974 
2975 	return (IMA_STATUS_SUCCESS);
2976 }
2977 
2978 /* ARGSUSED */
2979 IMA_STATUS SUN_IMA_GetSessionOidList(
2980     IMA_OID initiatorOid,
2981     IMA_OID_LIST **ppList
2982 )
2983 {
2984 	return (get_target_oid_list(ISCSI_TGT_OID_LIST, ppList));
2985 }
2986 
2987 /*ARGSUSED*/
2988 IMA_API	IMA_STATUS SUN_IMA_GetTargetAuthParms(
2989 	IMA_OID oid,
2990 	IMA_AUTHMETHOD method,
2991 	IMA_INITIATOR_AUTHPARMS *pParms
2992 )
2993 {
2994 	int fd;
2995 	iscsi_chap_props_t  chap_p;
2996 
2997 	if (pParms == NULL) {
2998 		return (IMA_ERROR_INVALID_PARAMETER);
2999 	}
3000 
3001 	if (oid.objectType != IMA_OBJECT_TYPE_TARGET) {
3002 		return (IMA_ERROR_INCORRECT_OBJECT_TYPE);
3003 	}
3004 
3005 	if (method != IMA_AUTHMETHOD_CHAP) {
3006 		return (IMA_ERROR_INVALID_PARAMETER);
3007 	}
3008 
3009 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3010 		syslog(LOG_USER|LOG_DEBUG, "Cannot open %s (%d)",
3011 		    ISCSI_DRIVER_DEVCTL, errno);
3012 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3013 	}
3014 
3015 	(void) memset(&chap_p, 0, sizeof (iscsi_chap_props_t));
3016 	chap_p.c_vers = ISCSI_INTERFACE_VERSION;
3017 	chap_p.c_oid = (uint32_t)oid.objectSequenceNumber;
3018 
3019 	if (ioctl(fd, ISCSI_CHAP_GET, &chap_p) != 0) {
3020 		syslog(LOG_USER|LOG_DEBUG,
3021 
3022 		    "ISCSI_CHAP_GET ioctl failed, errno: %d",
3023 		    errno);
3024 		(void) close(fd);
3025 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3026 	}
3027 
3028 	(void) memcpy(pParms->chapParms.name, chap_p.c_user,
3029 	    chap_p.c_user_len);
3030 
3031 	pParms->chapParms.nameLength = chap_p.c_user_len;
3032 	(void) memcpy(pParms->chapParms.challengeSecret, chap_p.c_secret,
3033 	    chap_p.c_secret_len);
3034 
3035 	pParms->chapParms.challengeSecretLength = chap_p.c_secret_len;
3036 
3037 	return (IMA_STATUS_SUCCESS);
3038 }
3039 
3040 IMA_API IMA_STATUS SUN_IMA_GetBootTargetName(
3041     IMA_NODE_NAME tgtName
3042 )
3043 {
3044 	int fd;
3045 	IMA_STATUS rtn;
3046 	iscsi_boot_property_t bootProp;
3047 
3048 	bootProp.tgt_name.n_name[0] = '\0';
3049 	bootProp.tgt_chap.c_user[0] = '\0';
3050 	tgtName[0] = L'\0';
3051 	rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
3052 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3053 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
3054 		    ISCSI_DRIVER_DEVCTL, errno);
3055 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3056 	}
3057 
3058 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
3059 		syslog(LOG_USER|LOG_DEBUG,
3060 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
3061 		    errno);
3062 		(void) close(fd);
3063 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3064 	}
3065 
3066 	if ((bootProp.tgt_name.n_name[0] != '\0') && (tgtName != NULL)) {
3067 		if (mbstowcs(tgtName, (const char *)bootProp.tgt_name.n_name,
3068 		    IMA_NODE_NAME_LEN) == (size_t)-1) {
3069 			syslog(LOG_USER|LOG_DEBUG,
3070 			    "ISCSI Target name covert to WCHAR fail");
3071 			return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3072 		} else {
3073 			rtn = IMA_STATUS_SUCCESS;
3074 		}
3075 	}
3076 
3077 	return (rtn);
3078 }
3079 
3080 IMA_API IMA_STATUS SUN_IMA_GetBootTargetAuthParams(
3081     IMA_INITIATOR_AUTHPARMS *pTgtCHAP
3082 )
3083 {
3084 	int fd;
3085 	IMA_STATUS rtn;
3086 	iscsi_boot_property_t bootProp;
3087 
3088 	bootProp.tgt_name.n_name[0] = '\0';
3089 	bootProp.tgt_chap.c_user[0] = '\0';
3090 	bootProp.tgt_chap.c_secret[0] = '\0';
3091 	rtn = IMA_ERROR_UNEXPECTED_OS_ERROR;
3092 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3093 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
3094 		    ISCSI_DRIVER_DEVCTL, errno);
3095 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3096 	}
3097 
3098 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
3099 		syslog(LOG_USER|LOG_DEBUG,
3100 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
3101 		    errno);
3102 		(void) close(fd);
3103 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3104 	}
3105 
3106 	if (pTgtCHAP != NULL) {
3107 		if (bootProp.tgt_chap.c_user[0] != '\0') {
3108 			(void) memcpy(pTgtCHAP->chapParms.name,
3109 			    bootProp.tgt_chap.c_user, ISCSI_MAX_NAME_LEN);
3110 		} else {
3111 			pTgtCHAP->chapParms.name[0] = '\0';
3112 		}
3113 		if (bootProp.tgt_chap.c_secret[0] != '\0') {
3114 			(void) memcpy(pTgtCHAP->chapParms.challengeSecret,
3115 			    bootProp.tgt_chap.c_secret, MAX_CHAP_SECRET_LEN);
3116 		} else {
3117 			pTgtCHAP->chapParms.challengeSecret[0] = '\0';
3118 		}
3119 		rtn = IMA_STATUS_SUCCESS;
3120 	}
3121 	return (rtn);
3122 }
3123 
3124 IMA_STATUS SUN_IMA_GetBootMpxio(
3125     IMA_BOOL *pMpxioEnabled
3126 )
3127 {
3128 	int fd;
3129 	iscsi_boot_property_t bootProp;
3130 
3131 	bootProp.hba_mpxio_enabled = B_FALSE;
3132 	*pMpxioEnabled = IMA_UNKNOWN;
3133 
3134 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3135 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
3136 		    ISCSI_DRIVER_DEVCTL, errno);
3137 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3138 	}
3139 
3140 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
3141 		syslog(LOG_USER|LOG_DEBUG,
3142 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
3143 		    errno);
3144 		(void) close(fd);
3145 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3146 	}
3147 
3148 	if (bootProp.hba_mpxio_enabled) {
3149 		*pMpxioEnabled = IMA_TRUE;
3150 	} else {
3151 		*pMpxioEnabled = IMA_FALSE;
3152 	}
3153 
3154 	(void) close(fd);
3155 	return (IMA_STATUS_SUCCESS);
3156 }
3157 
3158 IMA_STATUS SUN_IMA_GetBootIscsi(
3159     IMA_BOOL *pIscsiBoot
3160 )
3161 {
3162 	int fd;
3163 	iscsi_boot_property_t bootProp;
3164 
3165 	bootProp.iscsiboot = 0;
3166 	*pIscsiBoot = 0;
3167 
3168 	if ((fd = open(ISCSI_DRIVER_DEVCTL, O_RDONLY)) == -1) {
3169 		syslog(LOG_USER|LOG_DEBUG, "Unable to open %s (%d)",
3170 		    ISCSI_DRIVER_DEVCTL, errno);
3171 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3172 	}
3173 
3174 	if (ioctl(fd, ISCSI_BOOTPROP_GET, &bootProp) != 0) {
3175 		syslog(LOG_USER|LOG_DEBUG,
3176 		    "ISCSI_BOOTPROP_GET ioctl failed, errno: %d",
3177 		    errno);
3178 		(void) close(fd);
3179 		return (IMA_ERROR_UNEXPECTED_OS_ERROR);
3180 	}
3181 
3182 	*pIscsiBoot = bootProp.iscsiboot;
3183 
3184 	(void) close(fd);
3185 	return (IMA_STATUS_SUCCESS);
3186 }
3187