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