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