xref: /titanic_51/usr/src/cmd/iscsiadm/iscsiadm_main.c (revision 6cefaae1e90a413ba01560575bb3998e1a3df40e)
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 <stdlib.h>
27 #include <stdio.h>
28 #include <wchar.h>
29 #include <widec.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <libintl.h>
36 #include <limits.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <syslog.h>
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <wctype.h>
45 #include <assert.h>
46 
47 #include <ima.h>
48 #include <sys/scsi/adapters/iscsi_protocol.h>
49 #include <sys/scsi/adapters/iscsi_if.h>
50 
51 #include "cmdparse.h"
52 #include "sun_ima.h"
53 #include "iscsiadm.h"
54 
55 #define	VERSION_STRING_MAX_LEN	10
56 #define	MAX_LONG_CHAR_LEN 19
57 
58 #define	MAX_AUTH_METHODS 5
59 /*
60  * Version number:
61  *  MAJOR - This should only change when there is an incompatible change made
62  *  to the interfaces or the output.
63  *
64  *  MINOR - This should change whenever there is a new command or new feature
65  *  with no incompatible change.
66  */
67 #define	VERSION_STRING_MAJOR	    "1"
68 #define	VERSION_STRING_MINOR	    "0"
69 
70 #define	OPTIONSTRING1	"yes|no"
71 #define	OPTIONSTRING2	"initiator node name"
72 #define	OPTIONSTRING3	"initiator node alias"
73 #define	OPTIONSTRING4	"enable|disable"
74 #define	OPTIONSTRING5	"key=value,..."
75 #define	OPTIONSTRING6	"none|CRC32"
76 #define	OPTIONSTRING7	"CHAP name"
77 #define	OPTIONSTRING8	"<# sessions>|<IP Address>[,<IP Address>]*"
78 #define	OPTIONVAL1	"0 to 3600"
79 #define	OPTIONVAL2	"512 to 2**24 - 1"
80 #define	OPTIONVAL3	"1 to 65535"
81 #define	OPTIONVAL4	"<IP address>[:port]"
82 
83 #define	MAX_ISCSI_NAME_LEN	    223
84 #define	MAX_ADDRESS_LEN		    255
85 #define	MIN_CHAP_SECRET_LEN	    12
86 #define	MAX_CHAP_SECRET_LEN	    16
87 #define	DEFAULT_ISCSI_PORT	    3260
88 #define	ISNS_DEFAULT_SERVER_PORT    3205
89 #define	DEFAULT_RADIUS_PORT	    1812
90 #define	MAX_CHAP_NAME_LEN	    512
91 
92 /* For listNode */
93 #define	INF_ERROR		1
94 #define	INVALID_NODE_NAME	2
95 
96 #define	IMABOOLPRINT(prop, option)	 \
97 	if ((option) == PRINT_CONFIGURED_PARAMS) { \
98 		(void) fprintf(stdout, "%s/%s\n", \
99 		(prop).defaultValue == IMA_TRUE ? gettext("yes") : \
100 			gettext("no"), \
101 		(prop).currentValueValid == IMA_TRUE ? \
102 			((prop).currentValue == IMA_TRUE ? \
103 			gettext("yes"): gettext("no")) : "-"); \
104 	} else if ((option) == PRINT_NEGOTIATED_PARAMS) { \
105 		(void) fprintf(stdout, "%s\n", \
106 		(prop).currentValueValid == IMA_TRUE ? \
107 		(((prop).currentValue == IMA_TRUE) ? gettext("yes") : \
108 		gettext("no")) : "-"); \
109 	}
110 
111 #define	IMAMINMAXPRINT(prop, option) \
112 	if ((option) == PRINT_CONFIGURED_PARAMS) { \
113 		(void) fprintf(stdout, "%d/", (prop).defaultValue); \
114 		if ((prop).currentValueValid == IMA_TRUE) { \
115 			(void) fprintf(stdout, "%d\n", (prop).currentValue); \
116 		} else if ((prop).currentValueValid == IMA_FALSE) { \
117 			(void) fprintf(stdout, "%s\n", "-"); \
118 		} \
119 	} else if ((option) == PRINT_NEGOTIATED_PARAMS) { \
120 		if ((prop).currentValueValid == IMA_TRUE) { \
121 			(void) fprintf(stdout, "%d\n", (prop).currentValue); \
122 		} else if ((prop).currentValueValid == IMA_FALSE) { \
123 			(void) fprintf(stdout, "%s\n", "-"); \
124 		} \
125 	}
126 
127 /* forward declarations */
128 #define	PARSE_ADDR_OK				0
129 #define	PARSE_ADDR_MISSING_CLOSING_BRACKET	1
130 #define	PARSE_ADDR_PORT_OUT_OF_RANGE		2
131 #define	PARSE_TARGET_OK				0
132 #define	PARSE_TARGET_INVALID_TPGT		1
133 #define	PARSE_TARGET_INVALID_ADDR		2
134 
135 #define	PRINT_CONFIGURED_PARAMS			1
136 #define	PRINT_NEGOTIATED_PARAMS			2
137 
138 typedef enum iSCSINameCheckStatus {
139 	iSCSINameCheckOK,
140 	iSCSINameLenZero,
141 	iSCSINameLenExceededMax,
142 	iSCSINameUnknownType,
143 	iSCSINameInvalidCharacter,
144 	iSCSINameIqnFormatError,
145 	iSCSINameEUIFormatError,
146 	iSCSINameIqnDateFormatError,
147 	iSCSINameIqnSubdomainFormatError,
148 	iSCSINameIqnInvalidYearError,
149 	iSCSINameIqnInvalidMonthError,
150 	iSCSINameIqnFQDNError
151 } iSCSINameCheckStatusType;
152 
153 /* Utility functions */
154 iSCSINameCheckStatusType iSCSINameStringProfileCheck(wchar_t *name);
155 boolean_t isNaturalNumber(char *numberStr, uint32_t upperBound);
156 static int parseAddress(char *address_port_str, uint16_t defaultPort,
157     char *address_str, size_t address_str_len,
158     uint16_t *port, boolean_t *isIpv6);
159 int parseTarget(char *targetStr,
160     wchar_t *targetNameStr,
161     size_t targetNameStrLen,
162     boolean_t *targetAddressSpecified,
163     wchar_t *targetAddressStr,
164     size_t targetAddressStrLen,
165     uint16_t *port,
166     boolean_t *tpgtSpecified,
167     uint16_t *tpgt,
168     boolean_t *isIpv6);
169 
170 /* subcommand functions */
171 static int addFunc(int, char **, int, cmdOptions_t *, void *, int *);
172 static int listFunc(int, char **, int, cmdOptions_t *, void *, int *);
173 static int modifyFunc(int, char **, int, cmdOptions_t *, void *, int *);
174 static int removeFunc(int, char **, int, cmdOptions_t *, void *, int *);
175 
176 /* helper functions */
177 static char *getExecBasename(char *);
178 static int getNodeProps(IMA_NODE_PROPERTIES *);
179 static int getSecret(char *, int *, int, int);
180 static int getTargetAddress(int, char *, IMA_TARGET_ADDRESS *);
181 static int printLoginParameters(char *, IMA_OID, int);
182 static void printDiscoveryMethod(char *, IMA_UINT32);
183 static void printTargetLuns(IMA_OID_LIST *);
184 static void printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *);
185 static void printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *, int);
186 static int setLoginParameter(IMA_OID, int, char *);
187 static int setLoginParameters(IMA_OID, char *);
188 static void printLibError(IMA_STATUS);
189 /* LINTED E_STATIC_UNUSED */
190 static int sunPluginChk(IMA_OID, boolean_t *);
191 static int sunInitiatorFind(IMA_OID *);
192 static int getAuthMethodValue(char *, IMA_AUTHMETHOD *);
193 static int getLoginParam(char *);
194 static void iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status);
195 static int modifyIndividualTargetParam(cmdOptions_t *optionList,
196     IMA_OID targetOid, int *);
197 static void listCHAPName(IMA_OID oid);
198 static int printConfiguredSessions(IMA_OID);
199 
200 /* object functions per subcommand */
201 static int addAddress(int, int, char *[], int *);
202 static int addStaticConfig(int, char *[], int *);
203 static int listDiscovery(int *);
204 static int listDiscoveryAddress(int, char *[], cmdOptions_t *, int *);
205 static int listISNSServerAddress(int, char *[], cmdOptions_t *, int *);
206 static int listNode(int *);
207 static int listStaticConfig(int, char *[], int *);
208 static int listTarget(int, char *[], cmdOptions_t *, int *);
209 static int listTargetParam(int, char *[], cmdOptions_t *, int *);
210 static int modifyDiscovery(cmdOptions_t *, int *);
211 static int modifyNodeAuthMethod(IMA_OID, char *, int *);
212 static int modifyNodeAuthParam(IMA_OID oid, int, char *, int *);
213 static int modifyNodeRadiusConfig(IMA_OID, char *, int *);
214 static int modifyNodeRadiusAccess(IMA_OID, char *, int *);
215 static int modifyNodeRadiusSharedSecret(IMA_OID, int *);
216 static int modifyNode(cmdOptions_t *, int *);
217 static int modifyTargetAuthMethod(IMA_OID, char *, int *);
218 static int modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *);
219 static int modifyTargetParam(cmdOptions_t *, char *, int *);
220 static int removeAddress(int, int, char *[], int *);
221 static int removeStaticConfig(int, char *[], int *);
222 static int removeTargetParam(int, char *[], int *);
223 static int modifyTargetBidirAuthFlag(IMA_OID, char *, int *);
224 static int modifyConfiguredSessions(IMA_OID targetOid, char *optarg);
225 
226 /* LINTED E_STATIC_UNUSED */
227 static IMA_STATUS getISCSINodeParameter(int paramType,
228     IMA_OID *oid,
229     void *pProps,
230     uint32_t paramIndex);
231 /* LINTED E_STATIC_UNUSED */
232 static IMA_STATUS setISCSINodeParameter(int paramType,
233     IMA_OID *oid,
234     void *pProps,
235     uint32_t paramIndex);
236 /* LINTED E_STATIC_UNUSED */
237 static IMA_STATUS getDigest(IMA_OID oid, int ioctlCmd,
238     SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm);
239 
240 IMA_STATUS getNegotiatedDigest(int digestType,
241 	SUN_IMA_DIGEST_ALGORITHM_VALUE *algorithm,
242 	SUN_IMA_CONN_PROPERTIES *connProps);
243 
244 /* globals */
245 static char *cmdName;
246 
247 /*
248  * Available option letters:
249  *
250  * bcefgijklmnoquwxyz
251  *
252  * DEFGHIJKLMOQTUVWXYZ
253  */
254 
255 /*
256  * Add new options here
257  */
258 optionTbl_t longOptions[] = {
259 	{"static", required_arg, 's', OPTIONSTRING4},
260 	{"sendtargets", required_arg, 't', OPTIONSTRING4},
261 	{"iSNS", required_arg, 'i', OPTIONSTRING4},
262 	{"headerdigest", required_arg, 'h', OPTIONSTRING6},
263 	{"datadigest", required_arg, 'd', OPTIONSTRING6},
264 	{"login-param", required_arg, 'p', OPTIONSTRING5},
265 	{"authentication", required_arg, 'a', "CHAP|none"},
266 	{"bi-directional-authentication", required_arg, 'B', OPTIONSTRING4},
267 	{"CHAP-secret", no_arg, 'C', NULL},
268 	{"CHAP-name", required_arg, 'H', OPTIONSTRING7},
269 	{"node-name", required_arg, 'N', OPTIONSTRING2},
270 	{"node-alias", required_arg, 'A', OPTIONSTRING3},
271 	{"radius-server", required_arg, 'r', OPTIONVAL4},
272 	{"radius-access", required_arg, 'R', OPTIONSTRING4},
273 	{"radius-shared-secret", no_arg, 'P', NULL},
274 	{"verbose", no_arg, 'v', NULL},
275 	{"scsi-target", no_arg, 'S', NULL},
276 	{"configured-sessions", required_arg, 'c', OPTIONSTRING8},
277 	{NULL, 0, 0, 0}
278 };
279 
280 parameterTbl_t loginParams[] = {
281 	{"dataseqinorder", DATA_SEQ_IN_ORDER},
282 	{"defaulttime2retain", DEFAULT_TIME_2_RETAIN},
283 	{"defaulttime2wait", DEFAULT_TIME_2_WAIT},
284 	{"firstburstlength", FIRST_BURST_LENGTH},
285 	{"immediatedata", IMMEDIATE_DATA},
286 	{"initialr2t", INITIAL_R2T},
287 	{"maxburstlength", MAX_BURST_LENGTH},
288 	{"datapduinorder", DATA_PDU_IN_ORDER},
289 	{"maxoutstandingr2t", MAX_OUTSTANDING_R2T},
290 	{"maxrecvdataseglen", MAX_RECV_DATA_SEG_LEN},
291 	{"maxconnections", MAX_CONNECTIONS},
292 	{"errorrecoverylevel", ERROR_RECOVERY_LEVEL},
293 	{NULL, 0}
294 };
295 
296 /*
297  * Add new subcommands here
298  */
299 subcommand_t subcommands[] = {
300 	{"add", ADD, addFunc},
301 	{"list", LIST, listFunc},
302 	{"modify", MODIFY, modifyFunc},
303 	{"remove", REMOVE, removeFunc},
304 	{NULL, 0, NULL}
305 };
306 
307 /*
308  * Add objects here
309  */
310 object_t objects[] = {
311 	{"discovery", DISCOVERY},
312 	{"discovery-address", DISCOVERY_ADDRESS},
313 	{"isns-server", ISNS_SERVER_ADDRESS},
314 	{"initiator-node", NODE},
315 	{"static-config", STATIC_CONFIG},
316 	{"target", TARGET},
317 	{"target-param", TARGET_PARAM},
318 	{NULL, 0}
319 };
320 
321 /*
322  * Rules for subcommands and objects
323  */
324 objectRules_t objectRules[] = {
325 	{TARGET, 0, LIST, 0, ADD|REMOVE|MODIFY, LIST,
326 	"target-name"},
327 	{TARGET_PARAM, MODIFY|REMOVE, LIST, 0, ADD, MODIFY,
328 	"target-name"},
329 	{DISCOVERY, 0, 0, LIST|MODIFY, ADD|REMOVE, 0, NULL},
330 	{NODE, 0, 0, MODIFY|LIST, ADD|REMOVE, 0, NULL},
331 	{STATIC_CONFIG, ADD|REMOVE, LIST, 0, MODIFY, ADD|REMOVE|LIST,
332 	"target-name,target-address[:port-number][,tpgt]"},
333 	{DISCOVERY_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY,
334 	ADD|REMOVE|LIST, "IP-address[:port-number]"},
335 	{ISNS_SERVER_ADDRESS, ADD|REMOVE, LIST, 0, MODIFY,
336 	ADD|REMOVE|LIST, "IP-address[:port-number]"},
337 	{0, 0, 0, 0, 0, NULL}
338 };
339 
340 /*
341  * list of objects, subcommands, valid short options, required flag and
342  * exclusive option string
343  *
344  * If it's not here, there are no options for that object.
345  */
346 optionRules_t optionRules[] = {
347 	{DISCOVERY, MODIFY, "sti", B_TRUE, NULL},
348 	{DISCOVERY_ADDRESS, LIST, "v", B_FALSE, NULL},
349 	{ISNS_SERVER_ADDRESS, LIST, "v", B_FALSE, NULL},
350 	{TARGET, LIST, "vS", B_FALSE, NULL},
351 	{NODE, MODIFY, "NAhdCaRrPHc", B_TRUE, "CP"},
352 	{TARGET_PARAM, MODIFY, "ahdBCpcH", B_TRUE, "C"},
353 	{TARGET_PARAM, LIST, "v", B_FALSE, NULL},
354 	{0, 0, 0, 0, 0}
355 };
356 
357 
358 static boolean_t
359 targetNamesEqual(wchar_t *name1, wchar_t *name2)
360 {
361 	int i;
362 	wchar_t wchar1, wchar2;
363 
364 	if (name1 == NULL || name2 == NULL) {
365 		return (B_FALSE);
366 	}
367 
368 	if (wcslen(name1) != wcslen(name2)) {
369 		return (B_FALSE);
370 	}
371 
372 	/*
373 	 * Convert names to lower case and compare
374 	 */
375 	for (i = 0; i < wcslen(name1); i++) {
376 		wchar1 = towctrans((wint_t)name1[i], wctrans("tolower"));
377 		wchar2 = towctrans((wint_t)name2[i], wctrans("tolower"));
378 
379 		if (wchar1 != wchar2) {
380 			return (B_FALSE);
381 		}
382 	}
383 
384 	return (B_TRUE);
385 }
386 
387 static boolean_t
388 ipAddressesEqual(IMA_TARGET_ADDRESS addr1, IMA_TARGET_ADDRESS addr2)
389 {
390 #define	IPV4_ADDR_BYTES 4
391 #define	IPV6_ADDR_BYTES 16
392 
393 	int compSize;
394 
395 	if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address !=
396 	    addr2.hostnameIpAddress.id.ipAddress.ipv4Address) {
397 		return (B_FALSE);
398 	}
399 
400 	compSize = IPV6_ADDR_BYTES;
401 	if (addr1.hostnameIpAddress.id.ipAddress.ipv4Address) {
402 		compSize = IPV4_ADDR_BYTES;
403 	}
404 
405 	if (bcmp(addr1.hostnameIpAddress.id.ipAddress.ipAddress,
406 	    addr2.hostnameIpAddress.id.ipAddress.ipAddress, compSize) == 0) {
407 		return (B_TRUE);
408 	}
409 
410 	return (B_FALSE);
411 }
412 
413 static int
414 getLoginParam(char *arg)
415 {
416 	parameterTbl_t *paramp;
417 	int len;
418 
419 	for (paramp = loginParams; paramp->name; paramp++) {
420 		len = strlen(arg);
421 		if (len == strlen(paramp->name) &&
422 		    strncasecmp(arg, paramp->name, len) == 0) {
423 			return (paramp->val);
424 		}
425 	}
426 	return (-1);
427 }
428 
429 static void
430 printLibError(IMA_STATUS status)
431 {
432 	char *errorString;
433 	switch (status) {
434 	case IMA_ERROR_NOT_SUPPORTED:
435 		errorString =
436 		gettext("Operation currently not supported");
437 		break;
438 	case IMA_ERROR_INSUFFICIENT_MEMORY:
439 		errorString = gettext("Insufficient memory");
440 		break;
441 	case IMA_ERROR_UNEXPECTED_OS_ERROR:
442 		errorString = gettext("unexpected OS error");
443 		break;
444 	case IMA_ERROR_UNKNOWN_ERROR:
445 		errorString = gettext("Unknown error");
446 		break;
447 	case IMA_ERROR_LU_IN_USE:
448 		errorString = gettext("Logical unit in use");
449 		break;
450 	case IMA_ERROR_INVALID_PARAMETER:
451 		errorString = gettext("Invalid parameter specified");
452 		break;
453 	case IMA_ERROR_INVALID_OBJECT_TYPE:
454 		errorString =
455 		gettext("Internal library error: Invalid oid type specified");
456 		break;
457 	case IMA_ERROR_INCORRECT_OBJECT_TYPE:
458 		errorString =
459 		gettext("Internal library error: Incorrect oid type specified");
460 		break;
461 	case IMA_ERROR_OBJECT_NOT_FOUND:
462 		errorString = gettext("Internal library error: Oid not found");
463 		break;
464 	case IMA_ERROR_NAME_TOO_LONG:
465 		errorString = gettext("Name too long");
466 		break;
467 	default:
468 		errorString = gettext("Unknown error");
469 	}
470 	(void) fprintf(stderr, "%s: %s\n", cmdName, errorString);
471 }
472 
473 /*
474  * input:
475  *  execFullName - exec name of program (argv[0])
476  *
477  * Returns:
478  *  command name portion of execFullName
479  */
480 static char *
481 getExecBasename(char *execFullname)
482 {
483 	char *lastSlash, *execBasename;
484 
485 	/* guard against '/' at end of command invocation */
486 	for (;;) {
487 		lastSlash = strrchr(execFullname, '/');
488 		if (lastSlash == NULL) {
489 			execBasename = execFullname;
490 			break;
491 		} else {
492 			execBasename = lastSlash + 1;
493 			if (*execBasename == '\0') {
494 				*lastSlash = '\0';
495 				continue;
496 			}
497 			break;
498 		}
499 	}
500 	return (execBasename);
501 }
502 
503 
504 /*
505  * input:
506  *  nodeProps - pointer to caller allocated IMA_NODE_PROPERTIES
507  *
508  * returns:
509  *  zero on success
510  *  non-zero otherwise
511  */
512 static int
513 getNodeProps(IMA_NODE_PROPERTIES *nodeProps)
514 {
515 	IMA_OID sharedNodeOid;
516 
517 	IMA_STATUS status = IMA_GetSharedNodeOid(&sharedNodeOid);
518 	if (!(IMA_SUCCESS(status))) {
519 		printLibError(status);
520 		return (INF_ERROR);
521 	}
522 
523 	status = IMA_GetNodeProperties(sharedNodeOid, nodeProps);
524 	if (!IMA_SUCCESS(status)) {
525 		printLibError(status);
526 		return (INF_ERROR);
527 	}
528 
529 	return (0);
530 }
531 
532 /*
533  * sunInitiatorFind
534  * Purpose:
535  *  Finds the Sun iSCSI initiator (LHBA). This CLI currently supports only
536  *  one initiator.
537  *
538  * output:
539  *  oid of initiator
540  *
541  * Returns:
542  *  zero on success with initiator found
543  *  > 0 on success with no initiator found
544  *  < 0 on failure
545  */
546 static int
547 sunInitiatorFind(IMA_OID *oid)
548 {
549 	IMA_OID_LIST *lhbaList;
550 
551 	IMA_STATUS status = IMA_GetLhbaOidList(&lhbaList);
552 	if (!IMA_SUCCESS(status)) {
553 		printLibError(status);
554 		return (-1);
555 	}
556 
557 	*oid = lhbaList->oids[0];
558 
559 	return (0);
560 }
561 
562 /*
563  * input:
564  *  wcInput - wide character string containing discovery address
565  * output:
566  *  address - IMA_TARGET_ADDRESS structure containing valid
567  *	discovery address
568  * returns:
569  *  zero on success
570  *  non-zero on failure
571  */
572 
573 static int
574 getTargetAddress(int addrType, char *ipStr, IMA_TARGET_ADDRESS *address)
575 {
576 	char cCol = ':';
577 	char cBracketL = '['; /* Open Bracket '[' */
578 	char cBracketR = ']'; /* Close Bracket ']' */
579 	char *colPos;
580 	char *startPos;
581 	unsigned long inputPort;
582 	int addressType = AF_INET;
583 	char *tmpStrPtr, tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
584 	int rval;
585 
586 	/* Check if this is a ipv6 address */
587 	if (ipStr[0] == cBracketL) {
588 		addressType = AF_INET6;
589 		startPos = strchr(ipStr, cBracketR);
590 		if (!startPos) {
591 			(void) fprintf(stderr, "%s: %s: ']' %s\n",
592 			    cmdName, ipStr, gettext("missing"));
593 			return (1);
594 		}
595 		(void) strlcpy(tmpStr, ipStr+1, startPos-ipStr);
596 		address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_FALSE;
597 		tmpStrPtr = tmpStr;
598 	} else {
599 		/* set start position to beginning of input object */
600 		addressType = AF_INET;
601 		startPos = ipStr;
602 		address->hostnameIpAddress.id.ipAddress.ipv4Address = IMA_TRUE;
603 		tmpStrPtr = ipStr;
604 	}
605 	/* wcschr for ':'. If not there, use default port */
606 	colPos = strchr(startPos, cCol);
607 
608 	if (!colPos) {
609 		if (addrType == DISCOVERY_ADDRESS) {
610 			inputPort = DEFAULT_ISCSI_PORT;
611 		} else if (addrType == ISNS_SERVER_ADDRESS) {
612 			inputPort = ISNS_DEFAULT_SERVER_PORT;
613 		} else {
614 			*colPos = NULL;
615 		}
616 	} else {
617 		*colPos = NULL;
618 	}
619 
620 	rval = inet_pton(addressType, tmpStrPtr,
621 	    address->hostnameIpAddress.id.ipAddress.ipAddress);
622 	/* inet_pton returns 1 on success */
623 	if (rval != 1) {
624 		(void) fprintf(stderr, "%s: %s: %s\n", cmdName, ipStr,
625 		    gettext("invalid IP address"));
626 		return (1);
627 	}
628 
629 
630 	if (colPos) {
631 		char *errchr;
632 
633 		colPos++;
634 		if (*colPos == NULL) {
635 			(void) fprintf(stderr, "%s: %s: %s\n",
636 			    cmdName, ipStr,
637 			    gettext("port number missing"));
638 			return (1);
639 		}
640 
641 		/*
642 		 * convert port string to unsigned value
643 		 * Note:  Don't remove errno = 0 as you may get false failures.
644 		 */
645 		errno = 0;
646 		inputPort = strtol(colPos, &errchr, 10);
647 		if (errno != 0 || inputPort == 0 && errchr != NULL) {
648 			(void) fprintf(stderr, "%s: %s:%s %s\n",
649 			    cmdName, ipStr, colPos,
650 			    gettext("port number invalid"));
651 			return (1);
652 		}
653 		/* make sure it's in the range */
654 		if (inputPort > USHRT_MAX) {
655 			(void) fprintf(stderr, "%s: %s: %s\n",
656 			    cmdName, ipStr,
657 			    gettext("port number out of range"));
658 			return (1);
659 		}
660 	}
661 	address->portNumber  = inputPort;
662 
663 	return (0);
664 }
665 
666 /*
667  * Print results of send targets command
668  */
669 static void
670 printSendTargets(SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList)
671 {
672 	char outBuf[INET6_ADDRSTRLEN];
673 	int inetSize;
674 	int af;
675 	int i;
676 
677 	for (i = 0; i < pList->keyCount; i++) {
678 		if (pList->keys[i].address.ipAddress.ipv4Address == IMA_TRUE) {
679 			af = AF_INET;
680 			inetSize = INET_ADDRSTRLEN;
681 		} else {
682 			af = AF_INET6;
683 			inetSize = INET6_ADDRSTRLEN;
684 		}
685 		(void) fprintf(stdout, gettext("\tTarget name: %ws\n"),
686 		    pList->keys[i].name);
687 		(void) fprintf(stdout, "\t\t%s: %15s:%d", "Target address",
688 		    inet_ntop(af, &(pList->keys[i].address.ipAddress.ipAddress),
689 		    outBuf, inetSize), pList->keys[i].address.portNumber);
690 		(void) fprintf(stdout, ", %d", pList->keys[i].tpgt);
691 		(void) fprintf(stdout, "\n");
692 	}
693 }
694 
695 
696 /*
697  * Print all login parameters
698  */
699 static int
700 printLoginParameters(char *prefix, IMA_OID oid, int printOption)
701 {
702 	IMA_STATUS status;
703 	IMA_BOOL_VALUE propBool;
704 	IMA_MIN_MAX_VALUE propMinMax;
705 	char longString[MAX_LONG_CHAR_LEN + 1];
706 	SUN_IMA_CONN_PROPERTIES	*connProps = NULL;
707 	IMA_OID_LIST *pConnList;
708 
709 	(void) memset(longString, 0, sizeof (longString));
710 
711 	switch (printOption) {
712 		case PRINT_CONFIGURED_PARAMS:
713 			(void) fprintf(stdout, "%s%s:\n",
714 			    prefix,
715 			    gettext("Login Parameters (Default/Configured)"));
716 			break;
717 		case PRINT_NEGOTIATED_PARAMS:
718 			(void) fprintf(stdout, "%s%s:\n",
719 			    prefix,
720 			    gettext("Login Parameters (Negotiated)"));
721 			status = SUN_IMA_GetConnOidList(
722 			    &oid,
723 			    &pConnList);
724 
725 			if (!IMA_SUCCESS(status)) {
726 				printLibError(status);
727 				return (1);
728 			}
729 
730 			status = SUN_IMA_GetConnProperties(&pConnList->oids[0],
731 			    &connProps);
732 			propBool.currentValueValid = connProps->valuesValid;
733 			propMinMax.currentValueValid = connProps->valuesValid;
734 			break;
735 		default:
736 			return (1);
737 	}
738 
739 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
740 		propBool.currentValue = connProps->dataSequenceInOrder;
741 	} else {
742 		status = IMA_GetDataSequenceInOrderProperties(oid, &propBool);
743 	}
744 	if (!IMA_SUCCESS(status)) {
745 		printLibError(status);
746 		(void) IMA_FreeMemory(connProps);
747 		return (1);
748 	}
749 	(void) fprintf(stdout, "%s\t%s: ", prefix,
750 	    gettext("Data Sequence In Order"));
751 	IMABOOLPRINT(propBool, printOption);
752 
753 
754 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
755 		propBool.currentValue = connProps->dataPduInOrder;
756 	} else {
757 		status = IMA_GetDataPduInOrderProperties(oid, &propBool);
758 	}
759 	if (!IMA_SUCCESS(status)) {
760 		printLibError(status);
761 		(void) IMA_FreeMemory(connProps);
762 		return (1);
763 	}
764 	(void) fprintf(stdout, "%s\t%s: ", prefix,
765 	    gettext("Data PDU In Order"));
766 	IMABOOLPRINT(propBool, printOption);
767 
768 
769 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
770 		propMinMax.currentValue = connProps->defaultTime2Retain;
771 	} else {
772 		status = IMA_GetDefaultTime2RetainProperties(oid, &propMinMax);
773 	}
774 	if (!IMA_SUCCESS(status)) {
775 		printLibError(status);
776 		(void) IMA_FreeMemory(connProps);
777 		return (1);
778 	}
779 	(void) fprintf(stdout, "%s\t%s: ", prefix,
780 	    gettext("Default Time To Retain"));
781 	IMAMINMAXPRINT(propMinMax, printOption);
782 
783 
784 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
785 		propMinMax.currentValue = connProps->defaultTime2Wait;
786 	} else {
787 		status = IMA_GetDefaultTime2WaitProperties(oid, &propMinMax);
788 	}
789 	if (!IMA_SUCCESS(status)) {
790 		printLibError(status);
791 		(void) IMA_FreeMemory(connProps);
792 		return (1);
793 	}
794 	(void) fprintf(stdout, "%s\t%s: ", prefix,
795 	    gettext("Default Time To Wait"));
796 	IMAMINMAXPRINT(propMinMax, printOption);
797 
798 
799 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
800 		propMinMax.currentValue = connProps->errorRecoveryLevel;
801 	} else {
802 		status = IMA_GetErrorRecoveryLevelProperties(oid, &propMinMax);
803 	}
804 	if (!IMA_SUCCESS(status)) {
805 		printLibError(status);
806 		(void) IMA_FreeMemory(connProps);
807 		return (1);
808 	}
809 	(void) fprintf(stdout, "%s\t%s: ", prefix,
810 	    gettext("Error Recovery Level"));
811 	IMAMINMAXPRINT(propMinMax, printOption);
812 
813 
814 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
815 		propMinMax.currentValue = connProps->firstBurstLength;
816 	} else {
817 		status = IMA_GetFirstBurstLengthProperties(oid,
818 		    &propMinMax);
819 	}
820 	if (!IMA_SUCCESS(status)) {
821 		printLibError(status);
822 		(void) IMA_FreeMemory(connProps);
823 		return (1);
824 	}
825 	(void) fprintf(stdout, "%s\t%s: ",
826 	    prefix, gettext("First Burst Length"));
827 	IMAMINMAXPRINT(propMinMax, printOption);
828 
829 
830 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
831 		propBool.currentValue = connProps->immediateData;
832 	} else {
833 		status = IMA_GetImmediateDataProperties(oid, &propBool);
834 	}
835 	if (!IMA_SUCCESS(status)) {
836 		printLibError(status);
837 		(void) IMA_FreeMemory(connProps);
838 		return (1);
839 	}
840 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Immediate Data"));
841 	IMABOOLPRINT(propBool, printOption);
842 
843 
844 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
845 		propBool.currentValue = connProps->initialR2T;
846 	} else {
847 		status = IMA_GetInitialR2TProperties(oid, &propBool);
848 	}
849 	if (!IMA_SUCCESS(status)) {
850 		printLibError(status);
851 		(void) IMA_FreeMemory(connProps);
852 		return (1);
853 	}
854 	(void) fprintf(stdout, "%s\t%s: ", prefix,
855 	    gettext("Initial Ready To Transfer (R2T)"));
856 	IMABOOLPRINT(propBool, printOption);
857 
858 
859 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
860 		propMinMax.currentValue = connProps->maxBurstLength;
861 	} else {
862 		status = IMA_GetMaxBurstLengthProperties(oid, &propMinMax);
863 	}
864 	if (!IMA_SUCCESS(status)) {
865 		printLibError(status);
866 		(void) IMA_FreeMemory(connProps);
867 		return (1);
868 	}
869 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Burst Length"));
870 	IMAMINMAXPRINT(propMinMax, printOption);
871 
872 
873 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
874 		propMinMax.currentValue = connProps->maxOutstandingR2T;
875 	} else {
876 		status = IMA_GetMaxOutstandingR2TProperties(oid, &propMinMax);
877 	}
878 	if (!IMA_SUCCESS(status)) {
879 		printLibError(status);
880 		(void) IMA_FreeMemory(connProps);
881 		return (1);
882 	}
883 	(void) fprintf(stdout, "%s\t%s: ", prefix,
884 	    gettext("Max Outstanding R2T"));
885 	IMAMINMAXPRINT(propMinMax, printOption);
886 
887 
888 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
889 		propMinMax.currentValue = connProps->maxRecvDataSegmentLength;
890 	} else {
891 		status = IMA_GetMaxRecvDataSegmentLengthProperties(oid,
892 		    &propMinMax);
893 	}
894 	if (!IMA_SUCCESS(status)) {
895 		printLibError(status);
896 		(void) IMA_FreeMemory(connProps);
897 		return (1);
898 	}
899 	(void) fprintf(stdout, "%s\t%s: ", prefix,
900 	    gettext("Max Receive Data Segment Length"));
901 	IMAMINMAXPRINT(propMinMax, printOption);
902 
903 
904 	if (printOption == PRINT_NEGOTIATED_PARAMS) {
905 		propMinMax.currentValue = connProps->maxConnections;
906 	} else {
907 		status = IMA_GetMaxConnectionsProperties(oid, &propMinMax);
908 	}
909 	if (!IMA_SUCCESS(status)) {
910 		printLibError(status);
911 		(void) IMA_FreeMemory(connProps);
912 		return (1);
913 	}
914 	(void) fprintf(stdout, "%s\t%s: ", prefix, gettext("Max Connections"));
915 	IMAMINMAXPRINT(propMinMax, printOption);
916 
917 	(void) IMA_FreeMemory(connProps);
918 	return (0);
919 }
920 
921 /*
922  * Print discovery information.
923  */
924 static void
925 printDiscoveryMethod(char *prefix, IMA_UINT32 discoveryMethodFlags)
926 {
927 	(void) fprintf(stdout, "%s%s: ", prefix, gettext("Discovery Method"));
928 	if (discoveryMethodFlags == IMA_TARGET_DISCOVERY_METHOD_UNKNOWN) {
929 		(void) fprintf(stdout, "%s\n", gettext("NA"));
930 	} else {
931 		if (!((discoveryMethodFlags &
932 		    IMA_TARGET_DISCOVERY_METHOD_STATIC) ^
933 		    IMA_TARGET_DISCOVERY_METHOD_STATIC)) {
934 			(void) fprintf(stdout, "%s ", gettext("Static"));
935 		}
936 		if (!((discoveryMethodFlags &
937 		    IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS) ^
938 		    IMA_TARGET_DISCOVERY_METHOD_SENDTARGETS)) {
939 			(void) fprintf(stdout, "%s ", gettext("SendTargets"));
940 		}
941 		if (!((discoveryMethodFlags &
942 		    IMA_TARGET_DISCOVERY_METHOD_ISNS) ^
943 		    IMA_TARGET_DISCOVERY_METHOD_ISNS)) {
944 			(void) fprintf(stdout, "%s ", gettext("iSNS"));
945 		}
946 		(void) fprintf(stdout, "\n");
947 	}
948 }
949 
950 /*
951  * printConnectionList - Prints the conection list provided
952  */
953 static void
954 printConnectionList(char *prefix, IMA_OID_LIST *pConnList)
955 {
956 	IMA_STATUS		imaStatus;
957 	int			i;
958 	SUN_IMA_CONN_PROPERTIES	*connProps;
959 	union {
960 		char	ipv4[INET_ADDRSTRLEN+1];
961 		char	ipv6[INET6_ADDRSTRLEN+1];
962 	} tmp;
963 
964 	for (i = 0; i < pConnList->oidCount; i++) {
965 		imaStatus = SUN_IMA_GetConnProperties(&pConnList->oids[i],
966 		    &connProps);
967 
968 		if (imaStatus != IMA_STATUS_SUCCESS) {
969 			continue;
970 		}
971 
972 		(void) fprintf(stdout, "%sCID: %d\n", prefix,
973 		    connProps->connectionID);
974 
975 		(void) memset(&tmp, 0, sizeof (tmp));
976 		if (connProps->local.ipAddress.ipv4Address == IMA_TRUE) {
977 			if (inet_ntop(AF_INET,
978 			    &connProps->local.ipAddress.ipAddress[0],
979 			    &tmp.ipv4[0],
980 			    INET_ADDRSTRLEN)) {
981 				(void) fprintf(stdout,
982 				    "%s  %s: %s:%u\n",
983 				    prefix,
984 				    gettext("IP address (Local)"),
985 				    &tmp.ipv4[0],
986 				    ntohs(connProps->local.portNumber));
987 			}
988 		} else {
989 			if (inet_ntop(AF_INET6,
990 			    &connProps->local.ipAddress.ipAddress[0],
991 			    &tmp.ipv6[0],
992 			    INET6_ADDRSTRLEN)) {
993 				(void) fprintf(stdout,
994 				    "%s  %s: [%s]:%u\n",
995 				    prefix,
996 				    gettext("IP address (Local)"),
997 				    &tmp.ipv6[0],
998 				    ntohs(connProps->local.portNumber));
999 			}
1000 		}
1001 		if (connProps->peer.ipAddress.ipv4Address == IMA_TRUE) {
1002 			if (inet_ntop(AF_INET,
1003 			    &connProps->peer.ipAddress.ipAddress[0],
1004 			    &tmp.ipv4[0],
1005 			    INET_ADDRSTRLEN)) {
1006 				(void) fprintf(stdout,
1007 				    "%s  %s: %s:%u\n",
1008 				    prefix,
1009 				    gettext("IP address (Peer)"),
1010 				    &tmp.ipv4[0],
1011 				    ntohs(connProps->peer.portNumber));
1012 			}
1013 		} else {
1014 			if (inet_ntop(AF_INET6,
1015 			    &connProps->peer.ipAddress.ipAddress[0],
1016 			    &tmp.ipv6[0],
1017 			    INET6_ADDRSTRLEN)) {
1018 				(void) fprintf(stdout,
1019 				    "%s  %s: [%s]:%u\n",
1020 				    prefix,
1021 				    gettext("IP address (Peer)"),
1022 				    &tmp.ipv6[0],
1023 				    ntohs(connProps->peer.portNumber));
1024 			}
1025 		}
1026 
1027 		(void) IMA_FreeMemory(connProps);
1028 	}
1029 }
1030 
1031 /*
1032  * Set login parameters on a target or initiator
1033  */
1034 static int
1035 setLoginParameter(IMA_OID oid, int optval, char *optarg)
1036 {
1037 	IMA_STATUS status = IMA_STATUS_SUCCESS;
1038 	IMA_UINT uintValue;
1039 	IMA_BOOL boolValue;
1040 	SUN_IMA_DIGEST_ALGORITHM digestAlgList[1];
1041 	IMA_MIN_MAX_VALUE propMinMax;
1042 	char *endptr;
1043 
1044 	/*
1045 	 * for clarity, there are two switch statements
1046 	 * The first loads the variable and the second
1047 	 * calls the appropriate API
1048 	 */
1049 	switch (optval) {
1050 		case DATA_SEQ_IN_ORDER:
1051 		case IMMEDIATE_DATA:
1052 		case INITIAL_R2T:
1053 		case DATA_PDU_IN_ORDER:
1054 			/* implement 'default'? */
1055 			if (strcasecmp(optarg, "yes") == 0) {
1056 				boolValue = IMA_TRUE;
1057 			} else if (strcasecmp(optarg, "no") == 0) {
1058 				boolValue = IMA_FALSE;
1059 			} else {
1060 				(void) fprintf(stderr, "%s: %s - %s\n",
1061 				    cmdName,
1062 				    gettext("invalid option argument"),
1063 				    optarg);
1064 				return (1);
1065 			}
1066 			break;
1067 		case DEFAULT_TIME_2_RETAIN:
1068 		case DEFAULT_TIME_2_WAIT:
1069 			errno = 0;
1070 			uintValue = strtoul(optarg, &endptr, 0);
1071 			if (*endptr != '\0' || errno != 0) {
1072 				(void) fprintf(stderr, "%s: %s - %s\n",
1073 				    cmdName,
1074 				    gettext("invalid option argument"),
1075 				    optarg);
1076 				return (1);
1077 			}
1078 			if (uintValue > 3600) {
1079 				(void) fprintf(stderr, "%s: %s\n",
1080 				    cmdName,
1081 gettext("value must be between 0 and 3600"));
1082 				return (1);
1083 			}
1084 			break;
1085 		case FIRST_BURST_LENGTH:
1086 		case MAX_BURST_LENGTH:
1087 		case MAX_RECV_DATA_SEG_LEN:
1088 			errno = 0;
1089 			/* implement 'default'? */
1090 			uintValue = strtoul(optarg, &endptr, 0);
1091 			if (*endptr != '\0' || errno != 0) {
1092 				(void) fprintf(stderr, "%s: %s - %s\n",
1093 				    cmdName,
1094 				    gettext("invalid option argument"),
1095 				    optarg);
1096 				return (1);
1097 			}
1098 			if (uintValue < 512 || uintValue > 16777215) {
1099 				(void) fprintf(stderr, "%s: %s\n",
1100 				    cmdName,
1101 gettext("value must be between 512 and 16777215"));
1102 				return (1);
1103 			}
1104 			break;
1105 		case MAX_OUTSTANDING_R2T:
1106 			errno = 0;
1107 			uintValue = strtoul(optarg, &endptr, 0);
1108 			if (*endptr != '\0' || errno != 0) {
1109 				(void) fprintf(stderr, "%s: %s - %s\n",
1110 				    cmdName,
1111 				    gettext("invalid option argument"),
1112 				    optarg);
1113 				return (1);
1114 			}
1115 			if (uintValue < 1 || uintValue > 65535) {
1116 				(void) fprintf(stderr, "%s: %s\n",
1117 				    cmdName,
1118 gettext("value must be between 1 and 65535"));
1119 				return (1);
1120 			}
1121 			break;
1122 		case HEADER_DIGEST:
1123 		case DATA_DIGEST:
1124 			if (strcasecmp(optarg, "none") == 0) {
1125 				digestAlgList[0] = SUN_IMA_DIGEST_NONE;
1126 			} else if (strcasecmp(optarg, "CRC32") == 0) {
1127 				digestAlgList[0] = SUN_IMA_DIGEST_CRC32;
1128 			} else {
1129 				(void) fprintf(stderr, "%s: %s - %s\n",
1130 				    cmdName,
1131 				    gettext("invalid option argument"),
1132 				    optarg);
1133 				return (1);
1134 			}
1135 			break;
1136 		case MAX_CONNECTIONS:
1137 			errno = 0;
1138 			uintValue = strtoul(optarg, &endptr, 0);
1139 			if (*endptr != '\0' || errno != 0) {
1140 				(void) fprintf(stderr, "%s: %s - %s\n",
1141 				    cmdName,
1142 				    gettext("invalid option argument"),
1143 				    optarg);
1144 				return (1);
1145 			}
1146 			if (uintValue < 1 || uintValue > 256) {
1147 				(void) fprintf(stderr, "%s: %s\n",
1148 				    cmdName,
1149 gettext("value must be between 1 and 256"));
1150 				return (1);
1151 			}
1152 			break;
1153 		case ERROR_RECOVERY_LEVEL:
1154 			errno = 0;
1155 			uintValue = strtoul(optarg, &endptr, 0);
1156 			if (*endptr != '\0' || errno != 0) {
1157 				(void) fprintf(stderr, "%s: %s - %s\n",
1158 				    cmdName,
1159 				    gettext("invalid option argument"),
1160 				    optarg);
1161 				return (1);
1162 			}
1163 			if (uintValue > 2) {
1164 				(void) fprintf(stderr, "%s: %s\n",
1165 				    cmdName,
1166 gettext("value must be between 0 and 2"));
1167 				return (1);
1168 			}
1169 			break;
1170 		default:
1171 			(void) fprintf(stderr, "%s: %c: %s\n",
1172 			    cmdName, optval, gettext("unknown option"));
1173 			return (1);
1174 	}
1175 
1176 	switch (optval) {
1177 		case DATA_PDU_IN_ORDER:
1178 			status = IMA_SetDataPduInOrder(oid, boolValue);
1179 			break;
1180 		case DATA_SEQ_IN_ORDER:
1181 			status = IMA_SetDataSequenceInOrder(oid, boolValue);
1182 			break;
1183 		case DEFAULT_TIME_2_RETAIN:
1184 			status = IMA_SetDefaultTime2Retain(oid, uintValue);
1185 			break;
1186 		case DEFAULT_TIME_2_WAIT:
1187 			status = IMA_SetDefaultTime2Wait(oid, uintValue);
1188 			break;
1189 		case FIRST_BURST_LENGTH:
1190 			status = IMA_SetFirstBurstLength(oid, uintValue);
1191 
1192 			/*
1193 			 * If this call fails check to see if it's because
1194 			 * the requested value is > than maxBurstLength
1195 			 */
1196 			if (!IMA_SUCCESS(status)) {
1197 				status = IMA_GetMaxBurstLengthProperties(oid,
1198 				    &propMinMax);
1199 				if (!IMA_SUCCESS(status)) {
1200 					printLibError(status);
1201 					return (1);
1202 				}
1203 				if (uintValue > propMinMax.currentValue) {
1204 					(void) fprintf(stderr,
1205 					    "%s: %s\n", cmdName,
1206 					    gettext("firstBurstLength must " \
1207 					    "be less than or equal to than " \
1208 					    "maxBurstLength"));
1209 				}
1210 				return (1);
1211 			}
1212 
1213 			break;
1214 		case IMMEDIATE_DATA:
1215 			status = IMA_SetImmediateData(oid, boolValue);
1216 			break;
1217 		case INITIAL_R2T:
1218 			status = IMA_SetInitialR2T(oid, boolValue);
1219 			break;
1220 		case MAX_BURST_LENGTH:
1221 			status = IMA_SetMaxBurstLength(oid, uintValue);
1222 			/*
1223 			 * If this call fails check to see if it's because
1224 			 * the requested value is < than firstBurstLength
1225 			 */
1226 			if (!IMA_SUCCESS(status)) {
1227 				status = IMA_GetFirstBurstLengthProperties(oid,
1228 				    &propMinMax);
1229 				if (!IMA_SUCCESS(status)) {
1230 					printLibError(status);
1231 					return (1);
1232 				}
1233 				if (uintValue < propMinMax.currentValue) {
1234 					(void) fprintf(stderr, "%s: %s\n",
1235 					    cmdName,
1236 					    gettext("maxBurstLength must be " \
1237 					    "greater than or equal to " \
1238 					    "firstBurstLength"));
1239 				}
1240 				return (1);
1241 			}
1242 			break;
1243 
1244 		case MAX_OUTSTANDING_R2T:
1245 			status = IMA_SetMaxOutstandingR2T(oid, uintValue);
1246 			break;
1247 		case MAX_RECV_DATA_SEG_LEN:
1248 			status = IMA_SetMaxRecvDataSegmentLength(oid,
1249 			    uintValue);
1250 			break;
1251 		case HEADER_DIGEST:
1252 			status = SUN_IMA_SetHeaderDigest(oid, 1,
1253 			    &digestAlgList[0]);
1254 			break;
1255 		case DATA_DIGEST:
1256 			status = SUN_IMA_SetDataDigest(oid, 1,
1257 			    &digestAlgList[0]);
1258 			break;
1259 		case MAX_CONNECTIONS:
1260 			status = IMA_SetMaxConnections(oid, uintValue);
1261 			break;
1262 		case ERROR_RECOVERY_LEVEL:
1263 			status = IMA_SetErrorRecoveryLevel(oid, uintValue);
1264 			break;
1265 	}
1266 	if (!IMA_SUCCESS(status)) {
1267 		printLibError(status);
1268 		return (1);
1269 	}
1270 	return (0);
1271 }
1272 
1273 static void
1274 printDigestAlgorithm(SUN_IMA_DIGEST_ALGORITHM_VALUE *digestAlgorithms,
1275     int printOption)
1276 {
1277 	int i;
1278 
1279 	if (printOption == PRINT_CONFIGURED_PARAMS) {
1280 		for (i = 0; i < digestAlgorithms->defaultAlgorithmCount; i++) {
1281 			if (i > 0) {
1282 				(void) fprintf(stdout, "|");
1283 			}
1284 			switch (digestAlgorithms->defaultAlgorithms[i]) {
1285 				case SUN_IMA_DIGEST_NONE:
1286 					(void) fprintf(stdout,
1287 					    gettext("NONE"));
1288 					break;
1289 				case SUN_IMA_DIGEST_CRC32:
1290 					(void) fprintf(stdout,
1291 					    gettext("CRC32"));
1292 					break;
1293 				default:
1294 					(void) fprintf(stdout,
1295 					    gettext("Unknown"));
1296 					break;
1297 			}
1298 		}
1299 		(void) fprintf(stdout, "/");
1300 		if (digestAlgorithms->currentValid == IMA_TRUE) {
1301 			for (i = 0;
1302 			    i < digestAlgorithms->currentAlgorithmCount; i++) {
1303 				if (i > 0) {
1304 					(void) fprintf(stdout, "|");
1305 				}
1306 				switch (digestAlgorithms->
1307 				    currentAlgorithms[i]) {
1308 					case SUN_IMA_DIGEST_NONE:
1309 						(void) fprintf(stdout,
1310 						    gettext("NONE"));
1311 						break;
1312 					case SUN_IMA_DIGEST_CRC32:
1313 						(void) fprintf(stdout,
1314 						    gettext("CRC32"));
1315 						break;
1316 					default:
1317 						(void) fprintf(stdout,
1318 						    gettext("Unknown"));
1319 						break;
1320 				}
1321 			}
1322 		} else {
1323 			(void) fprintf(stdout, "-");
1324 		}
1325 		(void) fprintf(stdout, "\n");
1326 	} else if (printOption == PRINT_NEGOTIATED_PARAMS) {
1327 
1328 		if (digestAlgorithms->negotiatedValid == IMA_TRUE) {
1329 			for (i = 0;
1330 			    i < digestAlgorithms->negotiatedAlgorithmCount;
1331 			    i++) {
1332 				if (i > 0) {
1333 					(void) fprintf(stdout, "|");
1334 				}
1335 				switch (digestAlgorithms->
1336 				    negotiatedAlgorithms[i]) {
1337 					case SUN_IMA_DIGEST_NONE:
1338 						(void) fprintf(stdout,
1339 						    gettext("NONE"));
1340 						break;
1341 					case SUN_IMA_DIGEST_CRC32:
1342 						(void) fprintf(stdout,
1343 						    gettext("CRC32"));
1344 						break;
1345 					default:
1346 						(void) fprintf(stdout,
1347 						    gettext("Unknown"));
1348 						break;
1349 				}
1350 			}
1351 		} else {
1352 			(void) fprintf(stdout, "-");
1353 		}
1354 		(void) fprintf(stdout, "\n");
1355 	}
1356 }
1357 
1358 static int
1359 setLoginParameters(IMA_OID oid, char *optarg)
1360 {
1361 	char keyp[MAXOPTARGLEN];
1362 	char valp[MAXOPTARGLEN];
1363 	int key;
1364 	char *nameValueString, *indexp, *delim = NULL;
1365 
1366 	if ((nameValueString = strdup(optarg)) == NULL) {
1367 		if (errno == ENOMEM) {
1368 			(void) fprintf(stderr, "%s: %s\n",
1369 			    cmdName, strerror(errno));
1370 		} else {
1371 			(void) fprintf(stderr, "%s: %s\n", cmdName,
1372 			    gettext("unknown error"));
1373 		}
1374 		return (1);
1375 	}
1376 
1377 	indexp = nameValueString;
1378 
1379 	/*
1380 	 * Retrieve all login params from option argument
1381 	 * Syntax <key=value,...>
1382 	 */
1383 	while (indexp) {
1384 		if (delim = strchr(indexp, ',')) {
1385 			delim[0] = '\0';
1386 		}
1387 		(void) memset(keyp, 0, sizeof (keyp));
1388 		(void) memset(valp, 0, sizeof (valp));
1389 		if (sscanf(indexp, gettext("%[^=]=%s"), keyp, valp) != 2) {
1390 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1391 			    gettext("Unknown param"), indexp);
1392 			return (1);
1393 		}
1394 		if ((key = getLoginParam(keyp)) == -1) {
1395 			(void) fprintf(stderr, "%s: %s: %s\n", cmdName,
1396 			    gettext("Unknown key"), keyp);
1397 			return (1);
1398 		}
1399 		if (setLoginParameter(oid, key, valp) != 0) {
1400 			return (1);
1401 		}
1402 		if (delim) {
1403 			indexp = delim + 1;
1404 		} else {
1405 			indexp = NULL;
1406 		}
1407 	}
1408 
1409 	return (0);
1410 }
1411 
1412 /*
1413  * Print logical unit information for a specific target
1414  */
1415 static void
1416 printTargetLuns(IMA_OID_LIST * lunList)
1417 {
1418 	int	j;
1419 	IMA_STATUS status;
1420 	SUN_IMA_LU_PROPERTIES	lunProps;
1421 
1422 	for (j = 0; j < lunList->oidCount; j++) {
1423 		status = SUN_IMA_GetLuProperties(lunList->oids[j],
1424 		    &lunProps);
1425 		if (!IMA_SUCCESS(status)) {
1426 			printLibError(status);
1427 			return;
1428 		}
1429 
1430 		if (lunProps.imaProps.osDeviceNameValid == IMA_TRUE) {
1431 			(void) fprintf(stdout, "\tLUN: %lld\n",
1432 			    lunProps.imaProps.targetLun);
1433 			(void) fprintf(stdout, "\t     Vendor:  %s\n",
1434 			    lunProps.vendorId);
1435 			(void) fprintf(stdout, "\t     Product: %s\n",
1436 			    lunProps.productId);
1437 			(void) fprintf(stdout,
1438 			    gettext("\t     OS Device Name: %ws\n"),
1439 			    lunProps.imaProps.osDeviceName);
1440 		}
1441 	}
1442 }
1443 
1444 /*
1445  * Retrieve CHAP secret from input
1446  */
1447 static int
1448 getSecret(char *secret, int *secretLen, int minSecretLen, int maxSecretLen)
1449 {
1450 	char *chapSecret;
1451 
1452 	/* get password */
1453 	chapSecret = getpassphrase(gettext("Enter secret:"));
1454 
1455 	if (strlen(chapSecret) > maxSecretLen) {
1456 		(void) fprintf(stderr, "%s: %s %d\n", cmdName,
1457 		    gettext("secret too long, maximum length is"),
1458 		    maxSecretLen);
1459 		*secret = NULL;
1460 		return (1);
1461 	}
1462 
1463 	if (strlen(chapSecret) < minSecretLen) {
1464 		(void) fprintf(stderr, "%s: %s %d\n", cmdName,
1465 		    gettext("secret too short, minimum length is"),
1466 		    minSecretLen);
1467 		*secret = NULL;
1468 		return (1);
1469 	}
1470 
1471 	(void) strcpy(secret, chapSecret);
1472 
1473 	chapSecret = getpassphrase(gettext("Re-enter secret:"));
1474 	if (strcmp(secret, chapSecret) != 0) {
1475 		(void) fprintf(stderr, "%s: %s\n", cmdName,
1476 		    gettext("secrets do not match, secret not changed"));
1477 		*secret = NULL;
1478 		return (1);
1479 	}
1480 	*secretLen = strlen(chapSecret);
1481 	return (0);
1482 }
1483 
1484 /*
1485  * Lists the discovery attributes
1486  */
1487 static int
1488 listDiscovery(int *funcRet)
1489 {
1490 	IMA_OID	initiatorOid;
1491 	IMA_DISCOVERY_PROPERTIES discProps;
1492 	int ret;
1493 	IMA_STATUS status;
1494 
1495 	assert(funcRet != NULL);
1496 
1497 
1498 	/* Find Sun initiator */
1499 	ret = sunInitiatorFind(&initiatorOid);
1500 	if (ret > 0) {
1501 		(void) fprintf(stderr, "%s: %s\n",
1502 		    cmdName, gettext("no initiator found"));
1503 	}
1504 
1505 	if (ret != 0) {
1506 		return (ret);
1507 	}
1508 
1509 	/* Get discovery attributes from IMA */
1510 	status = IMA_GetDiscoveryProperties(initiatorOid, &discProps);
1511 	if (!IMA_SUCCESS(status)) {
1512 		printLibError(status);
1513 		*funcRet = 1;
1514 		return (ret);
1515 	}
1516 
1517 
1518 	(void) fprintf(stdout, "%s:\n", "Discovery");
1519 	(void) fprintf(stdout, "\tStatic: %s\n",
1520 	    discProps.staticDiscoveryEnabled == IMA_TRUE ? \
1521 	    gettext("enabled") : gettext("disabled"));
1522 	(void) fprintf(stdout, "\tSend Targets: %s\n",
1523 	    discProps.sendTargetsDiscoveryEnabled == IMA_TRUE ? \
1524 	    gettext("enabled") : gettext("disabled"));
1525 	(void) fprintf(stdout, "\tiSNS: %s\n",
1526 	    discProps.iSnsDiscoveryEnabled == IMA_TRUE ? \
1527 	    gettext("enabled") : gettext("disabled"));
1528 
1529 	return (0);
1530 }
1531 
1532 /*
1533  * Print all initiator node attributes
1534  */
1535 static int
1536 listNode(int *funcRet)
1537 {
1538 	IMA_OID	initiatorOid;
1539 	IMA_NODE_PROPERTIES nodeProps;
1540 	IMA_STATUS status;
1541 	int ret;
1542 	IMA_UINT maxEntries = MAX_AUTH_METHODS;
1543 	IMA_AUTHMETHOD	methodList[MAX_AUTH_METHODS];
1544 	SUN_IMA_RADIUS_CONFIG radiusConfig;
1545 	SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
1546 	IMA_BOOL radiusAccess;
1547 
1548 	int i;
1549 
1550 	assert(funcRet != NULL);
1551 
1552 	ret = getNodeProps(&nodeProps);
1553 	if (ret != 0) {
1554 		return (ret);
1555 	}
1556 
1557 	if (nodeProps.nameValid == IMA_FALSE) {
1558 		return (INVALID_NODE_NAME);
1559 	}
1560 
1561 	/* Find Sun initiator */
1562 	ret = sunInitiatorFind(&initiatorOid);
1563 	if (ret > 0) {
1564 		(void) fprintf(stderr, "%s: %s\n",
1565 		    cmdName, gettext("no initiator found"));
1566 	}
1567 
1568 	if (ret != 0) {
1569 		return (ret);
1570 	}
1571 	/* Begin output */
1572 	(void) fprintf(stdout, gettext("%s: %ws\n"),
1573 	    gettext("Initiator node name"),
1574 	    nodeProps.name);
1575 	(void) fprintf(stdout, gettext("Initiator node alias: "));
1576 	if (nodeProps.aliasValid == IMA_TRUE) {
1577 		(void) fprintf(stdout, gettext("%ws\n"), nodeProps.alias);
1578 	} else {
1579 		(void) fprintf(stdout, "%s\n", "-");
1580 	}
1581 	(void) fprintf(stdout, "\t%s:\n",
1582 	    gettext("Login Parameters (Default/Configured)"));
1583 
1584 	/* Get Digest configuration */
1585 	status = SUN_IMA_GetHeaderDigest(initiatorOid, &digestAlgorithms);
1586 	if (IMA_SUCCESS(status)) {
1587 		(void) fprintf(stdout, "\t\t%s: ", gettext("Header Digest"));
1588 		printDigestAlgorithm(&digestAlgorithms,
1589 		    PRINT_CONFIGURED_PARAMS);
1590 	} else {
1591 		printLibError(status);
1592 		*funcRet = 1;
1593 		return (ret);
1594 	}
1595 
1596 	status = SUN_IMA_GetDataDigest(initiatorOid, &digestAlgorithms);
1597 	if (IMA_SUCCESS(status)) {
1598 		(void) fprintf(stdout, "\t\t%s: ", gettext("Data Digest"));
1599 		printDigestAlgorithm(&digestAlgorithms,
1600 		    PRINT_CONFIGURED_PARAMS);
1601 	} else {
1602 		printLibError(status);
1603 		*funcRet = 1;
1604 		return (ret);
1605 	}
1606 
1607 	/* Get authentication type for this lhba */
1608 	status = IMA_GetInUseInitiatorAuthMethods(initiatorOid, &maxEntries,
1609 	    &methodList[0]);
1610 	(void) fprintf(stdout, "\t%s: ", gettext("Authentication Type"));
1611 	if (!IMA_SUCCESS(status)) {
1612 		/* No authentication method set - default is NONE */
1613 		(void) fprintf(stdout, gettext("NONE"));
1614 	} else {
1615 		for (i = 0; i < maxEntries; i++) {
1616 			if (i > 0) {
1617 				(void) fprintf(stdout, "|");
1618 			}
1619 			switch (methodList[i]) {
1620 				case IMA_AUTHMETHOD_NONE:
1621 					(void) fprintf(stdout, gettext("NONE"));
1622 					break;
1623 				case IMA_AUTHMETHOD_CHAP:
1624 					(void) fprintf(stdout, gettext("CHAP"));
1625 					listCHAPName(initiatorOid);
1626 					break;
1627 				default:
1628 					(void) fprintf(stdout,
1629 					    gettext("unknown type"));
1630 					break;
1631 			}
1632 		}
1633 	}
1634 	(void) fprintf(stdout, "\n");
1635 
1636 
1637 	/* Get RADIUS configuration */
1638 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
1639 	(void) fprintf(stdout, "\t%s: ", gettext("RADIUS Server"));
1640 	if (IMA_SUCCESS(status)) {
1641 		if (strlen(radiusConfig.hostnameIpAddress) > 0) {
1642 			(void) fprintf(stdout, "%s:%d",
1643 			    radiusConfig.hostnameIpAddress,
1644 			    radiusConfig.port);
1645 		} else {
1646 			(void) fprintf(stdout, "%s", gettext("NONE"));
1647 		}
1648 	} else {
1649 		(void) fprintf(stdout, "%s", gettext("NONE"));
1650 	}
1651 	(void) fprintf(stdout, "\n");
1652 
1653 	status = SUN_IMA_GetInitiatorRadiusAccess(initiatorOid,
1654 	    &radiusAccess);
1655 	(void) fprintf(stdout, "\t%s: ", gettext("RADIUS Access"));
1656 	if (IMA_SUCCESS(status)) {
1657 		if (radiusAccess == IMA_TRUE) {
1658 			(void) fprintf(stdout, "%s", gettext("enabled"));
1659 		} else {
1660 			(void) fprintf(stdout, "%s", gettext("disabled"));
1661 		}
1662 	} else if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
1663 		(void) fprintf(stdout, "%s", gettext("disabled"));
1664 	} else {
1665 		(void) fprintf(stdout, "%s", gettext("unknown"));
1666 	}
1667 	(void) fprintf(stdout, "\n");
1668 
1669 	/* print configured session information. */
1670 	ret = printConfiguredSessions(initiatorOid);
1671 
1672 	return (ret);
1673 }
1674 
1675 /*
1676  * Print discovery addresses
1677  */
1678 static int
1679 listDiscoveryAddress(int objectLen, char *objects[], cmdOptions_t *options,
1680     int *funcRet)
1681 {
1682 	IMA_OID	initiatorOid;
1683 	SUN_IMA_DISC_ADDR_PROP_LIST *discoveryAddressPropertiesList;
1684 	IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps;
1685 	IMA_TARGET_ADDRESS address;
1686 	SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
1687 	IMA_STATUS status;
1688 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
1689 	int ret;
1690 	boolean_t object = B_FALSE;
1691 	int outerLoop;
1692 	boolean_t found;
1693 	boolean_t verbose = B_FALSE;
1694 	int i, j;
1695 	cmdOptions_t *optionList = options;
1696 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
1697 
1698 	assert(funcRet != NULL);
1699 
1700 	/* Find Sun initiator */
1701 	ret = sunInitiatorFind(&initiatorOid);
1702 	if (ret > 0) {
1703 		(void) fprintf(stderr, "%s: %s\n",
1704 		    cmdName, gettext("no initiator found"));
1705 	}
1706 
1707 	if (ret != 0) {
1708 		return (ret);
1709 	}
1710 
1711 	for (; optionList->optval; optionList++) {
1712 		switch (optionList->optval) {
1713 			case 'v':
1714 				verbose = B_TRUE;
1715 				break;
1716 			default:
1717 				(void) fprintf(stderr, "%s: %c: %s\n",
1718 				    cmdName, optionList->optval,
1719 				    gettext("unknown option"));
1720 				return (1);
1721 		}
1722 	}
1723 
1724 	/*
1725 	 * If there are multiple objects, execute outer 'for' loop that
1726 	 * many times for each target detail, otherwise, execute it only
1727 	 * once with summaries only
1728 	 */
1729 	if (objectLen > 0) {
1730 		object = B_TRUE;
1731 		outerLoop = objectLen;
1732 	} else {
1733 		object = B_FALSE;
1734 		outerLoop = 1;
1735 	}
1736 
1737 	status = SUN_IMA_GetDiscoveryAddressPropertiesList(
1738 	    &discoveryAddressPropertiesList);
1739 	if (!IMA_SUCCESS(status)) {
1740 		printLibError(status);
1741 		*funcRet = 1;
1742 		return (ret);
1743 	}
1744 
1745 	for (i = 0; i < outerLoop; i++) {
1746 		if (object) {
1747 			/* initialize */
1748 			(void) memset(&wcInputObject[0], 0,
1749 			    sizeof (wcInputObject));
1750 			(void) memset(&address, 0, sizeof (address));
1751 			if (mbstowcs(wcInputObject, objects[i],
1752 			    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
1753 				(void) fprintf(stderr, "%s: %s\n",
1754 				    cmdName,
1755 				    gettext("conversion error"));
1756 				ret = 1;
1757 				continue;
1758 			}
1759 
1760 			/*
1761 			 * if one or more objects were input,
1762 			 * get the values
1763 			 */
1764 			if (getTargetAddress(DISCOVERY_ADDRESS,
1765 			    objects[i], &address) != 0) {
1766 				ret = 1;
1767 				continue;
1768 			}
1769 		}
1770 		for (found = B_FALSE, j = 0;
1771 		    j < discoveryAddressPropertiesList->discAddrCount;
1772 		    j++) {
1773 			discAddrProps =
1774 			    discoveryAddressPropertiesList->props[j];
1775 
1776 			/*
1777 			 * Compare the discovery address with the input if
1778 			 * one was input
1779 			 */
1780 			if (object &&
1781 			    ipAddressesEqual(discAddrProps.discoveryAddress,
1782 			    address) && (discAddrProps.discoveryAddress.
1783 			    portNumber == address.portNumber)) {
1784 				found = B_TRUE;
1785 			}
1786 
1787 			if (!object || found) {
1788 				/* Print summary - always */
1789 				if (discAddrProps.discoveryAddress.
1790 				    hostnameIpAddress.id.ipAddress.
1791 				    ipv4Address) {
1792 					(void) inet_ntop(AF_INET, discAddrProps.
1793 					    discoveryAddress.hostnameIpAddress.
1794 					    id.ipAddress.ipAddress, sAddr,
1795 					    sizeof (sAddr));
1796 					(void) fprintf(stdout,
1797 					    "Discovery Address: %s:%u\n",
1798 					    sAddr, discAddrProps.
1799 					    discoveryAddress.portNumber);
1800 				} else {
1801 					(void) inet_ntop(AF_INET6,
1802 					    discAddrProps.
1803 					    discoveryAddress.hostnameIpAddress.
1804 					    id.ipAddress.ipAddress, sAddr,
1805 					    sizeof (sAddr));
1806 					(void) fprintf(stdout,
1807 					    "DiscoveryAddress: [%s]:%u\n",
1808 					    sAddr, discAddrProps.
1809 					    discoveryAddress.portNumber);
1810 				}
1811 			}
1812 
1813 			if ((!object || found) && verbose) {
1814 				IMA_NODE_PROPERTIES nodeProps;
1815 
1816 				if (getNodeProps(&nodeProps) != 0) {
1817 					break;
1818 				}
1819 
1820 				/*
1821 				 * Issue sendTargets only when an addr is
1822 				 * specified.
1823 				 */
1824 				status = SUN_IMA_SendTargets(nodeProps.name,
1825 				    discAddrProps.discoveryAddress, &pList);
1826 				if (!IMA_SUCCESS(status)) {
1827 					(void) fprintf(stderr, "%s\n",
1828 					    gettext("\tUnable to get "\
1829 					    "targets."));
1830 					*funcRet = 1;
1831 					continue;
1832 				}
1833 				printSendTargets(pList);
1834 			}
1835 
1836 			if (found) {
1837 				/* we found the discovery address - break */
1838 				break;
1839 			}
1840 		}
1841 		/*
1842 		 * There was an object entered but we didn't
1843 		 * find it.
1844 		 */
1845 		if (object && !found) {
1846 			(void) fprintf(stdout, "%s: %s\n",
1847 			    objects[i], gettext("not found"));
1848 		}
1849 	}
1850 	return (ret);
1851 }
1852 
1853 /*
1854  * Print ISNS Server addresses
1855  */
1856 static int
1857 listISNSServerAddress(int objectLen, char *objects[], cmdOptions_t *options,
1858     int *funcRet)
1859 {
1860 	IMA_OID	initiatorOid;
1861 	SUN_IMA_DISC_ADDR_PROP_LIST	    *discoveryAddressPropertiesList;
1862 	IMA_DISCOVERY_ADDRESS_PROPERTIES discAddrProps;
1863 	IMA_TARGET_ADDRESS address;
1864 	SUN_IMA_DISC_ADDRESS_KEY_PROPERTIES *pList;
1865 	IMA_STATUS status;
1866 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
1867 	int ret;
1868 	boolean_t object = B_FALSE;
1869 	int outerLoop;
1870 	boolean_t found;
1871 	boolean_t showTarget = B_FALSE;
1872 	int i, j;
1873 	cmdOptions_t *optionList = options;
1874 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
1875 
1876 	assert(funcRet != NULL);
1877 
1878 	/* Find Sun initiator */
1879 	ret = sunInitiatorFind(&initiatorOid);
1880 	if (ret > 0) {
1881 		(void) fprintf(stderr, "%s: %s\n",
1882 		    cmdName, gettext("no initiator found"));
1883 	}
1884 
1885 	if (ret != 0) {
1886 		return (ret);
1887 	}
1888 
1889 	for (; optionList->optval; optionList++) {
1890 		switch (optionList->optval) {
1891 			case 'v':
1892 				showTarget = B_TRUE;
1893 				break;
1894 			default:
1895 				(void) fprintf(stderr, "%s: %c: %s\n",
1896 				    cmdName, optionList->optval,
1897 				    gettext("unknown option"));
1898 				return (1);
1899 		}
1900 	}
1901 
1902 	/*
1903 	 * If there are multiple objects, execute outer 'for' loop that
1904 	 * many times for each target detail, otherwise, execute it only
1905 	 * once with summaries only
1906 	 */
1907 	if (objectLen > 0) {
1908 		object = B_TRUE;
1909 		outerLoop = objectLen;
1910 	} else {
1911 		object = B_FALSE;
1912 		outerLoop = 1;
1913 	}
1914 
1915 	status = SUN_IMA_GetISNSServerAddressPropertiesList(
1916 	    &discoveryAddressPropertiesList);
1917 	if (!IMA_SUCCESS(status)) {
1918 		printLibError(status);
1919 		*funcRet = 1;
1920 		return (ret);
1921 	}
1922 
1923 	for (i = 0; i < outerLoop; i++) {
1924 		if (object) {
1925 			/* initialize */
1926 			(void) memset(&wcInputObject[0], 0,
1927 			    sizeof (wcInputObject));
1928 			(void) memset(&address, 0, sizeof (address));
1929 			if (mbstowcs(wcInputObject, objects[i],
1930 			    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
1931 				(void) fprintf(stderr, "%s: %s\n",
1932 				    cmdName,
1933 				    gettext("conversion error"));
1934 				ret = 1;
1935 				continue;
1936 			}
1937 
1938 			/*
1939 			 * if one or more objects were input,
1940 			 * get the values
1941 			 */
1942 			if (getTargetAddress(ISNS_SERVER_ADDRESS,
1943 			    objects[i], &address) != 0) {
1944 				ret = 1;
1945 				continue;
1946 			}
1947 		}
1948 		for (found = B_FALSE, j = 0;
1949 		    j < discoveryAddressPropertiesList->discAddrCount;
1950 		    j++) {
1951 			discAddrProps =
1952 			    discoveryAddressPropertiesList->props[j];
1953 
1954 			/*
1955 			 * Compare the discovery address with the input if
1956 			 * one was input
1957 			 */
1958 			if (object &&
1959 			    ipAddressesEqual(discAddrProps.discoveryAddress,
1960 			    address) &&
1961 			    (discAddrProps.discoveryAddress.portNumber ==
1962 			    address.portNumber)) {
1963 				found = B_TRUE;
1964 			}
1965 
1966 			if (!object || found) {
1967 				/* Print summary - always */
1968 				if (discAddrProps.discoveryAddress.
1969 				    hostnameIpAddress.id.ipAddress.
1970 				    ipv4Address) {
1971 					(void) inet_ntop(AF_INET, discAddrProps.
1972 					    discoveryAddress.hostnameIpAddress.
1973 					    id.ipAddress.ipAddress, sAddr,
1974 					    sizeof (sAddr));
1975 				} else {
1976 					(void) inet_ntop(AF_INET6,
1977 					    discAddrProps.
1978 					    discoveryAddress.hostnameIpAddress.
1979 					    id.ipAddress.ipAddress, sAddr,
1980 					    sizeof (sAddr));
1981 				}
1982 				(void) fprintf(stdout,
1983 				    "iSNS Server IP Address: %s:%u\n",
1984 				    sAddr,
1985 				    discAddrProps.discoveryAddress.portNumber);
1986 			}
1987 
1988 			if ((!object || found) && showTarget) {
1989 				IMA_NODE_PROPERTIES nodeProps;
1990 
1991 				if (getNodeProps(&nodeProps) != 0) {
1992 					break;
1993 				}
1994 
1995 				/*
1996 				 * Issue sendTargets only when an addr is
1997 				 * specified.
1998 				 */
1999 				status = SUN_IMA_RetrieveISNSServerTargets(
2000 				    discAddrProps.discoveryAddress,
2001 				    &pList);
2002 				if (!IMA_SUCCESS(status)) {
2003 					/*
2004 					 * Check if the discovery mode is
2005 					 * disabled.
2006 					 */
2007 					if (status ==
2008 					    IMA_ERROR_OBJECT_NOT_FOUND) {
2009 						(void) fprintf(stderr, "%s\n",
2010 						    gettext("\tiSNS "\
2011 						    "discovery "\
2012 						    "mode "\
2013 						    "disabled. "\
2014 						    "No targets "\
2015 						    "to report."));
2016 
2017 					} else {
2018 						(void) fprintf(stderr, "%s\n",
2019 						    gettext("\tUnable "\
2020 						    "to get "\
2021 						    "targets."));
2022 					}
2023 					continue;
2024 				}
2025 				printSendTargets(pList);
2026 			}
2027 
2028 			if (found) {
2029 				/* we found the discovery address - break */
2030 				break;
2031 			}
2032 		}
2033 		/*
2034 		 * There was an object entered but we didn't
2035 		 * find it.
2036 		 */
2037 		if (object && !found) {
2038 			(void) fprintf(stdout, "%s: %s\n",
2039 			    objects[i], gettext("not found"));
2040 		}
2041 	}
2042 	return (ret);
2043 }
2044 
2045 /*
2046  * Print static configuration targets
2047  */
2048 static int
2049 listStaticConfig(int operandLen, char *operand[], int *funcRet)
2050 {
2051 	IMA_STATUS status;
2052 	IMA_OID	initiatorOid;
2053 	IMA_OID_LIST *staticTargetList;
2054 	SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps;
2055 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
2056 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2057 	wchar_t wcCol;
2058 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
2059 	int ret;
2060 	boolean_t object = B_FALSE;
2061 	int outerLoop;
2062 	boolean_t found; /* B_TRUE if a target name is found */
2063 	boolean_t matched; /* B_TRUE if a specific target is found */
2064 	boolean_t targetAddressSpecified = B_FALSE;
2065 	boolean_t tpgtSpecified = B_FALSE;
2066 	boolean_t isIpv6;
2067 	int i, j;
2068 	IMA_UINT16 port = 0;
2069 	IMA_UINT16 tpgt = 0;
2070 	char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
2071 	wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2072 
2073 	assert(funcRet != NULL);
2074 
2075 	/* Find Sun initiator */
2076 	ret = sunInitiatorFind(&initiatorOid);
2077 	if (ret > 0) {
2078 		(void) fprintf(stderr, "%s: %s\n",
2079 		    cmdName, gettext("no initiator found"));
2080 	}
2081 
2082 	if (ret != 0) {
2083 		return (ret);
2084 	}
2085 
2086 	/*
2087 	 * If there are multiple objects, execute outer 'for' loop that
2088 	 * many times for each static config detail, otherwise, execute it only
2089 	 * once with summaries only
2090 	 */
2091 	if (operandLen > 0) {
2092 		object = B_TRUE;
2093 		outerLoop = operandLen;
2094 	} else {
2095 		object = B_FALSE;
2096 		outerLoop = 1;
2097 	}
2098 
2099 	/* convert ':' to wide char for wchar string search */
2100 	if (mbtowc(&wcCol, ":", sizeof (wcCol)) == -1) {
2101 		(void) fprintf(stderr, "%s: %s\n",
2102 		    cmdName, gettext("conversion error"));
2103 		return (1);
2104 	}
2105 
2106 	status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid,
2107 	    &staticTargetList);
2108 	if (!IMA_SUCCESS(status)) {
2109 		printLibError(status);
2110 		*funcRet = 1;
2111 		return (ret);
2112 	}
2113 
2114 	for (i = 0; i < outerLoop; i++) {
2115 		if (object) {
2116 			if (parseTarget(operand[i],
2117 			    &staticTargetName[0],
2118 			    MAX_ISCSI_NAME_LEN + 1,
2119 			    &targetAddressSpecified,
2120 			    &staticTargetAddress[0],
2121 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2122 			    &port,
2123 			    &tpgtSpecified,
2124 			    &tpgt,
2125 			    &isIpv6) != PARSE_TARGET_OK) {
2126 				ret = 1;
2127 				continue;
2128 			}
2129 		}
2130 
2131 		for (found = B_FALSE, j = 0; j < staticTargetList->oidCount;
2132 		    j++) {
2133 			boolean_t isIpv6 = B_FALSE;
2134 			IMA_UINT16 stpgt;
2135 			IMA_BOOL defaultTpgt;
2136 
2137 			matched = B_FALSE;
2138 			(void) memset(&staticTargetProps, 0,
2139 			    sizeof (staticTargetProps));
2140 
2141 			status = SUN_IMA_GetStaticTargetProperties(
2142 			    staticTargetList->oids[j], &staticTargetProps);
2143 			if (!IMA_SUCCESS(status)) {
2144 				printLibError(status);
2145 				(void) IMA_FreeMemory(staticTargetList);
2146 				*funcRet = 1;
2147 				return (ret);
2148 			}
2149 
2150 			stpgt = staticTargetProps.staticTarget.targetAddress.
2151 			    tpgt;
2152 
2153 			defaultTpgt = staticTargetProps.staticTarget.
2154 			    targetAddress.defaultTpgt;
2155 
2156 			isIpv6 = !staticTargetProps.staticTarget.targetAddress.
2157 			    imaStruct.hostnameIpAddress.id.ipAddress.
2158 			    ipv4Address;
2159 
2160 			/*
2161 			 * Compare the static target name with the input if
2162 			 * one was input
2163 			 */
2164 
2165 			if (object &&
2166 			    (targetNamesEqual(
2167 			    staticTargetProps.staticTarget.targetName,
2168 			    staticTargetName) == B_TRUE)) {
2169 				/* targetName found - found = B_TRUE */
2170 				found = B_TRUE;
2171 				if (targetAddressSpecified == B_FALSE) {
2172 					matched = B_TRUE;
2173 				} else {
2174 
2175 				if (staticTargetProps.staticTarget.
2176 				    targetAddress.imaStruct.
2177 				    hostnameIpAddress.id.ipAddress.
2178 				    ipv4Address == IMA_TRUE) {
2179 					(void) inet_ntop(AF_INET,
2180 					    staticTargetProps.
2181 					    staticTarget.targetAddress.
2182 					    imaStruct.hostnameIpAddress.id.
2183 					    ipAddress.ipAddress, tmpStr,
2184 					    sizeof (tmpStr));
2185 				} else {
2186 					(void) inet_ntop(AF_INET6,
2187 					    staticTargetProps.
2188 					    staticTarget.targetAddress.
2189 					    imaStruct.hostnameIpAddress.id.
2190 					    ipAddress.ipAddress, tmpStr,
2191 					    sizeof (tmpStr));
2192 				}
2193 
2194 				if (mbstowcs(tmpTargetAddress, tmpStr,
2195 				    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
2196 				    (size_t)-1) {
2197 					(void) fprintf(stderr, "%s: %s\n",
2198 					    cmdName,
2199 					gettext("conversion error"));
2200 					ret = 1;
2201 					continue;
2202 				}
2203 
2204 				if (wcsncmp(tmpTargetAddress,
2205 				    staticTargetAddress,
2206 				    SUN_IMA_IP_ADDRESS_PORT_LEN)
2207 				    == 0 &&
2208 				    staticTargetProps.
2209 				    staticTarget.targetAddress.
2210 				    imaStruct.portNumber == port) {
2211 					/*
2212 					 * Since an object is
2213 					 * specified, it should also
2214 					 * have a tpgt specified. If
2215 					 * not, that means the object
2216 					 * specified is associated with
2217 					 * the default tpgt. In
2218 					 * either case, a tpgt
2219 					 * comparison should be done
2220 					 * before claiming that a
2221 					 * match is found.
2222 					 */
2223 					if ((tpgt == stpgt &&
2224 					    tpgtSpecified == B_TRUE &&
2225 					    defaultTpgt == IMA_FALSE) ||
2226 					    (tpgt == stpgt &&
2227 					    tpgtSpecified == B_FALSE &&
2228 					    defaultTpgt == IMA_TRUE)) {
2229 						matched = B_TRUE;
2230 					}
2231 				}
2232 
2233 				}
2234 			}
2235 
2236 			if (!object || matched) {
2237 				/* print summary - always */
2238 				(void) fprintf(stdout, gettext("%s: %ws,"),
2239 				    "Static Configuration Target",
2240 				    staticTargetProps.staticTarget.targetName);
2241 
2242 				if (isIpv6 == B_FALSE) {
2243 					(void) inet_ntop(AF_INET,
2244 					    staticTargetProps.
2245 					    staticTarget.targetAddress.
2246 					    imaStruct.hostnameIpAddress.id.
2247 					    ipAddress.ipAddress, sAddr,
2248 					    sizeof (sAddr));
2249 					(void) fprintf(stdout, "%s:%d",
2250 					    sAddr,
2251 					    staticTargetProps.staticTarget.
2252 					    targetAddress.imaStruct.portNumber);
2253 				} else {
2254 					(void) inet_ntop(AF_INET6,
2255 					    staticTargetProps.
2256 					    staticTarget.targetAddress.
2257 					    imaStruct.hostnameIpAddress.id.
2258 					    ipAddress.ipAddress, sAddr,
2259 					    sizeof (sAddr));
2260 					(void) fprintf(stdout, "[%s]:%d",
2261 					    sAddr,
2262 					    staticTargetProps.staticTarget.
2263 					    targetAddress.imaStruct.portNumber);
2264 				}
2265 
2266 				if (staticTargetProps.staticTarget.
2267 				    targetAddress.
2268 				    defaultTpgt == IMA_FALSE) {
2269 					(void) fprintf(stdout, ",%d\n",
2270 					    staticTargetProps.
2271 					    staticTarget.targetAddress.tpgt);
2272 				} else {
2273 					(void) fprintf(stdout, "\n");
2274 				}
2275 			}
2276 
2277 		}
2278 		/*
2279 		 * No details to display, but if there were:
2280 		 *  if (object && found)...
2281 		 *
2282 		 */
2283 
2284 		/*
2285 		 * There was an object entered but we didn't
2286 		 * find it.
2287 		 */
2288 		if (object && !found) {
2289 			(void) fprintf(stdout, "%s: %s\n",
2290 			    operand[i], gettext("not found"));
2291 			ret = 1; /* DIY test fix */
2292 		}
2293 	}
2294 	return (ret);
2295 }
2296 
2297 /*
2298  * Print targets
2299  */
2300 /*ARGSUSED*/
2301 static int
2302 listTarget(int objectLen, char *objects[], cmdOptions_t *options, int *funcRet)
2303 {
2304 	IMA_OID	initiatorOid;
2305 	IMA_OID_LIST *targetList;
2306 	IMA_OID_LIST *lunList;
2307 	SUN_IMA_TARGET_PROPERTIES targetProps;
2308 	IMA_STATUS status;
2309 	IMA_OID_LIST *pConnList;
2310 	SUN_IMA_CONN_PROPERTIES *connProps;
2311 
2312 	int ret;
2313 	wchar_t targetName[MAX_ISCSI_NAME_LEN + 1];
2314 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2315 	int outerLoop;
2316 	boolean_t found;
2317 	boolean_t operandEntered = B_FALSE;
2318 	boolean_t verbose = B_FALSE;
2319 	boolean_t scsi_target = B_FALSE;
2320 	boolean_t targetAddressSpecified = B_FALSE;
2321 	boolean_t isIpv6 = B_FALSE;
2322 	int i, j;
2323 	cmdOptions_t *optionList = options;
2324 	boolean_t tpgtSpecified = B_FALSE;
2325 	IMA_UINT16 port = 0;
2326 	uint16_t tpgt;
2327 
2328 	assert(funcRet != NULL);
2329 
2330 	/* Find Sun initiator */
2331 	ret = sunInitiatorFind(&initiatorOid);
2332 	if (ret > 0) {
2333 		(void) fprintf(stderr, "%s: %s\n",
2334 		    cmdName, gettext("no initiator found"));
2335 	}
2336 
2337 	if (ret != 0) {
2338 		return (ret);
2339 	}
2340 
2341 	for (; optionList->optval; optionList++) {
2342 		switch (optionList->optval) {
2343 			case 'S':
2344 				scsi_target = B_TRUE;
2345 				break;
2346 			case 'v':
2347 				verbose = B_TRUE;
2348 				break;
2349 			default:
2350 				(void) fprintf(stderr, "%s: %c: %s\n",
2351 				    cmdName, optionList->optval,
2352 				    gettext("unknown option"));
2353 				return (1);
2354 		}
2355 	}
2356 
2357 	/*
2358 	 * If there are multiple objects, execute outer 'for' loop that
2359 	 * many times for each target detail, otherwise, execute it only
2360 	 * once with summaries only
2361 	 */
2362 	if (objectLen > 0) {
2363 		operandEntered = B_TRUE;
2364 		outerLoop = objectLen;
2365 	} else {
2366 		operandEntered = B_FALSE;
2367 		outerLoop = 1;
2368 	}
2369 
2370 	status = SUN_IMA_GetSessionOidList(initiatorOid, &targetList);
2371 	if (!IMA_SUCCESS(status)) {
2372 		printLibError(status);
2373 		*funcRet = 1;
2374 		return (ret);
2375 	}
2376 
2377 	for (i = 0; i < outerLoop; i++) {
2378 
2379 		tpgtSpecified = B_FALSE;
2380 		if (operandEntered) {
2381 			if (parseTarget(objects[i],
2382 			    &targetName[0],
2383 			    MAX_ISCSI_NAME_LEN + 1,
2384 			    &targetAddressSpecified,
2385 			    &targetAddress[0],
2386 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2387 			    &port,
2388 			    &tpgtSpecified,
2389 			    &tpgt,
2390 			    &isIpv6) != PARSE_TARGET_OK) {
2391 				ret = 1;
2392 				continue;
2393 			}
2394 		}
2395 		for (found = B_FALSE, j = 0; j < targetList->oidCount; j++) {
2396 			status = SUN_IMA_GetTargetProperties(
2397 			    targetList->oids[j],
2398 			    &targetProps);
2399 			if (!IMA_SUCCESS(status)) {
2400 				printLibError(status);
2401 				(void) IMA_FreeMemory(targetList);
2402 				*funcRet = 1;
2403 				return (ret);
2404 			}
2405 
2406 			/*
2407 			 * Compare the target name with the input if
2408 			 * one was input, if they match, print the target's info
2409 			 *
2410 			 * if no target name was input, continue printing this
2411 			 * target
2412 			 */
2413 			if (operandEntered) {
2414 				if (targetNamesEqual(targetProps.imaProps.name,
2415 				    targetName) == B_TRUE) {
2416 					if (tpgtSpecified == B_TRUE) {
2417 						if (targetProps.
2418 						    defaultTpgtConf ==
2419 						    IMA_FALSE &&
2420 						    targetProps.
2421 						    tpgtConf == tpgt) {
2422 							found = B_TRUE;
2423 						} else {
2424 							/*
2425 							 * tpgt does not match,
2426 							 * move on to next
2427 							 * target
2428 							 */
2429 							continue;
2430 						}
2431 					} else {
2432 						found = B_TRUE;
2433 					}
2434 				} else {
2435 					/*
2436 					 * target name does not match, move on
2437 					 * to next target
2438 					 */
2439 					continue;
2440 				}
2441 			}
2442 
2443 			/* print summary - always */
2444 			(void) fprintf(stdout, gettext("%s: %ws\n"),
2445 			    gettext("Target"), targetProps.imaProps.name);
2446 
2447 			/* Alias */
2448 			(void) fprintf(stdout, "\t%s: ", gettext("Alias"));
2449 			if (wslen(targetProps.imaProps.alias) > (size_t)0) {
2450 				(void) fprintf(stdout, gettext("%ws\n"),
2451 				    targetProps.imaProps.alias);
2452 			} else {
2453 				(void) fprintf(stdout, "%s\n", "-");
2454 			}
2455 
2456 			if (targetProps.defaultTpgtNego != IMA_TRUE) {
2457 				(void) fprintf(stdout, "%s%s: %d\n",
2458 				    "\t", gettext("TPGT"),
2459 				    targetProps.tpgtNego);
2460 			} else if (targetProps.defaultTpgtConf != IMA_TRUE) {
2461 				(void) fprintf(stdout, "%s%s: %d\n",
2462 				    "\t", gettext("TPGT"),
2463 				    targetProps.tpgtConf);
2464 			}
2465 
2466 			(void) fprintf(stdout,
2467 			    "%s%s: %02x%02x%02x%02x%02x%02x\n",
2468 			    "\t", gettext("ISID"),
2469 			    targetProps.isid[0], targetProps.isid[1],
2470 			    targetProps.isid[2], targetProps.isid[3],
2471 			    targetProps.isid[4], targetProps.isid[5]);
2472 
2473 			pConnList = NULL;
2474 			status = SUN_IMA_GetConnOidList(
2475 			    &targetList->oids[j],
2476 			    &pConnList);
2477 
2478 			if (!IMA_SUCCESS(status)) {
2479 				printLibError(status);
2480 				(void) IMA_FreeMemory(targetList);
2481 				*funcRet = 1;
2482 				return (ret);
2483 			}
2484 
2485 			(void) fprintf(stdout, "%s%s: %lu\n",
2486 			    "\t",
2487 			    gettext("Connections"),
2488 			    pConnList->oidCount);
2489 
2490 			if (verbose) {
2491 				SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
2492 
2493 				printConnectionList("\t\t", pConnList);
2494 				printDiscoveryMethod(
2495 				    "\t\t  ",
2496 				    targetProps.imaProps.discoveryMethodFlags);
2497 				(void) printLoginParameters(
2498 				    "\t\t  ",
2499 				    targetList->oids[j],
2500 				    PRINT_NEGOTIATED_PARAMS);
2501 
2502 				/* Get Digest configuration */
2503 				status = SUN_IMA_GetConnProperties(
2504 				    &pConnList->oids[0], &connProps);
2505 
2506 				(void) getNegotiatedDigest(
2507 				    ISCSI_LOGIN_PARAM_HEADER_DIGEST,
2508 				    &digestAlgorithms, connProps);
2509 
2510 				if (IMA_SUCCESS(status)) {
2511 					(void) fprintf(stdout, "\t\t  \t%s: ",
2512 					    gettext("Header Digest"));
2513 					printDigestAlgorithm(
2514 					    &digestAlgorithms,
2515 					    PRINT_NEGOTIATED_PARAMS);
2516 				} else {
2517 					(void) IMA_FreeMemory(pConnList);
2518 					(void) IMA_FreeMemory(targetList);
2519 					printLibError(status);
2520 					*funcRet = 1;
2521 					return (ret);
2522 				}
2523 
2524 				(void) getNegotiatedDigest(
2525 				    ISCSI_LOGIN_PARAM_DATA_DIGEST,
2526 				    &digestAlgorithms, connProps);
2527 
2528 				if (IMA_SUCCESS(status)) {
2529 					(void) fprintf(stdout, "\t\t  \t%s: ",
2530 					    gettext("Data Digest"));
2531 					printDigestAlgorithm(
2532 					    &digestAlgorithms,
2533 					    PRINT_NEGOTIATED_PARAMS);
2534 				} else {
2535 					(void) IMA_FreeMemory(pConnList);
2536 					(void) IMA_FreeMemory(targetList);
2537 					printLibError(status);
2538 					*funcRet = 1;
2539 					return (ret);
2540 				}
2541 
2542 				(void) fprintf(stdout, "\n");
2543 			}
2544 
2545 			if (scsi_target) {
2546 				status = IMA_GetLuOidList(
2547 				    targetList->oids[j],
2548 				    &lunList);
2549 				if (!IMA_SUCCESS(status)) {
2550 					printLibError(status);
2551 					(void) IMA_FreeMemory(targetList);
2552 					*funcRet = 1;
2553 					return (ret);
2554 				}
2555 				if (lunList->oidCount != 0) {
2556 					printTargetLuns(lunList);
2557 				}
2558 				(void) fprintf(stdout, "\n");
2559 				(void) IMA_FreeMemory(lunList);
2560 			}
2561 		}
2562 		/*
2563 		 * did we find the object
2564 		 */
2565 
2566 		if (operandEntered && !found) {
2567 			(void) fprintf(stdout, "%s: %s\n",
2568 			    objects[i], gettext("not found"));
2569 		}
2570 	}
2571 
2572 	(void) IMA_FreeMemory(targetList);
2573 	return (ret);
2574 }
2575 
2576 
2577 /*
2578  * Print configured session information
2579  */
2580 static int
2581 printConfiguredSessions(IMA_OID oid)
2582 {
2583 	IMA_STATUS		status;
2584 	const char		*rtn;
2585 	SUN_IMA_CONFIG_SESSIONS	*pConfigSessions;
2586 	char			address[MAX_ADDRESS_LEN];
2587 	int			out;
2588 
2589 	/* Get configured session information */
2590 	status = SUN_IMA_GetConfigSessions(oid, &pConfigSessions);
2591 
2592 	if (IMA_SUCCESS(status)) {
2593 		(void) fprintf(stdout, "\t%s: ",
2594 		    gettext("Configured Sessions"));
2595 		if (pConfigSessions->bound == IMA_FALSE) {
2596 			/* default binding */
2597 			(void) fprintf(stdout, "%lu\n", pConfigSessions->out);
2598 		} else {
2599 			/* hardcoded binding */
2600 			for (out = 0;
2601 			    out < pConfigSessions->out; out++) {
2602 				if (pConfigSessions->bindings[out].
2603 				    ipAddress.ipv4Address == IMA_TRUE) {
2604 					rtn = inet_ntop(AF_INET,
2605 					    pConfigSessions->bindings[out].
2606 					    ipAddress.ipAddress, address,
2607 					    MAX_ADDRESS_LEN);
2608 				} else {
2609 					rtn = inet_ntop(AF_INET6,
2610 					    pConfigSessions->bindings[out].
2611 					    ipAddress.ipAddress, address,
2612 					    MAX_ADDRESS_LEN);
2613 				}
2614 				if (rtn != NULL) {
2615 					(void) printf("%s ", address);
2616 				}
2617 			}
2618 			(void) fprintf(stdout, "\n");
2619 		}
2620 	} else {
2621 		free(pConfigSessions);
2622 		printLibError(status);
2623 		return (1);
2624 	}
2625 
2626 	free(pConfigSessions);
2627 	return (0);
2628 }
2629 
2630 /*
2631  * Print target parameters
2632  */
2633 static int
2634 listTargetParam(int operandLen, char *operand[], cmdOptions_t *options,
2635     int *funcRet)
2636 {
2637 	IMA_STATUS status;
2638 	IMA_OID	initiatorOid;
2639 	IMA_OID_LIST *targetList;
2640 	IMA_AUTHMETHOD	methodList[MAX_AUTH_METHODS];
2641 	SUN_IMA_TARGET_PROPERTIES targetProps;
2642 	IMA_UINT maxEntries = MAX_AUTH_METHODS;
2643 	IMA_BOOL bidirAuth;
2644 	int ret;
2645 	wchar_t targetName[MAX_ISCSI_NAME_LEN + 1];
2646 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
2647 	boolean_t operandEntered = B_FALSE;
2648 	boolean_t targetAddressSpecified = B_FALSE;
2649 	boolean_t printObject = B_FALSE;
2650 	boolean_t tpgtSpecified = B_FALSE;
2651 	boolean_t isIpv6 = B_FALSE;
2652 	int outerLoop;
2653 	boolean_t found;
2654 	int i, j;
2655 	SUN_IMA_DIGEST_ALGORITHM_VALUE digestAlgorithms;
2656 	boolean_t verbose = B_FALSE;
2657 	cmdOptions_t *optionList = options;
2658 	IMA_UINT16 port = 0;
2659 	IMA_UINT16 tpgt = 0;
2660 
2661 	assert(funcRet != NULL);
2662 
2663 	/* Find Sun initiator */
2664 	ret = sunInitiatorFind(&initiatorOid);
2665 	if (ret > 0) {
2666 		(void) fprintf(stderr, "%s: %s\n",
2667 		    cmdName, gettext("no initiator found"));
2668 	}
2669 
2670 	if (ret != 0) {
2671 		return (ret);
2672 	}
2673 
2674 	for (; optionList->optval; optionList++) {
2675 		switch (optionList->optval) {
2676 			case 'v':
2677 				verbose = B_TRUE;
2678 				break;
2679 			default:
2680 				(void) fprintf(stderr, "%s: %c: %s\n",
2681 				    cmdName, optionList->optval,
2682 				    gettext("unknown option"));
2683 				return (1);
2684 		}
2685 	}
2686 
2687 	/*
2688 	 * If there are multiple operands, execute outer 'for' loop that
2689 	 * many times to find each target parameter operand entered, otherwise,
2690 	 * execute it only once for all target parameters returned.
2691 	 */
2692 	if (operandLen > 0) {
2693 		operandEntered = B_TRUE;
2694 		outerLoop = operandLen;
2695 	} else {
2696 		operandEntered = B_FALSE;
2697 		outerLoop = 1;
2698 	}
2699 
2700 	/*
2701 	 * Ideally there should be an interface available for obtaining
2702 	 * the list of target-param objects. Since the driver currently
2703 	 * creates a target OID and the associated session structure when
2704 	 * a target-param object is created, we can leverage the target
2705 	 * OID list and use it to manage the target-param objects. When
2706 	 * we stop creating a session for target-param object in the
2707 	 * driver, we will switch to using a different interface to
2708 	 * obtain target-param objects.
2709 	 */
2710 	status = IMA_GetTargetOidList(initiatorOid, &targetList);
2711 	if (!IMA_SUCCESS(status)) {
2712 		printLibError(status);
2713 		*funcRet = 1;
2714 		return (ret);
2715 	}
2716 
2717 	for (i = 0; i < outerLoop; i++) {
2718 		if (operandEntered) {
2719 			if (parseTarget(operand[i],
2720 			    &targetName[0],
2721 			    MAX_ISCSI_NAME_LEN + 1,
2722 			    &targetAddressSpecified,
2723 			    &targetAddress[0],
2724 			    SUN_IMA_IP_ADDRESS_PORT_LEN,
2725 			    &port,
2726 			    &tpgtSpecified,
2727 			    &tpgt,
2728 			    &isIpv6) != PARSE_TARGET_OK) {
2729 				ret = 1;
2730 				continue;
2731 			}
2732 		}
2733 		for (j = 0; j < targetList->oidCount; j++) {
2734 			found = B_FALSE;
2735 			printObject = B_FALSE;
2736 			status = SUN_IMA_GetTargetProperties(
2737 			    targetList->oids[j],
2738 			    &targetProps);
2739 			if (!IMA_SUCCESS(status)) {
2740 				printLibError(status);
2741 				(void) IMA_FreeMemory(targetList);
2742 				*funcRet = 1;
2743 				return (ret);
2744 			}
2745 
2746 			/*
2747 			 * Compare the target name with the input if
2748 			 * one was input
2749 			 */
2750 			if (operandEntered &&
2751 			    (targetNamesEqual(targetProps.imaProps.name,
2752 			    targetName) == B_TRUE)) {
2753 				/*
2754 				 * For now, regardless of whether a target
2755 				 * address is specified, we return B_TRUE
2756 				 * because IMA_TARGET_PROPERTIES does not
2757 				 * have a field for specifying address.
2758 				 */
2759 				found = B_TRUE;
2760 			}
2761 
2762 			/*
2763 			 * if no operand was entered OR
2764 			 * an operand was entered and it was
2765 			 * found, we want to print
2766 			 */
2767 			if (!operandEntered || found) {
2768 				printObject = B_TRUE;
2769 			}
2770 
2771 			if (printObject) {
2772 				(void) fprintf(stdout, gettext("%s: %ws\n"),
2773 				    gettext("Target"),
2774 				    targetProps.imaProps.name);
2775 
2776 				(void) fprintf(stdout,
2777 				    "\t%s: ", gettext("Alias"));
2778 				if (wslen(targetProps.imaProps.alias) >
2779 				    (size_t)0) {
2780 					(void) fprintf(stdout,
2781 					    gettext("%ws\n"),
2782 					    targetProps.imaProps.alias);
2783 				} else {
2784 					(void) fprintf(stdout, "%s\n", "-");
2785 				}
2786 			}
2787 
2788 			if (printObject && verbose) {
2789 				/* Get bidirectional authentication flag */
2790 				(void) fprintf(stdout, "\t%s: ",
2791 				    gettext("Bi-directional Authentication"));
2792 				status = SUN_IMA_GetTargetBidirAuthFlag(
2793 				    targetList->oids[j],
2794 				    &bidirAuth);
2795 				if (IMA_SUCCESS(status)) {
2796 					if (bidirAuth == IMA_TRUE) {
2797 						(void) fprintf(stdout,
2798 						    gettext("enabled"));
2799 					} else {
2800 						(void) fprintf(stdout,
2801 						    gettext("disabled"));
2802 					}
2803 				} else {
2804 					(void) fprintf(stdout,
2805 					    gettext("disabled"));
2806 				}
2807 				(void) fprintf(stdout, "\n");
2808 
2809 				/* Get authentication type for this target */
2810 				status = SUN_IMA_GetTargetAuthMethods(
2811 				    initiatorOid,
2812 				    targetList->oids[j],
2813 				    &maxEntries,
2814 				    &methodList[0]);
2815 				(void) fprintf(stdout, "\t%s: ",
2816 				    gettext("Authentication Type"));
2817 				if (!IMA_SUCCESS(status)) {
2818 					/*
2819 					 * No authentication method define
2820 					 * NONE by default.
2821 					 */
2822 					(void) fprintf(stdout, gettext("NONE"));
2823 				} else {
2824 					for (i = 0; i < maxEntries; i++) {
2825 						if (i > 0) {
2826 							(void) fprintf(stdout,
2827 							    "|");
2828 						}
2829 						switch (methodList[i]) {
2830 						case IMA_AUTHMETHOD_NONE:
2831 							(void) fprintf(stdout,
2832 							    gettext("NONE"));
2833 							break;
2834 
2835 						case IMA_AUTHMETHOD_CHAP:
2836 							(void) fprintf(stdout,
2837 							    gettext("CHAP"));
2838 							listCHAPName(
2839 							    targetList->
2840 							    oids[j]);
2841 							break;
2842 
2843 						default:
2844 							(void) fprintf(stdout,
2845 							    gettext(
2846 							    "unknown "
2847 							    "type"));
2848 							break;
2849 						}
2850 					}
2851 				}
2852 				(void) fprintf(stdout, "\n");
2853 				if (printLoginParameters("\t",
2854 				    targetList->oids[j],
2855 				    PRINT_CONFIGURED_PARAMS)
2856 				    != 0) {
2857 					(void) IMA_FreeMemory(targetList);
2858 					*funcRet = 1;
2859 					return (ret);
2860 				}
2861 
2862 				/* Get Digest configuration */
2863 				status = SUN_IMA_GetHeaderDigest(
2864 				    targetList->oids[j],
2865 				    &digestAlgorithms);
2866 				if (IMA_SUCCESS(status)) {
2867 					(void) fprintf(stdout, "\t\t%s: ",
2868 					    gettext("Header Digest"));
2869 					printDigestAlgorithm(&digestAlgorithms,
2870 					    PRINT_CONFIGURED_PARAMS);
2871 				} else {
2872 					printLibError(status);
2873 					*funcRet = 1;
2874 					return (ret);
2875 				}
2876 
2877 				status = SUN_IMA_GetDataDigest(
2878 				    targetList->oids[j],
2879 				    &digestAlgorithms);
2880 				if (IMA_SUCCESS(status)) {
2881 					(void) fprintf(stdout, "\t\t%s: ",
2882 					    gettext("Data Digest"));
2883 					printDigestAlgorithm(&digestAlgorithms,
2884 					    PRINT_CONFIGURED_PARAMS);
2885 				} else {
2886 					printLibError(status);
2887 					*funcRet = 1;
2888 					return (ret);
2889 				}
2890 
2891 				/* print configured session information */
2892 				if (printConfiguredSessions(
2893 				    targetList->oids[j]) != 0) {
2894 					*funcRet = 1;
2895 					return (ret);
2896 				}
2897 
2898 				(void) fprintf(stdout, "\n");
2899 			}
2900 
2901 			if (found) {
2902 				break;
2903 			}
2904 		}
2905 		if (operandEntered && !found) {
2906 			*funcRet = 1; /* DIY message fix */
2907 			(void) fprintf(stdout, "%s: %s\n",
2908 			    operand[i], gettext("not found"));
2909 		}
2910 	}
2911 
2912 	(void) IMA_FreeMemory(targetList);
2913 	return (ret);
2914 }
2915 
2916 /*
2917  * Modify discovery attributes
2918  */
2919 static int
2920 modifyDiscovery(cmdOptions_t *options, int *funcRet)
2921 {
2922 	IMA_OID oid;
2923 	IMA_STATUS status;
2924 	IMA_BOOL setDiscovery;
2925 	IMA_HOST_ID hostId;
2926 
2927 	int ret;
2928 	cmdOptions_t *optionList = options;
2929 
2930 	assert(funcRet != NULL);
2931 
2932 	/* Find Sun initiator */
2933 	ret = sunInitiatorFind(&oid);
2934 	if (ret > 0) {
2935 		(void) fprintf(stderr, "%s: %s\n",
2936 		    cmdName, gettext("no initiator found"));
2937 	}
2938 
2939 	if (ret != 0) {
2940 		return (ret);
2941 	}
2942 
2943 	for (; optionList->optval; optionList++) {
2944 		/* check optarg and set bool accordingly */
2945 		if (strcasecmp(optionList->optarg, ISCSIADM_ARG_ENABLE) == 0) {
2946 			setDiscovery = IMA_TRUE;
2947 		} else if (strcasecmp(optionList->optarg, ISCSIADM_ARG_DISABLE)
2948 		    == 0) {
2949 			setDiscovery = IMA_FALSE;
2950 		} else {
2951 			(void) fprintf(stderr, "%s: %s\n",
2952 			    cmdName, gettext("invalid option argument"));
2953 			return (1);
2954 		}
2955 
2956 		switch (optionList->optval) {
2957 			case 's':
2958 				/* Set static discovery */
2959 				status = IMA_SetStaticDiscovery(oid,
2960 				    setDiscovery);
2961 				if (!IMA_SUCCESS(status)) {
2962 					printLibError(status);
2963 					*funcRet = 1;
2964 					return (ret);
2965 				}
2966 				break;
2967 			case 't':
2968 				/* Set send targets discovery */
2969 				status = IMA_SetSendTargetsDiscovery(oid,
2970 				    setDiscovery);
2971 				if (!IMA_SUCCESS(status)) {
2972 					printLibError(status);
2973 					*funcRet = 1;
2974 					return (ret);
2975 				}
2976 				break;
2977 			case 'i':
2978 				/* Set iSNS discovery */
2979 				(void) memset(&hostId, 0, sizeof (hostId));
2980 				status = IMA_SetIsnsDiscovery(oid, setDiscovery,
2981 				    IMA_ISNS_DISCOVERY_METHOD_STATIC, &hostId);
2982 				if (!IMA_SUCCESS(status)) {
2983 					printLibError(status);
2984 					*funcRet = 1;
2985 					return (ret);
2986 				}
2987 				break;
2988 			default:
2989 				(void) fprintf(stderr, "%s: %c: %s\n",
2990 				    cmdName, optionList->optval,
2991 				    gettext("unknown option"));
2992 				return (1);
2993 		}
2994 	}
2995 
2996 	return (ret);
2997 }
2998 
2999 /*
3000  * Set the initiator node's authentication method
3001  */
3002 static int
3003 modifyNodeAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet)
3004 {
3005 	IMA_INITIATOR_AUTHPARMS authParams;
3006 	IMA_STATUS status;
3007 	int ret;
3008 	int secretLen = MAX_CHAP_SECRET_LEN;
3009 
3010 	IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1];
3011 
3012 	assert(funcRet != NULL);
3013 
3014 	/*
3015 	 * Start with existing parameters and modify with the desired change
3016 	 * before passing along.  We ignore any failures as they probably
3017 	 * are caused by non-existence of auth params for the given node.
3018 	 */
3019 	status = IMA_GetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3020 	    &authParams);
3021 
3022 	switch (param) {
3023 	case AUTH_NAME:
3024 		if (chapName == NULL) {
3025 			(void) fprintf(stderr, "CHAP name cannot be NULL.\n");
3026 			return (1);
3027 		}
3028 		(void) memset(&authParams.chapParms.name, 0,
3029 		    sizeof (authParams.chapParms.name));
3030 		(void) memcpy(&authParams.chapParms.name,
3031 		    &chapName[0], strlen(chapName));
3032 		authParams.chapParms.nameLength = strlen(chapName);
3033 		break;
3034 
3035 	case AUTH_PASSWORD :
3036 		ret = getSecret((char *)&chapSecret[0], &secretLen,
3037 		    MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN);
3038 
3039 		if (ret != 0) {
3040 			return (ret);
3041 		}
3042 
3043 		(void) memset(&authParams.chapParms.challengeSecret, 0,
3044 		    sizeof (authParams.chapParms.challengeSecret));
3045 		(void) memcpy(&authParams.chapParms.challengeSecret,
3046 		    &chapSecret[0], secretLen);
3047 		authParams.chapParms.challengeSecretLength = secretLen;
3048 		break;
3049 
3050 	default:
3051 		(void) fprintf(stderr, "Invalid auth parameter %d\n", param);
3052 		return (1);
3053 	}
3054 
3055 	status = IMA_SetInitiatorAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3056 	    &authParams);
3057 	if (!IMA_SUCCESS(status)) {
3058 		printLibError(status);
3059 		*funcRet = 1;
3060 	}
3061 	return (ret);
3062 }
3063 
3064 /*
3065  * Set the target's authentication method
3066  */
3067 static int
3068 modifyTargetAuthParam(IMA_OID oid, int param, char *chapName, int *funcRet)
3069 {
3070 	IMA_INITIATOR_AUTHPARMS authParams;
3071 	IMA_STATUS status;
3072 	int ret;
3073 	int secretLen = MAX_CHAP_SECRET_LEN;
3074 
3075 	IMA_BYTE chapSecret[MAX_CHAP_SECRET_LEN + 1];
3076 
3077 	assert(funcRet != NULL);
3078 
3079 	/*
3080 	 * Start with existing parameters and modify with the desired change
3081 	 * before passing along.  We ignore any get failures as they probably
3082 	 * are caused by non-existence of auth params for the given target.
3083 	 */
3084 	status = SUN_IMA_GetTargetAuthParms(oid, IMA_AUTHMETHOD_CHAP,
3085 	    &authParams);
3086 
3087 	switch (param) {
3088 	case AUTH_NAME:
3089 		if (chapName == NULL) {
3090 			(void) fprintf(stderr, "CHAP name cannot be NULL.\n");
3091 			return (1);
3092 		}
3093 		(void) memset(&authParams.chapParms.name, 0,
3094 		    sizeof (authParams.chapParms.name));
3095 		(void) memcpy(&authParams.chapParms.name,
3096 		    &chapName[0], strlen(chapName));
3097 		authParams.chapParms.nameLength = strlen(chapName);
3098 		break;
3099 
3100 	case AUTH_PASSWORD :
3101 		ret = getSecret((char *)&chapSecret[0], &secretLen,
3102 		    1, MAX_CHAP_SECRET_LEN);
3103 
3104 		if (ret != 0) {
3105 			return (ret);
3106 		}
3107 
3108 		(void) memset(&authParams.chapParms.challengeSecret, 0,
3109 		    sizeof (authParams.chapParms.challengeSecret));
3110 		(void) memcpy(&authParams.chapParms.challengeSecret,
3111 		    &chapSecret[0], secretLen);
3112 		authParams.chapParms.challengeSecretLength = secretLen;
3113 		break;
3114 
3115 	default:
3116 		(void) fprintf(stderr, "Invalid auth parameter %d\n", param);
3117 		return (1);
3118 	}
3119 
3120 	status = SUN_IMA_SetTargetAuthParams(oid, IMA_AUTHMETHOD_CHAP,
3121 	    &authParams);
3122 	if (!IMA_SUCCESS(status)) {
3123 		printLibError(status);
3124 		*funcRet = 1;
3125 	}
3126 	return (0);
3127 }
3128 
3129 static int
3130 modifyTargetBidirAuthFlag(IMA_OID targetOid, char *optarg, int *funcRet)
3131 {
3132 	IMA_BOOL boolValue;
3133 	IMA_STATUS status;
3134 
3135 	assert(funcRet != NULL);
3136 
3137 	if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) {
3138 		boolValue = IMA_TRUE;
3139 	} else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) {
3140 		boolValue = IMA_FALSE;
3141 	} else {
3142 		(void) fprintf(stderr, "%s: %s %s\n",
3143 		    cmdName, gettext("invalid option argument"), optarg);
3144 		return (1);
3145 	}
3146 
3147 	status = SUN_IMA_SetTargetBidirAuthFlag(targetOid, &boolValue);
3148 	if (!IMA_SUCCESS(status)) {
3149 		printLibError(status);
3150 		*funcRet = 1;
3151 	}
3152 	return (0);
3153 }
3154 
3155 static int
3156 modifyConfiguredSessions(IMA_OID targetOid, char *optarg)
3157 {
3158 	SUN_IMA_CONFIG_SESSIONS *pConfigSessions;
3159 	IMA_STATUS		status;
3160 	int			sessions;
3161 	int			size;
3162 	char			tmp[1024];
3163 	boolean_t		isIpv6 = B_FALSE;
3164 	uint16_t		port;
3165 	char			address[MAX_ADDRESS_LEN];
3166 	char			*commaPos;
3167 	char			*addressPos;
3168 	int			rtn;
3169 
3170 	/*
3171 	 * Strip the first int value from the string.  If we sprintf
3172 	 * this back to a string and it matches the original string
3173 	 * then this command is using default binding.  If not a
3174 	 * match we have hard coded binding or a usage error.
3175 	 */
3176 	sessions = atoi(optarg);
3177 	(void) sprintf(tmp, "%d", sessions);
3178 	if (strcmp(optarg, tmp) == 0) {
3179 		/* default binding */
3180 
3181 		/* allocate the required pConfigSessions */
3182 		size = sizeof (SUN_IMA_CONFIG_SESSIONS);
3183 		pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
3184 		if (pConfigSessions == NULL) {
3185 			return (1);
3186 		}
3187 
3188 		/* setup pConfigSessions */
3189 		pConfigSessions->bound	= IMA_FALSE;
3190 		pConfigSessions->in	= sessions;
3191 		pConfigSessions->out	= 0;
3192 	} else {
3193 		/* hardcoded binding */
3194 
3195 		/*
3196 		 * First we need to determine how many bindings
3197 		 * are available.  This can be done by scanning
3198 		 * for the number of ',' + 1.
3199 		 */
3200 		sessions = 1;
3201 		commaPos = strchr(optarg, ',');
3202 		while (commaPos != NULL) {
3203 			sessions++;
3204 			commaPos = strchr(++commaPos, ',');
3205 		}
3206 
3207 		/* allocate the required pConfigSessions */
3208 		size = sizeof (SUN_IMA_CONFIG_SESSIONS) + ((sessions - 1) *
3209 		    sizeof (IMA_ADDRESS_KEY));
3210 		pConfigSessions = (SUN_IMA_CONFIG_SESSIONS *)calloc(1, size);
3211 		if (pConfigSessions == NULL) {
3212 			return (1);
3213 		}
3214 
3215 		/* setup pConfigSessions */
3216 		pConfigSessions->bound	= IMA_TRUE;
3217 		pConfigSessions->in	= sessions;
3218 		pConfigSessions->out	= 0;
3219 
3220 		/* Now fill in the binding information.  */
3221 		sessions = 0;
3222 		addressPos = optarg;
3223 		/*
3224 		 * Walk thru possible address strings
3225 		 * stop once all strings are processed.
3226 		 */
3227 		while (addressPos != NULL) {
3228 			/*
3229 			 * Check if there is another address after this
3230 			 * one. If so terminate the current address and
3231 			 * keep a pointer to the next one.
3232 			 */
3233 			commaPos = strchr(addressPos, ',');
3234 			if (commaPos != NULL) {
3235 				*commaPos++ = 0x00;
3236 			}
3237 
3238 			/*
3239 			 * Parse current address.  If invalid abort
3240 			 * processing of addresses and free memory.
3241 			 */
3242 			if (parseAddress(addressPos, 0, address,
3243 			    MAX_ADDRESS_LEN, &port, &isIpv6) != PARSE_ADDR_OK) {
3244 				free(pConfigSessions);
3245 				printLibError(IMA_ERROR_INVALID_PARAMETER);
3246 				return (1);
3247 			}
3248 
3249 			/* Convert address into binary form */
3250 			if (isIpv6 == B_FALSE) {
3251 				pConfigSessions->bindings[sessions].
3252 				    ipAddress.ipv4Address = IMA_TRUE;
3253 				rtn = inet_pton(AF_INET, address,
3254 				    pConfigSessions->bindings[sessions].
3255 				    ipAddress.ipAddress);
3256 			} else {
3257 				pConfigSessions->bindings[sessions].ipAddress.
3258 				    ipv4Address =
3259 				    IMA_FALSE;
3260 				rtn = inet_pton(AF_INET6, address,
3261 				    pConfigSessions->bindings[sessions].
3262 				    ipAddress.ipAddress);
3263 			}
3264 			if (rtn == 0) {
3265 				/* inet_pton found address invalid */
3266 				free(pConfigSessions);
3267 				printLibError(IMA_ERROR_INVALID_PARAMETER);
3268 				return (1);
3269 			}
3270 
3271 			/* update addressPos to next address */
3272 			sessions++;
3273 			addressPos = commaPos;
3274 		}
3275 	}
3276 
3277 	/* issue SUN_IMA request */
3278 	status = SUN_IMA_SetConfigSessions(targetOid,
3279 	    pConfigSessions);
3280 	if (!IMA_SUCCESS(status)) {
3281 		printLibError(status);
3282 		free(pConfigSessions);
3283 		return (1);
3284 	}
3285 
3286 	free(pConfigSessions);
3287 	return (0);
3288 }
3289 
3290 static int
3291 getAuthMethodValue(char *method, IMA_AUTHMETHOD *value)
3292 {
3293 	if (strcasecmp(method, "chap") == 0) {
3294 		*value = IMA_AUTHMETHOD_CHAP;
3295 		return (0);
3296 	}
3297 
3298 	if (strcasecmp(method, "none") == 0) {
3299 		*value =  IMA_AUTHMETHOD_NONE;
3300 		return (0);
3301 	}
3302 
3303 	return (1);
3304 }
3305 
3306 
3307 /*
3308  * Set the authentication method
3309  * Currently only supports CHAP and NONE
3310  */
3311 static int
3312 modifyNodeAuthMethod(IMA_OID oid, char *optarg, int *funcRet)
3313 {
3314 	IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS];
3315 	IMA_UINT methodCount = 0;
3316 	IMA_STATUS status;
3317 	IMA_AUTHMETHOD value;
3318 	char *method;
3319 	char *commaPos;
3320 
3321 	assert(funcRet != NULL);
3322 
3323 	/*
3324 	 * optarg will be a , delimited set of auth methods, in order
3325 	 * of preference
3326 	 * if any values here are incorrect, return without setting
3327 	 * anything.
3328 	 */
3329 	method = optarg;
3330 
3331 	commaPos = strchr(optarg, ',');
3332 
3333 	while (commaPos && methodCount < MAX_AUTH_METHODS) {
3334 		*commaPos = NULL;
3335 		if (getAuthMethodValue(method, &value) != 0) {
3336 			(void) fprintf(stderr, "%s: a: %s\n",
3337 			    cmdName, gettext("invalid option argument"));
3338 			return (1);
3339 		}
3340 		methodList[methodCount++] = value;
3341 		commaPos++;
3342 		method = commaPos;
3343 		commaPos = strchr(method, ',');
3344 	}
3345 	/* Should not find more method specified - if found, error */
3346 	if (commaPos) {
3347 		(void) fprintf(stderr, "%s: -a: %s\n",
3348 		    cmdName, gettext("invalid option argument"));
3349 		return (1);
3350 	}
3351 	if (getAuthMethodValue(method, &value) != 0) {
3352 		(void) fprintf(stderr, "%s: -a: %s\n",
3353 		    cmdName, gettext("invalid option argument"));
3354 		return (1);
3355 	}
3356 	methodList[methodCount++] = value;
3357 
3358 	status = IMA_SetInitiatorAuthMethods(oid, methodCount, &methodList[0]);
3359 	if (!IMA_SUCCESS(status)) {
3360 		printLibError(status);
3361 		*funcRet = 1;
3362 	}
3363 	return (0);
3364 }
3365 
3366 static int
3367 modifyTargetAuthMethod(IMA_OID oid, char *optarg, int *funcRet)
3368 {
3369 	IMA_AUTHMETHOD methodList[MAX_AUTH_METHODS];
3370 	IMA_UINT methodCount = 0;
3371 	IMA_STATUS status;
3372 	IMA_AUTHMETHOD value;
3373 	char *method;
3374 	char *commaPos;
3375 
3376 	assert(funcRet != NULL);
3377 
3378 	/*
3379 	 * optarg will be a , delimited set of auth methods, in order
3380 	 * of preference
3381 	 * if any values here are incorrect, return without setting
3382 	 * anything.
3383 	 */
3384 	method = optarg;
3385 
3386 	commaPos = strchr(optarg, ',');
3387 
3388 	while (commaPos && methodCount < MAX_AUTH_METHODS) {
3389 		*commaPos = NULL;
3390 		if (getAuthMethodValue(method, &value) != 0) {
3391 			(void) fprintf(stderr, "%s: a: %s\n",
3392 			    cmdName, gettext("invalid option argument"));
3393 			return (1);
3394 		}
3395 		methodList[methodCount++] = value;
3396 		commaPos++;
3397 		method = commaPos;
3398 		commaPos = strchr(method, ',');
3399 	}
3400 	/* Should not find more method specified - if found, error */
3401 	if (commaPos) {
3402 		(void) fprintf(stderr, "%s: -a: %s\n",
3403 		    cmdName, gettext("invalid option argument"));
3404 		return (1);
3405 	}
3406 	if (getAuthMethodValue(method, &value) != 0) {
3407 		(void) fprintf(stderr, "%s: -a: %s\n",
3408 		    cmdName, gettext("invalid option argument"));
3409 		return (1);
3410 	}
3411 	methodList[methodCount++] = value;
3412 
3413 	status = SUN_IMA_SetTargetAuthMethods(oid, &methodCount,
3414 	    &methodList[0]);
3415 	if (!IMA_SUCCESS(status)) {
3416 		printLibError(status);
3417 		*funcRet = 1;
3418 	}
3419 	return (0);
3420 }
3421 
3422 /*
3423  * Modify the RADIUS configuration of the initiator node.
3424  *
3425  * Return 0 on success.
3426  */
3427 static int
3428 modifyNodeRadiusConfig(IMA_OID oid, char *optarg, int *funcRet)
3429 {
3430 	SUN_IMA_RADIUS_CONFIG config;
3431 	IMA_STATUS status;
3432 	boolean_t isIpv6 = B_FALSE;
3433 	uint16_t port;
3434 
3435 	assert(funcRet != NULL);
3436 
3437 	(void) memset(&config, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3438 	if (parseAddress(optarg, DEFAULT_RADIUS_PORT,
3439 	    &config.hostnameIpAddress[0], SUN_IMA_IP_ADDRESS_PORT_LEN,
3440 	    &port, &isIpv6) !=
3441 	    PARSE_ADDR_OK) {
3442 		return (1);
3443 	}
3444 	config.port = (IMA_UINT16)port;
3445 	config.isIpv6 = (isIpv6 == B_TRUE) ? IMA_TRUE : IMA_FALSE;
3446 	/* Not setting shared secret here. */
3447 	config.sharedSecretValid = IMA_FALSE;
3448 
3449 	status = SUN_IMA_SetInitiatorRadiusConfig(oid, &config);
3450 	if (!IMA_SUCCESS(status)) {
3451 		printLibError(status);
3452 		*funcRet = 1;
3453 	}
3454 
3455 	return (0);
3456 }
3457 
3458 /*
3459  * Modify the RADIUS access flag of the initiator node.
3460  *
3461  * Return 0 on success.
3462  */
3463 static int
3464 modifyNodeRadiusAccess(IMA_OID oid, char *optarg, int *funcRet)
3465 {
3466 	IMA_BOOL radiusAccess;
3467 	IMA_OID initiatorOid;
3468 	IMA_STATUS status;
3469 	SUN_IMA_RADIUS_CONFIG radiusConfig;
3470 	int ret;
3471 
3472 	assert(funcRet != NULL);
3473 
3474 	/* Check if Radius Config is there */
3475 	ret = sunInitiatorFind(&initiatorOid);
3476 	if (ret != 0) {
3477 		(void) fprintf(stderr, "%s: %s\n",
3478 		    cmdName, gettext("no initiator found"));
3479 		return (1);
3480 	}
3481 	(void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3482 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
3483 	if (!IMA_SUCCESS(status)) {
3484 		(void) fprintf(stderr, "%s: %s\n",
3485 		    cmdName, gettext("RADIUS server not configured yet"));
3486 		*funcRet = 1;
3487 		return (ret);
3488 	}
3489 
3490 	/* Check if Radius Shared is set */
3491 	if (radiusConfig.sharedSecretValid == IMA_FALSE) {
3492 		(void) fprintf(stderr, "%s: %s\n", cmdName,
3493 		    gettext("RADIUS server secret not configured yet"));
3494 		return (1);
3495 	}
3496 
3497 	if (strcasecmp(optarg, ISCSIADM_ARG_ENABLE) == 0) {
3498 		radiusAccess = IMA_TRUE;
3499 	} else if (strcasecmp(optarg, ISCSIADM_ARG_DISABLE) == 0) {
3500 		radiusAccess = IMA_FALSE;
3501 	} else {
3502 		(void) fprintf(stderr, "%s: %s %s\n",
3503 		    cmdName,
3504 		    gettext("invalid option argument"),
3505 		    optarg);
3506 		return (1);
3507 	}
3508 	status = SUN_IMA_SetInitiatorRadiusAccess(oid, radiusAccess);
3509 	if (!IMA_SUCCESS(status)) {
3510 		printLibError(status);
3511 		*funcRet = 1;
3512 	}
3513 
3514 	return (ret);
3515 }
3516 
3517 /*
3518  * Modify the RADIUS shared secret.
3519  *
3520  * Returns:
3521  *  zero on success.
3522  *  > 0 on failure.
3523  */
3524 static int
3525 modifyNodeRadiusSharedSecret(IMA_OID oid, int *funcRet)
3526 {
3527 	IMA_BYTE radiusSharedSecret[SUN_IMA_MAX_RADIUS_SECRET_LEN + 1];
3528 	IMA_OID initiatorOid;
3529 	IMA_STATUS status;
3530 	SUN_IMA_RADIUS_CONFIG radiusConfig;
3531 	int ret;
3532 	int secretLen = SUN_IMA_MAX_RADIUS_SECRET_LEN;
3533 
3534 	assert(funcRet != NULL);
3535 
3536 	ret = getSecret((char *)&radiusSharedSecret[0], &secretLen,
3537 	    0, SUN_IMA_MAX_RADIUS_SECRET_LEN);
3538 	if (ret != 0) {
3539 		return (1);
3540 	}
3541 
3542 	ret = sunInitiatorFind(&initiatorOid);
3543 	if (ret > 0) {
3544 		(void) fprintf(stderr, "%s: %s\n",
3545 		    cmdName, gettext("no initiator found"));
3546 	}
3547 	if (ret != 0) {
3548 		return (1);
3549 	}
3550 	/* First obtain existing RADIUS configuration (if any) */
3551 	(void) memset(&radiusConfig, 0, sizeof (SUN_IMA_RADIUS_CONFIG));
3552 	status = SUN_IMA_GetInitiatorRadiusConfig(initiatorOid, &radiusConfig);
3553 	if (!IMA_SUCCESS(status)) {
3554 		(void) fprintf(stderr, "%s: %s\n",
3555 		    cmdName, gettext("RADIUS server not configured yet"));
3556 		return (1);
3557 	}
3558 
3559 	/* Modify the shared secret only */
3560 	radiusConfig.sharedSecretLength = secretLen;
3561 	(void) memcpy(&radiusConfig.sharedSecret,
3562 	    &radiusSharedSecret[0], secretLen);
3563 	radiusConfig.sharedSecretValid = IMA_TRUE;
3564 	status = SUN_IMA_SetInitiatorRadiusConfig(oid, &radiusConfig);
3565 	if (!IMA_SUCCESS(status)) {
3566 		printLibError(status);
3567 		*funcRet = 1;
3568 	}
3569 
3570 	return (0);
3571 }
3572 
3573 /*
3574  * Set initiator node attributes.
3575  */
3576 static int
3577 modifyNode(cmdOptions_t *options, int *funcRet)
3578 {
3579 	IMA_NODE_NAME	nodeName;
3580 	IMA_NODE_ALIAS	nodeAlias;
3581 	IMA_OID		oid;
3582 	IMA_STATUS	status;
3583 	cmdOptions_t	*optionList = options;
3584 	int		ret;
3585 	iSCSINameCheckStatusType nameCheckStatus;
3586 	IMA_OID sharedNodeOid;
3587 	int i;
3588 	int lowerCase;
3589 	IMA_BOOL	iscsiBoot = IMA_FALSE;
3590 	IMA_BOOL	mpxioEnabled = IMA_FALSE;
3591 
3592 	assert(funcRet != NULL);
3593 
3594 	/* Get boot session's info */
3595 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
3596 	if (iscsiBoot == IMA_TRUE) {
3597 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
3598 		if (!IMA_SUCCESS(status)) {
3599 			(void) fprintf(stderr, "%s: %s\n",
3600 			    cmdName, gettext("unable to get MPxIO info"
3601 			    " of root disk"));
3602 			*funcRet = 1;
3603 			return (1);
3604 		}
3605 	}
3606 
3607 	/* Find Sun initiator */
3608 	ret = sunInitiatorFind(&oid);
3609 	if (ret > 0) {
3610 		(void) fprintf(stderr, "%s: %s\n",
3611 		    cmdName, gettext("no initiator found"));
3612 	}
3613 
3614 	if (ret != 0) {
3615 		return (ret);
3616 	}
3617 
3618 	for (; optionList->optval; optionList++) {
3619 		switch (optionList->optval) {
3620 			case 'N':
3621 				if (strlen(optionList->optarg) >=
3622 				    MAX_ISCSI_NAME_LEN) {
3623 					(void) fprintf(stderr, "%s: %s %d\n",
3624 					    cmdName,
3625 					    gettext("name too long, \
3626 					    maximum length is:"),
3627 					    MAX_ISCSI_NAME_LEN);
3628 				}
3629 
3630 				/* Take the first operand as node name. */
3631 				(void) memset(&nodeName, 0,
3632 				    sizeof (IMA_NODE_NAME));
3633 				if (mbstowcs(nodeName, optionList->optarg,
3634 				    IMA_NODE_NAME_LEN) == (size_t)-1) {
3635 					(void) fprintf(stderr, "%s: %s\n",
3636 					    cmdName,
3637 					    gettext("conversion error"));
3638 					return (1);
3639 				}
3640 
3641 				for (i = 0; nodeName[i] != 0; i++) {
3642 					lowerCase = tolower(nodeName[i]);
3643 					nodeName[i] = lowerCase;
3644 				}
3645 				/* Perform string profile checks */
3646 				nameCheckStatus =
3647 				    iSCSINameStringProfileCheck(nodeName);
3648 				iSCSINameCheckStatusDisplay(nameCheckStatus);
3649 				if (nameCheckStatus != iSCSINameCheckOK) {
3650 					*funcRet = 1; /* DIY message fix */
3651 					return (1);
3652 				}
3653 
3654 				/*
3655 				 * IMA_GetSharedNodeOid(&sharedNodeOid);
3656 				 * if (!IMA_SUCCESS(status)) {
3657 				 *   printLibError(status);
3658 				 *   return (INF_ERROR);
3659 				 * }
3660 				 */
3661 				if (iscsiBoot == IMA_TRUE) {
3662 					(void) fprintf(stderr, "%s: %s\n",
3663 					    cmdName, gettext("iscsi boot, not"
3664 					    " allowed to change"
3665 					    " initiator's name"));
3666 					return (1);
3667 				}
3668 				oid.objectType = IMA_OBJECT_TYPE_NODE;
3669 				status = IMA_SetNodeName(oid, nodeName);
3670 				if (!IMA_SUCCESS(status)) {
3671 					printLibError(status);
3672 					*funcRet = 1;
3673 					return (ret);
3674 				}
3675 				break;
3676 
3677 			case 'A':
3678 				if (iscsiBoot == IMA_TRUE) {
3679 					(void) fprintf(stderr, "%s: %s\n",
3680 					    cmdName, gettext("iscsi boot, not"
3681 					    " allowed to change"
3682 					    " initiator's alias"));
3683 					return (1);
3684 				}
3685 				/* Take the first operand as node alias. */
3686 				if (strlen(optionList->optarg) >=
3687 				    MAX_ISCSI_NAME_LEN) {
3688 					(void) fprintf(stderr, "%s: %s %d\n",
3689 					    cmdName,
3690 					    gettext("alias too long, maximum  \
3691 					    length is:"),
3692 					    MAX_ISCSI_NAME_LEN);
3693 				}
3694 
3695 				(void) memset(&nodeAlias, 0,
3696 				    sizeof (IMA_NODE_ALIAS));
3697 				if (mbstowcs(nodeAlias, optionList->optarg,
3698 				    IMA_NODE_ALIAS_LEN) == (size_t)-1) {
3699 					(void) fprintf(stderr, "%s: %s\n",
3700 					    cmdName,
3701 					    gettext("conversion error"));
3702 					return (1);
3703 				}
3704 
3705 				status = IMA_GetSharedNodeOid(&sharedNodeOid);
3706 				if (!IMA_SUCCESS(status)) {
3707 					printLibError(status);
3708 					*funcRet = 1;
3709 					return (ret);
3710 				}
3711 
3712 				status = IMA_SetNodeAlias(sharedNodeOid,
3713 				    nodeAlias);
3714 				if (!IMA_SUCCESS(status)) {
3715 					printLibError(status);
3716 					*funcRet = 1;
3717 					return (ret);
3718 				}
3719 				break;
3720 
3721 			case 'a':
3722 				if (iscsiBoot == IMA_TRUE) {
3723 					(void) fprintf(stderr, "%s: %s\n",
3724 					    cmdName, gettext("iscsi boot, not"
3725 					    " allowed to change authentication"
3726 					    " method"));
3727 					return (1);
3728 				}
3729 				if (modifyNodeAuthMethod(oid, options->optarg,
3730 				    funcRet) != 0) {
3731 					return (1);
3732 				}
3733 				break;
3734 
3735 			case 'R':
3736 				if (modifyNodeRadiusAccess(oid, options->optarg,
3737 				    funcRet) != 0) {
3738 					return (1);
3739 				}
3740 				break;
3741 
3742 			case 'r':
3743 				if (modifyNodeRadiusConfig(oid, options->optarg,
3744 				    funcRet) != 0) {
3745 					return (1);
3746 				}
3747 				break;
3748 
3749 			case 'P':
3750 				if (modifyNodeRadiusSharedSecret(oid, funcRet)
3751 				    != 0) {
3752 					return (1);
3753 				}
3754 				break;
3755 
3756 			case 'C':
3757 				if (iscsiBoot == IMA_TRUE) {
3758 					(void) fprintf(stderr, "%s: %s\n",
3759 					    cmdName, gettext("iscsi boot, not"
3760 					    " allowed to change CHAP secret"));
3761 					return (1);
3762 				}
3763 				if (modifyNodeAuthParam(oid, AUTH_PASSWORD,
3764 				    NULL, funcRet) != 0) {
3765 					return (1);
3766 				}
3767 				break;
3768 
3769 			case 'c':
3770 				if (iscsiBoot == IMA_TRUE) {
3771 					if (mpxioEnabled == IMA_FALSE) {
3772 						(void) fprintf(stderr,
3773 						    "%s: %s\n", cmdName,
3774 						    gettext("iscsi"
3775 						    " boot and MPxIO"
3776 						    " is disabled, not allowed"
3777 						    " to change number of"
3778 						    " sessions to be"
3779 						    " configured"));
3780 						return (1);
3781 					}
3782 				}
3783 				if (modifyConfiguredSessions(oid,
3784 				    optionList->optarg) != 0) {
3785 					if (iscsiBoot == IMA_TRUE) {
3786 						(void) fprintf(stderr,
3787 						    "%s: %s\n", cmdName,
3788 						    gettext("iscsi boot,"
3789 						    " fail to set configured"
3790 						    " session"));
3791 					}
3792 					return (1);
3793 				}
3794 				break;
3795 
3796 
3797 			case 'H':
3798 				if (iscsiBoot == IMA_TRUE) {
3799 					(void) fprintf(stderr, "%s: %s\n",
3800 					    cmdName, gettext("iscsi boot, not"
3801 					    " allowed to change CHAP name"));
3802 					return (1);
3803 				}
3804 				if (modifyNodeAuthParam(oid, AUTH_NAME,
3805 				    optionList->optarg, funcRet) != 0) {
3806 					return (1);
3807 				}
3808 				break;
3809 
3810 
3811 			case 'd':
3812 				if (iscsiBoot == IMA_TRUE) {
3813 					if (mpxioEnabled == IMA_FALSE) {
3814 						(void) fprintf(stderr,
3815 						    "%s: %s\n", cmdName,
3816 						    gettext("iscsi"
3817 						    " boot and MPxIO"
3818 						    " is disabled, not"
3819 						    " allowed to"
3820 						    " change initiator's"
3821 						    " login params"));
3822 						return (1);
3823 					}
3824 				}
3825 				if (setLoginParameter(oid, DATA_DIGEST,
3826 				    optionList->optarg) != 0) {
3827 					return (1);
3828 				}
3829 				break;
3830 
3831 			case 'h':
3832 				if (iscsiBoot == IMA_TRUE) {
3833 					if (mpxioEnabled == IMA_FALSE) {
3834 						(void) fprintf(stderr,
3835 						    "%s: %s\n", cmdName,
3836 						    gettext("iscsi"
3837 						    " boot and MPxIO"
3838 						    " is disabled, not"
3839 						    " allowed to"
3840 						    " change initiator's"
3841 						    " login params"));
3842 						return (1);
3843 					}
3844 				}
3845 				if (setLoginParameter(oid, HEADER_DIGEST,
3846 				    optionList->optarg) != 0) {
3847 					return (1);
3848 				}
3849 				break;
3850 
3851 			default:
3852 				(void) fprintf(stderr, "%s: %c: %s\n",
3853 				    cmdName, optionList->optval,
3854 				    gettext("unknown option"));
3855 				break;
3856 		}
3857 	}
3858 
3859 	return (ret);
3860 }
3861 
3862 /*
3863  * Modify target parameters
3864  */
3865 static int
3866 modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet)
3867 {
3868 	IMA_OID oid;
3869 	IMA_OID targetOid;
3870 	IMA_STATUS status;
3871 	IMA_OID_LIST *targetList;
3872 	SUN_IMA_TARGET_PROPERTIES targetProps;
3873 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
3874 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
3875 	int ret;
3876 	boolean_t found;
3877 	boolean_t targetAddressSpecified = B_TRUE;
3878 	boolean_t tpgtSpecified = B_FALSE;
3879 	boolean_t isIpv6 = B_FALSE;
3880 	int i;
3881 	iSCSINameCheckStatusType nameCheckStatus;
3882 	IMA_UINT16 port = 0;
3883 	IMA_UINT16 tpgt = 0;
3884 
3885 	IMA_NODE_NAME bootTargetName;
3886 	IMA_INITIATOR_AUTHPARMS bootTargetCHAP;
3887 	IMA_BOOL  iscsiBoot;
3888 	IMA_BOOL  mpxioEnabled;
3889 
3890 	cmdOptions_t *optionList = options;
3891 
3892 	assert(funcRet != NULL);
3893 
3894 	/* Find Sun initiator */
3895 	ret = sunInitiatorFind(&oid);
3896 	if (ret > 0) {
3897 		(void) fprintf(stderr, "%s: %s\n",
3898 		    cmdName, gettext("no initiator found"));
3899 	}
3900 
3901 	if (ret != 0) {
3902 		return (ret);
3903 	}
3904 
3905 	if (parseTarget(targetName,
3906 	    &wcInputObject[0],
3907 	    MAX_ISCSI_NAME_LEN + 1,
3908 	    &targetAddressSpecified,
3909 	    &targetAddress[0],
3910 	    SUN_IMA_IP_ADDRESS_PORT_LEN,
3911 	    &port,
3912 	    &tpgtSpecified,
3913 	    &tpgt,
3914 	    &isIpv6) != PARSE_TARGET_OK) {
3915 		return (1);
3916 	}
3917 
3918 	/* Perform string profile checks */
3919 	nameCheckStatus = iSCSINameStringProfileCheck(wcInputObject);
3920 	iSCSINameCheckStatusDisplay(nameCheckStatus);
3921 	if (nameCheckStatus != iSCSINameCheckOK) {
3922 		return (1);
3923 	}
3924 
3925 	status = IMA_GetTargetOidList(oid, &targetList);
3926 	if (!IMA_SUCCESS(status)) {
3927 		printLibError(status);
3928 		*funcRet = 1;
3929 		return (0);
3930 	}
3931 
3932 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
3933 	if (iscsiBoot == IMA_TRUE) {
3934 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
3935 		if (!IMA_SUCCESS(status)) {
3936 			(void) fprintf(stderr, "%s: %s\n",
3937 			    cmdName, gettext("unable to get MPxIO info"
3938 			    " of root disk"));
3939 			*funcRet = 1;
3940 			return (ret);
3941 		}
3942 		status = SUN_IMA_GetBootTargetName(bootTargetName);
3943 		if (!IMA_SUCCESS(status)) {
3944 			(void) fprintf(stderr, "%s: %s\n",
3945 			    cmdName, gettext("unable to get boot target's"
3946 			    " name"));
3947 			*funcRet = 1;
3948 			return (ret);
3949 		}
3950 		status = SUN_IMA_GetBootTargetAuthParams(&bootTargetCHAP);
3951 		if (!IMA_SUCCESS(status)) {
3952 			(void) fprintf(stderr, "%s: %s\n",
3953 			    cmdName, gettext("unable to get boot target's"
3954 			    " auth param"));
3955 			*funcRet = 1;
3956 			return (ret);
3957 		}
3958 	}
3959 
3960 	/* find target oid */
3961 	for (found = B_FALSE, i = 0; i < targetList->oidCount; i++) {
3962 		status = SUN_IMA_GetTargetProperties(targetList->oids[i],
3963 		    &targetProps);
3964 		if (!IMA_SUCCESS(status)) {
3965 			printLibError(status);
3966 			(void) IMA_FreeMemory(targetList);
3967 			*funcRet = 1;
3968 			return (ret);
3969 		}
3970 
3971 		/*
3972 		 * Compare the target name with the input name
3973 		 */
3974 		if ((targetNamesEqual(wcInputObject, targetProps.imaProps.name)
3975 		    == B_TRUE)) {
3976 			/*
3977 			 * For now, regardless of whether a target address
3978 			 * is specified, we return B_TRUE because
3979 			 * IMA_TARGET_PROPERTIES does not have a field for
3980 			 * specifying address.
3981 			 */
3982 			found = B_TRUE;
3983 			targetOid = targetList->oids[i];
3984 
3985 			if ((targetNamesEqual(bootTargetName, wcInputObject)
3986 			    == B_TRUE) && (iscsiBoot == IMA_TRUE)) {
3987 				/*
3988 				 * iscsi booting, need changed target param is
3989 				 * booting target, for auth param, not allow
3990 				 * to change, for others dependent on mpxio
3991 				 */
3992 
3993 				if ((optionList->optval == 'C') ||
3994 				    (optionList->optval == 'H') ||
3995 				    (optionList->optval == 'B') ||
3996 				    (optionList->optval == 'a')) {
3997 					/*
3998 					 * -C CHAP secret set
3999 					 * -H CHAP name set
4000 					 * -a authentication
4001 					 * -B bi-directional-authentication
4002 					 */
4003 					(void) fprintf(stderr, "%s: %s\n",
4004 					    cmdName, gettext("iscsi boot,"
4005 					    " not allowed to modify"
4006 					    " authentication parameters"
4007 					    "  of boot target"));
4008 					return (1);
4009 				}
4010 				if (mpxioEnabled == IMA_FALSE) {
4011 					(void) fprintf(stderr, "%s: %s\n",
4012 					    cmdName, gettext("iscsi boot and"
4013 					    " MPxIO is disabled, not allowed"
4014 					    " to modify boot target's"
4015 					    " parameters"));
4016 					return (1);
4017 				}
4018 
4019 			}
4020 
4021 			if (modifyIndividualTargetParam(optionList, targetOid,
4022 			    funcRet) != 0) {
4023 				return (ret);
4024 			}
4025 
4026 			/*
4027 			 * Even after finding a matched target, keep going
4028 			 * since there could be multiple target objects
4029 			 * associated with one target name in the system
4030 			 * because of different TPGTs.
4031 			 */
4032 		}
4033 	}
4034 
4035 	/* If the target OID cannot be found create one */
4036 	if (!found) {
4037 		status = SUN_IMA_CreateTargetOid(wcInputObject, &targetOid);
4038 		if (!IMA_SUCCESS(status)) {
4039 			printLibError(status);
4040 			(void) IMA_FreeMemory(targetList);
4041 			*funcRet = 1;
4042 			return (ret);
4043 		}
4044 		if (modifyIndividualTargetParam(optionList, targetOid,
4045 		    funcRet) != 0) {
4046 				return (ret);
4047 		}
4048 	}
4049 
4050 	(void) IMA_FreeMemory(targetList);
4051 	return (ret);
4052 }
4053 
4054 /*
4055  * Add one or more addresses
4056  */
4057 static int
4058 addAddress(int addrType, int operandLen, char *operand[], int *funcRet)
4059 {
4060 	IMA_STATUS status;
4061 	IMA_OID oid, addressOid;
4062 	SUN_IMA_TARGET_ADDRESS address;
4063 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
4064 	int ret;
4065 	int i;
4066 
4067 	assert(funcRet != NULL);
4068 
4069 	/* Find Sun initiator */
4070 	ret = sunInitiatorFind(&oid);
4071 	if (ret > 0) {
4072 		(void) fprintf(stderr, "%s: %s\n",
4073 		    cmdName, gettext("no initiator found"));
4074 	}
4075 
4076 	if (ret != 0) {
4077 		return (ret);
4078 	}
4079 
4080 	/*
4081 	 * Format of discovery address operand:
4082 	 *
4083 	 * <IP address|hostname>:<port>
4084 	 */
4085 	for (i = 0; i < operandLen; i++) {
4086 		/* initialize */
4087 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4088 		(void) memset(&address, 0, sizeof (address));
4089 
4090 		if (mbstowcs(wcInputObject, operand[i],
4091 		    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
4092 			(void) fprintf(stderr, "%s: %s\n",
4093 			    cmdName, gettext("conversion error"));
4094 			ret = 1;
4095 			continue;
4096 		}
4097 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
4098 		    != 0) {
4099 			ret = 1;
4100 			continue;
4101 		}
4102 		if (addrType == DISCOVERY_ADDRESS) {
4103 			status = IMA_AddDiscoveryAddress(oid,
4104 			    address.imaStruct, &addressOid);
4105 			if (!IMA_SUCCESS(status)) {
4106 				printLibError(status);
4107 				*funcRet = 1;
4108 				return (ret);
4109 			}
4110 		} else if (addrType == ISNS_SERVER_ADDRESS) {
4111 			status = SUN_IMA_AddISNSServerAddress(address);
4112 			if (!IMA_SUCCESS(status)) {
4113 				printLibError(status);
4114 				*funcRet = 1;
4115 				return (ret);
4116 			}
4117 		}
4118 	}
4119 	return (ret);
4120 }
4121 
4122 /*
4123  * Add one or more static configuration targets
4124  */
4125 static int
4126 addStaticConfig(int operandLen, char *operand[], int *funcRet)
4127 {
4128 	int i;
4129 	boolean_t targetAddressSpecified = B_FALSE;
4130 	boolean_t tpgtSpecified = B_FALSE;
4131 	boolean_t isIpv6 = B_FALSE;
4132 	int ret;
4133 	int addrType;
4134 	IMA_STATUS status;
4135 	IMA_OID oid;
4136 	SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig;
4137 	IMA_UINT16 port = 0;
4138 	IMA_UINT16 tpgt = 0;
4139 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
4140 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4141 	iSCSINameCheckStatusType nameCheckStatus;
4142 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
4143 
4144 	assert(funcRet != NULL);
4145 
4146 	/* Find Sun initiator */
4147 	ret = sunInitiatorFind(&oid);
4148 	if (ret > 0) {
4149 		(void) fprintf(stderr, "%s: %s\n",
4150 		    cmdName, gettext("no initiator found"));
4151 	}
4152 
4153 	if (ret != 0) {
4154 		return (ret);
4155 	}
4156 
4157 	/*
4158 	 * Format of static config operand:
4159 	 *  <target-name>,<IP address|hostname>[:port][,tpgt]
4160 	 */
4161 	for (i = 0; i < operandLen; i++) {
4162 		if (parseTarget(operand[i],
4163 		    &staticTargetName[0],
4164 		    MAX_ISCSI_NAME_LEN + 1,
4165 		    &targetAddressSpecified,
4166 		    &staticTargetAddress[0],
4167 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4168 		    &port,
4169 		    &tpgtSpecified,
4170 		    &tpgt,
4171 		    &isIpv6) != PARSE_TARGET_OK) {
4172 			ret = 1;
4173 			continue;
4174 		}
4175 
4176 		if (targetAddressSpecified != B_TRUE) {
4177 			(void) fprintf(stderr, "%s: %s\n",
4178 			    cmdName, gettext("missing target address"));
4179 			*funcRet = 1; /* DIY message fix */
4180 			return (1);
4181 		}
4182 		/* Perform string profile checks */
4183 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4184 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4185 		if (nameCheckStatus != iSCSINameCheckOK) {
4186 			*funcRet = 1; /* DIY message fix */
4187 			return (1);
4188 		}
4189 		(void) wcsncpy(staticConfig.targetName, staticTargetName,
4190 		    MAX_ISCSI_NAME_LEN + 1);
4191 
4192 		(void) wcstombs(sAddr, staticTargetAddress, sizeof (sAddr));
4193 
4194 		if (isIpv6 == B_TRUE) {
4195 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4196 			    id.ipAddress.ipv4Address = B_FALSE;
4197 			addrType = AF_INET6;
4198 		} else {
4199 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4200 			    id.ipAddress.ipv4Address = B_TRUE;
4201 			addrType = AF_INET;
4202 		}
4203 
4204 		if (inet_pton(addrType, sAddr, staticConfig.targetAddress.
4205 		    imaStruct.hostnameIpAddress.id.ipAddress.ipAddress) != 1) {
4206 			(void) fprintf(stderr, "%s: %s\n",
4207 			    cmdName, gettext("static config conversion error"));
4208 			ret = 1;
4209 			continue;
4210 		}
4211 
4212 		staticConfig.targetAddress.imaStruct.portNumber = port;
4213 		if (tpgtSpecified == B_TRUE) {
4214 			staticConfig.targetAddress.defaultTpgt = B_FALSE;
4215 			staticConfig.targetAddress.tpgt = tpgt;
4216 		} else {
4217 			staticConfig.targetAddress.defaultTpgt = B_TRUE;
4218 			staticConfig.targetAddress.tpgt = 0;
4219 		}
4220 
4221 		status = SUN_IMA_AddStaticTarget(oid, staticConfig, &oid);
4222 		if (!IMA_SUCCESS(status)) {
4223 			printLibError(status);
4224 			*funcRet = 1;
4225 			return (1);
4226 		}
4227 	}
4228 	return (ret);
4229 }
4230 
4231 /*
4232  * Remove one or more addresses
4233  */
4234 static int
4235 removeAddress(int addrType, int operandLen, char *operand[], int *funcRet)
4236 {
4237 	IMA_STATUS status;
4238 	IMA_OID initiatorOid;
4239 	SUN_IMA_TARGET_ADDRESS address;
4240 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
4241 	int ret;
4242 	int i;
4243 
4244 	assert(funcRet != NULL);
4245 
4246 	/* Find Sun initiator */
4247 	ret = sunInitiatorFind(&initiatorOid);
4248 	if (ret > 0) {
4249 		(void) fprintf(stderr, "%s: %s\n",
4250 		    cmdName, gettext("no initiator found"));
4251 	}
4252 
4253 	if (ret != 0) {
4254 		return (ret);
4255 	}
4256 
4257 	for (i = 0; i < operandLen; i++) {
4258 		/* initialize */
4259 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4260 		(void) memset(&address, 0, sizeof (address));
4261 
4262 		if (mbstowcs(wcInputObject, operand[i],
4263 		    MAX_ADDRESS_LEN + 1) == (size_t)-1) {
4264 			(void) fprintf(stderr, "%s: %s\n",
4265 			    cmdName, gettext("conversion error"));
4266 			ret = 1;
4267 			continue;
4268 		}
4269 
4270 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
4271 		    != 0) {
4272 			ret = 1;
4273 			continue;
4274 		}
4275 
4276 		if (addrType == DISCOVERY_ADDRESS) {
4277 			status = SUN_IMA_RemoveDiscoveryAddress(address);
4278 			if (!IMA_SUCCESS(status)) {
4279 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4280 					(void) fprintf(stderr, "%s: %s\n",
4281 					    operand[i], gettext("not found"));
4282 				} else {
4283 					printLibError(status);
4284 				}
4285 				*funcRet = 1;
4286 			}
4287 		} else {
4288 			status = SUN_IMA_RemoveISNSServerAddress(address);
4289 			if (!IMA_SUCCESS(status)) {
4290 				printLibError(status);
4291 				*funcRet = 1;
4292 			}
4293 		}
4294 	}
4295 	return (ret);
4296 }
4297 
4298 /*
4299  * Remove one or more static configuration targets
4300  */
4301 static int
4302 removeStaticConfig(int operandLen, char *operand[], int *funcRet)
4303 {
4304 	IMA_STATUS status;
4305 	IMA_OID initiatorOid;
4306 	IMA_OID_LIST *staticTargetList;
4307 	SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps;
4308 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
4309 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4310 	int ret;
4311 	boolean_t atLeastFoundOne;
4312 	boolean_t matched;
4313 	boolean_t targetAddressSpecified = B_TRUE;
4314 	boolean_t tpgtSpecified = B_FALSE;
4315 	boolean_t isIpv6 = B_FALSE;
4316 	int i, j;
4317 	IMA_UINT16 port = 0;
4318 	IMA_UINT16 tpgt = 0;
4319 	iSCSINameCheckStatusType nameCheckStatus;
4320 	char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
4321 	wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4322 
4323 	assert(funcRet != NULL);
4324 
4325 	/* Find Sun initiator */
4326 	ret = sunInitiatorFind(&initiatorOid);
4327 	if (ret > 0) {
4328 		(void) fprintf(stderr, "%s: %s\n",
4329 		    cmdName, gettext("no initiator found"));
4330 	}
4331 
4332 	if (ret != 0) {
4333 		return (ret);
4334 	}
4335 
4336 	status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid,
4337 	    &staticTargetList);
4338 	if (!IMA_SUCCESS(status)) {
4339 		printLibError(status);
4340 		*funcRet = 1;
4341 		return (ret);
4342 	}
4343 
4344 	for (i = 0; i < operandLen; i++) {
4345 		if (parseTarget(operand[i],
4346 		    &staticTargetName[0],
4347 		    MAX_ISCSI_NAME_LEN + 1,
4348 		    &targetAddressSpecified,
4349 		    &staticTargetAddress[0],
4350 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4351 		    &port,
4352 		    &tpgtSpecified,
4353 		    &tpgt,
4354 		    &isIpv6) != PARSE_TARGET_OK) {
4355 			ret = 1;
4356 			continue;
4357 		}
4358 
4359 		/* Perform string profile checks */
4360 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4361 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4362 		if (nameCheckStatus != iSCSINameCheckOK) {
4363 			return (1);
4364 		}
4365 
4366 		for (atLeastFoundOne = B_FALSE, j = 0;
4367 		    j < staticTargetList->oidCount;
4368 		    j++) {
4369 			IMA_UINT16 stpgt;
4370 
4371 			matched = B_FALSE;
4372 			status = SUN_IMA_GetStaticTargetProperties(
4373 			    staticTargetList->oids[j], &staticTargetProps);
4374 			if (!IMA_SUCCESS(status)) {
4375 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4376 					/*
4377 					 * When removing multiple static-config
4378 					 * entries we need to expect get
4379 					 * failures. These failures occur when
4380 					 * we are trying to get entry
4381 					 * information we have just removed.
4382 					 * Ignore the failure and continue.
4383 					 */
4384 					ret = 1;
4385 					continue;
4386 				} else {
4387 					printLibError(status);
4388 					(void) IMA_FreeMemory(staticTargetList);
4389 					*funcRet = 1;
4390 					return (ret);
4391 				}
4392 			}
4393 
4394 			stpgt =
4395 			    staticTargetProps.staticTarget.targetAddress.tpgt;
4396 
4397 			/*
4398 			 * Compare the static target name with the input if
4399 			 * one was input
4400 			 */
4401 			if ((targetNamesEqual(
4402 			    staticTargetProps.staticTarget.targetName,
4403 			    staticTargetName) == B_TRUE)) {
4404 				if (targetAddressSpecified == B_FALSE) {
4405 					matched = B_TRUE;
4406 				} else {
4407 
4408 					if (staticTargetProps.staticTarget.
4409 					    targetAddress.imaStruct.
4410 					    hostnameIpAddress.
4411 					    id.ipAddress.ipv4Address ==
4412 					    IMA_TRUE) {
4413 						(void) inet_ntop(AF_INET,
4414 						    staticTargetProps.
4415 						    staticTarget.targetAddress.
4416 						    imaStruct.hostnameIpAddress.
4417 						    id.ipAddress.ipAddress,
4418 						    tmpStr,
4419 						    sizeof (tmpStr));
4420 					} else {
4421 						(void) inet_ntop(AF_INET6,
4422 						    staticTargetProps.
4423 						    staticTarget.targetAddress.
4424 						    imaStruct.hostnameIpAddress.
4425 						    id.ipAddress.ipAddress,
4426 						    tmpStr,
4427 						    sizeof (tmpStr));
4428 					}
4429 
4430 					if (mbstowcs(tmpTargetAddress, tmpStr,
4431 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4432 					    (size_t)-1) {
4433 						(void) fprintf(stderr,
4434 						    "%s: %s\n",
4435 						    cmdName, gettext(
4436 						    "conversion error"));
4437 						ret = 1;
4438 						continue;
4439 					}
4440 
4441 					if ((wcsncmp(tmpTargetAddress,
4442 					    staticTargetAddress,
4443 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4444 					    0) && (staticTargetProps.
4445 					    staticTarget.targetAddress.
4446 					    imaStruct.portNumber == port)) {
4447 						if (tpgtSpecified == B_FALSE) {
4448 							matched = B_TRUE;
4449 						} else {
4450 							if (tpgt == stpgt) {
4451 								matched =
4452 								    B_TRUE;
4453 							}
4454 						}
4455 					}
4456 				}
4457 
4458 				if (matched) {
4459 					status =
4460 					    IMA_RemoveStaticDiscoveryTarget(
4461 					    staticTargetList->oids[j]);
4462 					if (!IMA_SUCCESS(status)) {
4463 						printLibError(status);
4464 						*funcRet = 1;
4465 						return (ret);
4466 					}
4467 					atLeastFoundOne = B_TRUE;
4468 				}
4469 			}
4470 		}
4471 		if (!atLeastFoundOne) {
4472 			(void) fprintf(stderr, gettext("%ws,%ws: %s\n"),
4473 			    staticTargetName, staticTargetAddress,
4474 			    gettext("not found"));
4475 		}
4476 	}
4477 	return (ret);
4478 }
4479 
4480 /*
4481  * Remove one or more target params.
4482  */
4483 static int
4484 removeTargetParam(int operandLen, char *operand[], int *funcRet)
4485 {
4486 	char *commaPos;
4487 	IMA_STATUS status;
4488 	IMA_OID initiatorOid;
4489 	IMA_OID_LIST *targetList;
4490 	SUN_IMA_TARGET_PROPERTIES targetProps;
4491 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
4492 	int ret;
4493 	boolean_t found;
4494 	int i, j;
4495 	IMA_NODE_NAME bootTargetName;
4496 	IMA_BOOL	iscsiBoot = IMA_FALSE;
4497 	IMA_BOOL	mpxioEnabled = IMA_FALSE;
4498 
4499 	/* Get boot session's info */
4500 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
4501 	if (iscsiBoot == IMA_TRUE) {
4502 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
4503 		if (!IMA_SUCCESS(status)) {
4504 			(void) fprintf(stderr, "%s: %s\n",
4505 			    cmdName, gettext("unable to get MPxIO info of"
4506 			    " root disk"));
4507 			*funcRet = 1;
4508 			return (1);
4509 		}
4510 		status = SUN_IMA_GetBootTargetName(bootTargetName);
4511 		if (!IMA_SUCCESS(status)) {
4512 			(void) fprintf(stderr, "%s: %s\n",
4513 			    cmdName, gettext("unable to get boot"
4514 			    " target's name"));
4515 			*funcRet = 1;
4516 			return (1);
4517 		}
4518 	}
4519 
4520 	assert(funcRet != NULL);
4521 
4522 	/* Find Sun initiator */
4523 	ret = sunInitiatorFind(&initiatorOid);
4524 	if (ret > 0) {
4525 		(void) fprintf(stderr, "%s: %s\n",
4526 		    cmdName, gettext("no initiator found"));
4527 	}
4528 
4529 	if (ret != 0) {
4530 		return (ret);
4531 	}
4532 
4533 	status = IMA_GetTargetOidList(initiatorOid, &targetList);
4534 	if (!IMA_SUCCESS(status)) {
4535 		printLibError(status);
4536 		*funcRet = 1;
4537 		return (ret);
4538 	}
4539 
4540 	for (i = 0; i < operandLen; i++) {
4541 		/* initialize */
4542 		commaPos = strchr(operand[i], ',');
4543 		if (commaPos) {
4544 			/* Ignore IP address. */
4545 			*commaPos = NULL;
4546 		}
4547 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4548 		if (mbstowcs(wcInputObject, operand[i],
4549 		    MAX_ISCSI_NAME_LEN + 1) == (size_t)-1) {
4550 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4551 			    gettext("conversion error"));
4552 			ret = 1;
4553 			continue;
4554 		}
4555 
4556 		for (found = B_FALSE, j = 0; j < targetList->oidCount;
4557 		    j++) {
4558 			status = SUN_IMA_GetTargetProperties(
4559 			    targetList->oids[j], &targetProps);
4560 			if (!IMA_SUCCESS(status)) {
4561 				printLibError(status);
4562 				(void) IMA_FreeMemory(targetList);
4563 				*funcRet = 1;
4564 				return (ret);
4565 			}
4566 
4567 			/*
4568 			 * Compare the target name with the input if
4569 			 * one was input
4570 			 */
4571 			if (targetNamesEqual(targetProps.imaProps.name,
4572 			    wcInputObject) == B_TRUE) {
4573 				found = B_TRUE;
4574 				if ((targetNamesEqual(bootTargetName,
4575 				    wcInputObject) == B_TRUE) &&
4576 				    (iscsiBoot == IMA_TRUE)) {
4577 					/*
4578 					 * iscsi booting, need changed target
4579 					 * param is booting target, booting
4580 					 * session mpxio disabled, not
4581 					 * allow to update
4582 					 */
4583 					if (mpxioEnabled == IMA_FALSE) {
4584 						(void) fprintf(stderr,
4585 						    "%s: %s\n", cmdName,
4586 						    gettext("iscsi boot"
4587 						    " with MPxIO disabled,"
4588 						    " not allowed to remove"
4589 						    " boot sess param"));
4590 						continue;
4591 					}
4592 
4593 				}
4594 
4595 				status = SUN_IMA_RemoveTargetParam(
4596 				    targetList->oids[j]);
4597 				if (!IMA_SUCCESS(status)) {
4598 					printLibError(status);
4599 					(void) IMA_FreeMemory(targetList);
4600 					*funcRet = 1;
4601 					return (ret);
4602 				}
4603 			}
4604 		}
4605 		if (!found) {
4606 			/* Silently ignoring it? */
4607 			(void) fprintf(stderr, gettext("%ws: %s\n"),
4608 			    wcInputObject, gettext("not found"));
4609 		}
4610 	}
4611 
4612 	(void) IMA_FreeMemory(targetList);
4613 	return (ret);
4614 }
4615 
4616 /*ARGSUSED*/
4617 static int
4618 addFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4619     void *addArgs, int *funcRet)
4620 {
4621 	int ret;
4622 
4623 	assert(funcRet != NULL);
4624 
4625 	switch (object) {
4626 		case DISCOVERY_ADDRESS:
4627 		case ISNS_SERVER_ADDRESS:
4628 			ret = addAddress(object, operandLen, operand, funcRet);
4629 			break;
4630 		case STATIC_CONFIG:
4631 			ret = addStaticConfig(operandLen, operand, funcRet);
4632 			break;
4633 		default:
4634 			(void) fprintf(stderr, "%s: %s\n",
4635 			    cmdName, gettext("unknown object"));
4636 			ret = 1;
4637 			break;
4638 	}
4639 	return (ret);
4640 }
4641 
4642 /*ARGSUSED*/
4643 static int
4644 listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4645     void *addArgs, int *funcRet)
4646 {
4647 	int ret;
4648 
4649 	assert(funcRet != NULL);
4650 
4651 	switch (object) {
4652 	case DISCOVERY:
4653 		ret = listDiscovery(funcRet);
4654 		break;
4655 	case DISCOVERY_ADDRESS:
4656 		ret = listDiscoveryAddress(operandLen, operand, options,
4657 		    funcRet);
4658 		break;
4659 	case ISNS_SERVER_ADDRESS:
4660 		ret = listISNSServerAddress(operandLen, operand, options,
4661 		    funcRet);
4662 		break;
4663 	case NODE:
4664 		ret = listNode(funcRet);
4665 		break;
4666 	case STATIC_CONFIG:
4667 		ret = listStaticConfig(operandLen, operand, funcRet);
4668 		break;
4669 	case TARGET:
4670 		ret = listTarget(operandLen, operand, options, funcRet);
4671 		break;
4672 	case TARGET_PARAM:
4673 		ret = listTargetParam(operandLen, operand, options, funcRet);
4674 		break;
4675 	default:
4676 		(void) fprintf(stderr, "%s: %s\n",
4677 		    cmdName, gettext("unknown object"));
4678 		ret = 1;
4679 		break;
4680 	}
4681 	return (ret);
4682 }
4683 
4684 /*ARGSUSED*/
4685 static int
4686 modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4687     void *addArgs, int *funcRet)
4688 {
4689 	int ret, i;
4690 
4691 	assert(funcRet != NULL);
4692 
4693 	switch (object) {
4694 	case DISCOVERY:
4695 		ret = modifyDiscovery(options, funcRet);
4696 		break;
4697 	case NODE:
4698 		ret = modifyNode(options, funcRet);
4699 		break;
4700 	case TARGET_PARAM:
4701 		i = 0;
4702 		while (operand[i]) {
4703 			ret = modifyTargetParam(options, operand[i], funcRet);
4704 
4705 			if (ret) {
4706 				(void) fprintf(stderr, "%s: %s: %s\n",
4707 				    cmdName, gettext("modify failed"),
4708 				    operand[i]);
4709 				return (ret);
4710 			}
4711 			i++;
4712 		}
4713 
4714 		break;
4715 	default:
4716 		(void) fprintf(stderr, "%s: %s\n",
4717 		    cmdName, gettext("unknown object"));
4718 		ret = 1;
4719 		break;
4720 	}
4721 	return (ret);
4722 }
4723 
4724 /*ARGSUSED*/
4725 static int
4726 removeFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4727     void *addArgs, int *funcRet)
4728 {
4729 	int ret;
4730 
4731 	switch (object) {
4732 		case DISCOVERY_ADDRESS:
4733 		case ISNS_SERVER_ADDRESS:
4734 			ret = removeAddress(object, operandLen, operand,
4735 			    funcRet);
4736 			break;
4737 		case STATIC_CONFIG:
4738 			ret = removeStaticConfig(operandLen, operand, funcRet);
4739 			break;
4740 		case TARGET_PARAM:
4741 			ret = removeTargetParam(operandLen, operand, funcRet);
4742 			break;
4743 		default:
4744 			(void) fprintf(stderr, "%s: %s\n",
4745 			    cmdName, gettext("unknown object"));
4746 			ret = 1;
4747 			break;
4748 	}
4749 	return (ret);
4750 }
4751 
4752 static void
4753 iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status)
4754 {
4755 	switch (status) {
4756 		case iSCSINameLenZero:
4757 			(void) fprintf(stderr, "%s: %s\n",
4758 			    cmdName, gettext("empty iSCSI name."));
4759 			break;
4760 		case iSCSINameLenExceededMax:
4761 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4762 			    gettext("iSCSI name exceeded maximum length."));
4763 			break;
4764 		case iSCSINameUnknownType:
4765 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4766 			    gettext("unknown iSCSI name type."));
4767 			break;
4768 		case iSCSINameInvalidCharacter:
4769 			(void) fprintf(stderr, "%s: %s\n",
4770 			    cmdName,
4771 			    gettext("iSCSI name invalid character used"));
4772 			break;
4773 		case iSCSINameIqnFormatError:
4774 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4775 			    gettext("iqn formatting error."));
4776 			break;
4777 		case iSCSINameIqnDateFormatError:
4778 			(void) fprintf(stderr, "%s: %s\n",
4779 			    cmdName, gettext("invalid iqn date." \
4780 			    "  format is: YYYY-MM"));
4781 			break;
4782 		case iSCSINameIqnSubdomainFormatError:
4783 			(void) fprintf(stderr, "%s: %s\n",
4784 			    cmdName, gettext("missing subdomain after \":\""));
4785 			break;
4786 		case iSCSINameIqnInvalidYearError:
4787 			(void) fprintf(stderr, "%s: %s\n",
4788 			    cmdName, gettext("invalid year"));
4789 			break;
4790 		case iSCSINameIqnInvalidMonthError:
4791 			(void) fprintf(stderr, "%s: %s\n",
4792 			    cmdName, gettext("invalid month"));
4793 			break;
4794 		case iSCSINameIqnFQDNError:
4795 			(void) fprintf(stderr, "%s: %s\n",
4796 			    cmdName, gettext("missing reversed fully qualified"\
4797 			    " domain name"));
4798 			break;
4799 		case iSCSINameEUIFormatError:
4800 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4801 			    gettext("eui formatting error."));
4802 			break;
4803 	}
4804 }
4805 
4806 /*
4807  * A convenient function to modify the target parameters of an individual
4808  * target.
4809  *
4810  * Return 0 if successful
4811  * Return 1 if failed
4812  */
4813 static int
4814 modifyIndividualTargetParam(cmdOptions_t *optionList, IMA_OID targetOid,
4815     int *funcRet)
4816 {
4817 	assert(funcRet != NULL);
4818 
4819 	for (; optionList->optval; optionList++) {
4820 		switch (optionList->optval) {
4821 			case 'a':
4822 				if (modifyTargetAuthMethod(targetOid,
4823 				    optionList->optarg, funcRet) != 0) {
4824 					return (1);
4825 				}
4826 				break;
4827 			case 'B':
4828 				if (modifyTargetBidirAuthFlag(targetOid,
4829 				    optionList->optarg, funcRet) != 0) {
4830 					return (1);
4831 				}
4832 				break;
4833 			case 'C':
4834 				if (modifyTargetAuthParam(targetOid,
4835 				    AUTH_PASSWORD, NULL, funcRet) != 0) {
4836 					return (1);
4837 				}
4838 				break;
4839 			case 'd':
4840 				if (setLoginParameter(targetOid, DATA_DIGEST,
4841 				    optionList->optarg) != 0) {
4842 					return (1);
4843 				}
4844 				break;
4845 			case 'h':
4846 				if (setLoginParameter(targetOid, HEADER_DIGEST,
4847 				    optionList->optarg) != 0) {
4848 					return (1);
4849 				}
4850 				break;
4851 			case 'p':
4852 				/* Login parameter */
4853 				if (setLoginParameters(targetOid,
4854 				    optionList->optarg) != 0) {
4855 					return (1);
4856 				}
4857 				break;
4858 			case 'c':
4859 				/* Modify configure sessions */
4860 				if (modifyConfiguredSessions(targetOid,
4861 				    optionList->optarg) != 0) {
4862 					return (1);
4863 				}
4864 				break;
4865 			case 'H':
4866 				if (modifyTargetAuthParam(targetOid, AUTH_NAME,
4867 				    optionList->optarg, funcRet) != 0) {
4868 					return (1);
4869 				}
4870 				break;
4871 		}
4872 	}
4873 
4874 	return (0);
4875 }
4876 
4877 /*
4878  * This helper function could go into a utility module for general use.
4879  */
4880 static int
4881 parseAddress(char *address_port_str,
4882     uint16_t defaultPort,
4883     char *address_str,
4884     size_t address_str_len,
4885     uint16_t *port,
4886     boolean_t *isIpv6)
4887 {
4888 	char port_str[64];
4889 	int tmp_port;
4890 	char *errchr;
4891 
4892 	if (address_port_str[0] == '[') {
4893 		/* IPv6 address */
4894 		char *close_bracket_pos;
4895 		close_bracket_pos = strchr(address_port_str, ']');
4896 		if (!close_bracket_pos) {
4897 			syslog(LOG_USER|LOG_DEBUG,
4898 			    "IP address format error: %s\n", address_str);
4899 			return (PARSE_ADDR_MISSING_CLOSING_BRACKET);
4900 		}
4901 
4902 		*close_bracket_pos = NULL;
4903 		(void) strlcpy(address_str, &address_port_str[1],
4904 		    address_str_len);
4905 
4906 		/* Extract the port number */
4907 		close_bracket_pos++;
4908 		if (*close_bracket_pos == ':') {
4909 			close_bracket_pos++;
4910 			if (*close_bracket_pos != NULL) {
4911 				(void) strlcpy(port_str, close_bracket_pos, 64);
4912 				tmp_port = strtol(port_str, &errchr, 10);
4913 				if (tmp_port == 0 && errchr != NULL) {
4914 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4915 					    cmdName, address_str,
4916 					    close_bracket_pos,
4917 					    gettext("port number invalid"));
4918 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4919 				}
4920 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4921 				    (tmp_port < 0)) {
4922 					/* Port number out of range */
4923 					syslog(LOG_USER|LOG_DEBUG,
4924 					    "Specified port out of range: %d",
4925 					    tmp_port);
4926 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4927 				} else {
4928 					*port = (uint16_t)tmp_port;
4929 				}
4930 			} else {
4931 				*port = defaultPort;
4932 			}
4933 		} else {
4934 			*port = defaultPort;
4935 		}
4936 
4937 		*isIpv6 = B_TRUE;
4938 	} else {
4939 		/* IPv4 address */
4940 		char *colon_pos;
4941 		colon_pos = strchr(address_port_str, ':');
4942 		if (!colon_pos) {
4943 			/* No port number specified. */
4944 			*port = defaultPort;
4945 			(void) strlcpy(address_str, address_port_str,
4946 			    address_str_len);
4947 		} else {
4948 			*colon_pos = (char)NULL;
4949 			(void) strlcpy(address_str, address_port_str,
4950 			    address_str_len);
4951 
4952 			/* Extract the port number */
4953 			colon_pos++;
4954 			if (*colon_pos != NULL) {
4955 
4956 				(void) strlcpy(port_str, colon_pos, 64);
4957 				tmp_port = strtol(port_str, &errchr, 10);
4958 				if (tmp_port == 0 && errchr != NULL) {
4959 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4960 					    cmdName, address_str, colon_pos,
4961 					    gettext("port number invalid"));
4962 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4963 				}
4964 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4965 				    (tmp_port < 0)) {
4966 					/* Port number out of range */
4967 					syslog(LOG_USER|LOG_DEBUG,
4968 					    "Specified port out of range: %d",
4969 					    tmp_port);
4970 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4971 				} else {
4972 					*port = (uint16_t)tmp_port;
4973 				}
4974 			} else {
4975 				*port = defaultPort;
4976 			}
4977 		}
4978 
4979 		*isIpv6 = B_FALSE;
4980 	}
4981 
4982 	return (PARSE_ADDR_OK);
4983 }
4984 
4985 /*
4986  * This helper function could go into a utility module for general use.
4987  */
4988 iSCSINameCheckStatusType
4989 iSCSINameStringProfileCheck(wchar_t *name)
4990 {
4991 	char mb_name[MAX_ISCSI_NAME_LEN + 1];
4992 	size_t name_len;
4993 	char *tmp;
4994 
4995 	(void) wcstombs(mb_name, name, MAX_ISCSI_NAME_LEN + 1);
4996 
4997 	if ((name_len = strlen(mb_name)) == 0) {
4998 		return (iSCSINameLenZero);
4999 	} else if (name_len > MAX_ISCSI_NAME_LEN) {
5000 		return (iSCSINameLenExceededMax);
5001 	}
5002 
5003 	/*
5004 	 * check for invalid characters
5005 	 * According to RFC 3722 iSCSI name must be either a letter,
5006 	 * a digit or one of the following '-' '.' ':'
5007 	 */
5008 	for (tmp = mb_name; *tmp != NULL; tmp++) {
5009 		if ((isalnum(*tmp) == 0) &&
5010 		    (*tmp != '-') &&
5011 		    (*tmp != '.') &&
5012 		    (*tmp != ':')) {
5013 			return (iSCSINameInvalidCharacter);
5014 		}
5015 	}
5016 
5017 	if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX,
5018 	    strlen(ISCSI_IQN_NAME_PREFIX)) == 0) {
5019 		/*
5020 		 * If name is of type iqn, check date string and naming
5021 		 * authority.
5022 		 */
5023 		char *strp = NULL;
5024 
5025 		/*
5026 		 * Don't allow the string to end with a colon.  If there is a
5027 		 * colon then there must be a subdomain provided.
5028 		 */
5029 		if (mb_name[strlen(mb_name) - 1] == ':') {
5030 			return (iSCSINameIqnSubdomainFormatError);
5031 		}
5032 
5033 		/* Date string */
5034 		strp = strtok(&mb_name[3], ".");
5035 		if (strp) {
5036 			char tmpYear[5], tmpMonth[3], *endPtr = NULL;
5037 			int year, month;
5038 
5039 			/* Date string should be in YYYY-MM format */
5040 			if (strlen(strp) != strlen("YYYY-MM") ||
5041 			    strp[4] != '-') {
5042 				return (iSCSINameIqnDateFormatError);
5043 			}
5044 
5045 			/*
5046 			 * Validate year.  Only validating that the
5047 			 * year can be converted to a number.  No
5048 			 * validation will be done on year's actual
5049 			 * value.
5050 			 */
5051 			(void) strncpy(tmpYear, strp, 4);
5052 			tmpYear[4] = '\0';
5053 
5054 			errno = 0;
5055 			year = strtol(tmpYear, &endPtr, 10);
5056 			if (errno != 0 || *endPtr != '\0' ||
5057 			    year < 0 || year > 9999) {
5058 				return (iSCSINameIqnInvalidYearError);
5059 			}
5060 
5061 			/*
5062 			 * Validate month is valid.
5063 			 */
5064 			(void) strncpy(tmpMonth, &strp[5], 2);
5065 			tmpMonth[2] = '\0';
5066 			errno = 0;
5067 			month = strtol(tmpMonth, &endPtr, 10);
5068 
5069 			if (errno != 0 || *endPtr != '\0' ||
5070 			    month < 1 || month > 12) {
5071 				return (iSCSINameIqnInvalidMonthError);
5072 			}
5073 
5074 			/*
5075 			 * A reversed FQDN needs to be provided.  We
5076 			 * will only check for a "." followed by more
5077 			 * than two or more characters.  The list of domains is
5078 			 * too large and changes too frequently to
5079 			 * add validation for.
5080 			 */
5081 			strp = strtok(NULL, ".");
5082 			if (!strp || strlen(strp) < 2) {
5083 				return (iSCSINameIqnFQDNError);
5084 			}
5085 
5086 			/* Name authority string */
5087 			strp = strtok(NULL, ":");
5088 			if (strp) {
5089 				return (iSCSINameCheckOK);
5090 			} else {
5091 				return (iSCSINameIqnFQDNError);
5092 			}
5093 		} else {
5094 			return (iSCSINameIqnFormatError);
5095 		}
5096 	} else if (strncmp(mb_name, ISCSI_EUI_NAME_PREFIX,
5097 	    strlen(ISCSI_EUI_NAME_PREFIX)) == 0) {
5098 		/* If name is of type EUI, change its length */
5099 
5100 		if (strlen(mb_name) != ISCSI_EUI_NAME_LEN) {
5101 			return (iSCSINameEUIFormatError);
5102 		}
5103 
5104 		for (tmp = mb_name + strlen(ISCSI_EUI_NAME_PREFIX) + 1;
5105 		    *tmp != '\0'; tmp++) {
5106 			if (isxdigit(*tmp)) {
5107 				continue;
5108 			}
5109 			return (iSCSINameEUIFormatError);
5110 		}
5111 
5112 		return (iSCSINameCheckOK);
5113 	} else {
5114 		return (iSCSINameUnknownType);
5115 	}
5116 }
5117 
5118 /*
5119  * This helper function could go into a utility module for general use.
5120  *
5121  * Returns:
5122  * B_TRUE is the numberStr is an unsigned natural number and within the
5123  * specified bound.
5124  * B_FALSE otherwise.
5125  */
5126 boolean_t
5127 isNaturalNumber(char *numberStr, uint32_t upperBound)
5128 {
5129 	int i;
5130 	int number_str_len;
5131 
5132 	if ((number_str_len = strlen(numberStr)) == 0) {
5133 		return (B_FALSE);
5134 	}
5135 
5136 	for (i = 0; i < number_str_len; i++) {
5137 		if (numberStr[i] < 060 || numberStr[i] > 071) {
5138 			return (B_FALSE);
5139 		}
5140 	}
5141 
5142 	if (atoi(numberStr) > upperBound) {
5143 		return (B_FALSE);
5144 	}
5145 
5146 	return (B_TRUE);
5147 }
5148 
5149 /*
5150  * This helper function could go into a utility module for general use.
5151  * It parses a target string in the format of:
5152  *
5153  * 	<target_name>,[<ip_address>[:port][,tpgt]]
5154  *
5155  * and creates wchar strings for target name and target address. It
5156  * also populates port and tpgt if found.
5157  *
5158  * Returns:
5159  * 	PARSE_TARGET_OK if parsing is successful.
5160  *	PARSE_TARGET_INVALID_TPGT if the specified tpgt is
5161  *	invalid.
5162  * 	PARSE_TARGET_INVALID_ADDR if the address specified is
5163  *	invalid.
5164  */
5165 int
5166 parseTarget(char *targetStr,
5167 		wchar_t *targetNameStr,
5168 		size_t targetNameStrLen,
5169 		boolean_t *targetAddressSpecified,
5170 		wchar_t *targetAddressStr,
5171 		size_t targetAddressStrLen,
5172 		uint16_t *port,
5173 		boolean_t *tpgtSpecified,
5174 		uint16_t *tpgt,
5175 		boolean_t *isIpv6)
5176 {
5177 	char *commaPos;
5178 	char *commaPos2;
5179 	char targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
5180 	int i;
5181 	int lowerCase;
5182 
5183 	(void) memset(targetNameStr, 0,
5184 	    targetNameStrLen * sizeof (wchar_t));
5185 	(void) memset(targetAddressStr, 0,
5186 	    targetAddressStrLen * sizeof (wchar_t));
5187 
5188 	commaPos = strchr(targetStr, ',');
5189 	if (commaPos != NULL) {
5190 		*commaPos = NULL;
5191 		commaPos++;
5192 		*targetAddressSpecified = B_TRUE;
5193 
5194 		/*
5195 		 * Checking of tpgt makes sense only when
5196 		 * the target address/port are specified.
5197 		 */
5198 		commaPos2 = strchr(commaPos, ',');
5199 		if (commaPos2 != NULL) {
5200 			*commaPos2 = NULL;
5201 			commaPos2++;
5202 			if (isNaturalNumber(commaPos2, ISCSI_MAX_TPGT_VALUE) ==
5203 			    B_TRUE) {
5204 				*tpgt = atoi(commaPos2);
5205 				*tpgtSpecified = B_TRUE;
5206 			} else {
5207 				return (PARSE_TARGET_INVALID_TPGT);
5208 			}
5209 		}
5210 
5211 		switch (parseAddress(commaPos, ISCSI_LISTEN_PORT,
5212 		    &targetAddress[0], MAX_ADDRESS_LEN + 1, port, isIpv6)) {
5213 		case PARSE_ADDR_PORT_OUT_OF_RANGE:
5214 			return (PARSE_TARGET_INVALID_ADDR);
5215 		case PARSE_ADDR_OK:
5216 			break;
5217 		default:
5218 			(void) fprintf(stderr, "%s: %s\n",
5219 			    cmdName, gettext("cannot parse target name"));
5220 			return (PARSE_TARGET_INVALID_ADDR);
5221 		}
5222 		(void) mbstowcs(targetAddressStr, targetAddress,
5223 		    targetAddressStrLen);
5224 		for (i = 0; targetAddressStr[i] != 0; i++) {
5225 			lowerCase = tolower(targetAddressStr[i]);
5226 			targetAddressStr[i] = lowerCase;
5227 		}
5228 	} else {
5229 		*targetAddressSpecified = B_FALSE;
5230 		*tpgtSpecified = B_FALSE;
5231 	}
5232 
5233 	(void) mbstowcs(targetNameStr, targetStr, targetNameStrLen);
5234 	for (i = 0; targetNameStr[i] != 0; i++) {
5235 		lowerCase = tolower(targetNameStr[i]);
5236 		targetNameStr[i] = lowerCase;
5237 	}
5238 
5239 	return (PARSE_TARGET_OK);
5240 }
5241 
5242 /*ARGSUSED*/
5243 static void
5244 listCHAPName(IMA_OID oid)
5245 {
5246 	IMA_INITIATOR_AUTHPARMS authParams;
5247 	IMA_STATUS status;
5248 	IMA_BYTE chapName [MAX_CHAP_NAME_LEN + 1];
5249 
5250 	/* Get Chap Name depending upon oid object type */
5251 	if (oid.objectType == IMA_OBJECT_TYPE_LHBA) {
5252 		status = IMA_GetInitiatorAuthParms(oid,
5253 		    IMA_AUTHMETHOD_CHAP, &authParams);
5254 	} else {
5255 		status = SUN_IMA_GetTargetAuthParms(oid,
5256 		    IMA_AUTHMETHOD_CHAP, &authParams);
5257 	}
5258 
5259 	(void) fprintf(stdout, "\n\t\t%s: ", gettext("CHAP Name"));
5260 
5261 	if (IMA_SUCCESS(status)) {
5262 		/*
5263 		 * Default chap name will be the node name.  The default will
5264 		 * be set by the driver.
5265 		 */
5266 		if (authParams.chapParms.nameLength != 0) {
5267 			(void) memset(chapName, 0, sizeof (chapName));
5268 			(void) memcpy(chapName, authParams.chapParms.name,
5269 			    authParams.chapParms.nameLength);
5270 			(void) fprintf(stdout, "%s", chapName);
5271 
5272 		} else {
5273 			(void) fprintf(stdout, "%s", "-");
5274 		}
5275 	} else {
5276 		(void) fprintf(stdout, "%s", "-");
5277 	}
5278 }
5279 
5280 /*
5281  * Prints out see manual page.
5282  * Called out through atexit(3C) so is always last thing displayed.
5283  */
5284 void
5285 seeMan(void)
5286 {
5287 	static int sent = 0;
5288 
5289 	if (sent)
5290 		return;
5291 
5292 	(void) fprintf(stdout, "%s %s(1M)\n",
5293 	    gettext("For more information, please see"), cmdName);
5294 
5295 	sent = 1;
5296 }
5297 
5298 
5299 /*
5300  * main calls a parser that checks syntax of the input command against
5301  * various rules tables.
5302  *
5303  * The parser provides usage feedback based upon same tables by calling
5304  * two usage functions, usage and subUsage, handling command and subcommand
5305  * usage respectively.
5306  *
5307  * The parser handles all printing of usage syntactical errors
5308  *
5309  * When syntax is successfully validated, the parser calls the associated
5310  * function using the subcommands table functions.
5311  *
5312  * Syntax is as follows:
5313  *	command subcommand [options] resource-type [<object>]
5314  *
5315  * The return value from the function is placed in funcRet
5316  */
5317 int
5318 main(int argc, char *argv[])
5319 {
5320 	synTables_t synTables;
5321 	char versionString[VERSION_STRING_MAX_LEN];
5322 	int ret;
5323 	int funcRet = 0;
5324 	void *subcommandArgs = NULL;
5325 
5326 	if (geteuid() != 0) {
5327 		(void) fprintf(stderr, "%s\n", gettext("permission denied"));
5328 		return (1);
5329 	}
5330 
5331 	/* set global command name */
5332 	cmdName = getExecBasename(argv[0]);
5333 
5334 	(void) snprintf(versionString, sizeof (versionString), "%s.%s",
5335 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
5336 	synTables.versionString = versionString;
5337 	synTables.longOptionTbl = &longOptions[0];
5338 	synTables.subcommandTbl = &subcommands[0];
5339 	synTables.objectTbl = &objects[0];
5340 	synTables.objectRulesTbl = &objectRules[0];
5341 	synTables.optionRulesTbl = &optionRules[0];
5342 
5343 	/* call the CLI parser */
5344 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
5345 	if (ret == -1) {
5346 		perror(cmdName);
5347 		ret = 1;
5348 	}
5349 
5350 	if (funcRet != 0) {
5351 		(void) fprintf(stderr, "%s: %s\n",
5352 		    cmdName, gettext("Unable to complete operation"));
5353 		ret = 1;
5354 	}
5355 	return (ret);
5356 }
5357