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