xref: /titanic_51/usr/src/cmd/iscsiadm/iscsiadm_main.c (revision 53a7b6b6763f5865522a76e5e887390a8f4777d7)
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 	char		*mb_name = NULL;
3592 	int		prefixlen = 0;
3593 
3594 	assert(funcRet != NULL);
3595 
3596 	/* Get boot session's info */
3597 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
3598 	if (iscsiBoot == IMA_TRUE) {
3599 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
3600 		if (!IMA_SUCCESS(status)) {
3601 			(void) fprintf(stderr, "%s: %s\n",
3602 			    cmdName, gettext("unable to get MPxIO info"
3603 			    " of root disk"));
3604 			*funcRet = 1;
3605 			return (1);
3606 		}
3607 	}
3608 
3609 	/* Find Sun initiator */
3610 	ret = sunInitiatorFind(&oid);
3611 	if (ret > 0) {
3612 		(void) fprintf(stderr, "%s: %s\n",
3613 		    cmdName, gettext("no initiator found"));
3614 	}
3615 
3616 	if (ret != 0) {
3617 		return (ret);
3618 	}
3619 
3620 	for (; optionList->optval; optionList++) {
3621 		switch (optionList->optval) {
3622 			case 'N':
3623 				if (strlen(optionList->optarg) >=
3624 				    MAX_ISCSI_NAME_LEN) {
3625 					(void) fprintf(stderr, "%s: %s %d\n",
3626 					    cmdName,
3627 					    gettext("name too long, \
3628 					    maximum length is:"),
3629 					    MAX_ISCSI_NAME_LEN);
3630 				}
3631 
3632 				/* Take the first operand as node name. */
3633 				(void) memset(&nodeName, 0,
3634 				    sizeof (IMA_NODE_NAME));
3635 				if (mbstowcs(nodeName, optionList->optarg,
3636 				    IMA_NODE_NAME_LEN) == (size_t)-1) {
3637 					(void) fprintf(stderr, "%s: %s\n",
3638 					    cmdName,
3639 					    gettext("conversion error"));
3640 					return (1);
3641 				}
3642 
3643 				prefixlen = strlen(ISCSI_IQN_NAME_PREFIX);
3644 				mb_name = (char *)calloc(1, prefixlen + 1);
3645 				if (mb_name == NULL) {
3646 					return (1);
3647 				}
3648 
3649 				if (wcstombs(mb_name, nodeName,
3650 				    prefixlen) == (size_t)-1) {
3651 					(void) fprintf(stderr, "%s: %s\n",
3652 					    cmdName,
3653 					    gettext("conversion error"));
3654 					(void) IMA_FreeMemory(mb_name);
3655 					return (1);
3656 				}
3657 				if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX,
3658 				    prefixlen) == 0) {
3659 					/*
3660 					 * For iqn format, we should map
3661 					 * the upper-case characters to
3662 					 * their lower-case equivalents.
3663 					 */
3664 					for (i = 0; nodeName[i] != 0; i++) {
3665 						lowerCase =
3666 						    tolower(nodeName[i]);
3667 						nodeName[i] = lowerCase;
3668 					}
3669 				}
3670 				(void) IMA_FreeMemory(mb_name);
3671 
3672 				/* Perform string profile checks */
3673 				nameCheckStatus =
3674 				    iSCSINameStringProfileCheck(nodeName);
3675 				iSCSINameCheckStatusDisplay(nameCheckStatus);
3676 				if (nameCheckStatus != iSCSINameCheckOK) {
3677 					*funcRet = 1; /* DIY message fix */
3678 					return (1);
3679 				}
3680 
3681 				/*
3682 				 * IMA_GetSharedNodeOid(&sharedNodeOid);
3683 				 * if (!IMA_SUCCESS(status)) {
3684 				 *   printLibError(status);
3685 				 *   return (INF_ERROR);
3686 				 * }
3687 				 */
3688 				if (iscsiBoot == IMA_TRUE) {
3689 					(void) fprintf(stderr, "%s: %s\n",
3690 					    cmdName, gettext("iscsi boot, not"
3691 					    " allowed to change"
3692 					    " initiator's name"));
3693 					return (1);
3694 				}
3695 				oid.objectType = IMA_OBJECT_TYPE_NODE;
3696 				status = IMA_SetNodeName(oid, nodeName);
3697 				if (!IMA_SUCCESS(status)) {
3698 					printLibError(status);
3699 					*funcRet = 1;
3700 					return (ret);
3701 				}
3702 				break;
3703 
3704 			case 'A':
3705 				if (iscsiBoot == IMA_TRUE) {
3706 					(void) fprintf(stderr, "%s: %s\n",
3707 					    cmdName, gettext("iscsi boot, not"
3708 					    " allowed to change"
3709 					    " initiator's alias"));
3710 					return (1);
3711 				}
3712 				/* Take the first operand as node alias. */
3713 				if (strlen(optionList->optarg) >=
3714 				    MAX_ISCSI_NAME_LEN) {
3715 					(void) fprintf(stderr, "%s: %s %d\n",
3716 					    cmdName,
3717 					    gettext("alias too long, maximum  \
3718 					    length is:"),
3719 					    MAX_ISCSI_NAME_LEN);
3720 				}
3721 
3722 				(void) memset(&nodeAlias, 0,
3723 				    sizeof (IMA_NODE_ALIAS));
3724 				if (mbstowcs(nodeAlias, optionList->optarg,
3725 				    IMA_NODE_ALIAS_LEN) == (size_t)-1) {
3726 					(void) fprintf(stderr, "%s: %s\n",
3727 					    cmdName,
3728 					    gettext("conversion error"));
3729 					return (1);
3730 				}
3731 
3732 				status = IMA_GetSharedNodeOid(&sharedNodeOid);
3733 				if (!IMA_SUCCESS(status)) {
3734 					printLibError(status);
3735 					*funcRet = 1;
3736 					return (ret);
3737 				}
3738 
3739 				status = IMA_SetNodeAlias(sharedNodeOid,
3740 				    nodeAlias);
3741 				if (!IMA_SUCCESS(status)) {
3742 					printLibError(status);
3743 					*funcRet = 1;
3744 					return (ret);
3745 				}
3746 				break;
3747 
3748 			case 'a':
3749 				if (iscsiBoot == IMA_TRUE) {
3750 					(void) fprintf(stderr, "%s: %s\n",
3751 					    cmdName, gettext("iscsi boot, not"
3752 					    " allowed to change authentication"
3753 					    " method"));
3754 					return (1);
3755 				}
3756 				if (modifyNodeAuthMethod(oid, options->optarg,
3757 				    funcRet) != 0) {
3758 					return (1);
3759 				}
3760 				break;
3761 
3762 			case 'R':
3763 				if (modifyNodeRadiusAccess(oid, options->optarg,
3764 				    funcRet) != 0) {
3765 					return (1);
3766 				}
3767 				break;
3768 
3769 			case 'r':
3770 				if (modifyNodeRadiusConfig(oid, options->optarg,
3771 				    funcRet) != 0) {
3772 					return (1);
3773 				}
3774 				break;
3775 
3776 			case 'P':
3777 				if (modifyNodeRadiusSharedSecret(oid, funcRet)
3778 				    != 0) {
3779 					return (1);
3780 				}
3781 				break;
3782 
3783 			case 'C':
3784 				if (iscsiBoot == IMA_TRUE) {
3785 					(void) fprintf(stderr, "%s: %s\n",
3786 					    cmdName, gettext("iscsi boot, not"
3787 					    " allowed to change CHAP secret"));
3788 					return (1);
3789 				}
3790 				if (modifyNodeAuthParam(oid, AUTH_PASSWORD,
3791 				    NULL, funcRet) != 0) {
3792 					return (1);
3793 				}
3794 				break;
3795 
3796 			case 'c':
3797 				if (iscsiBoot == IMA_TRUE) {
3798 					if (mpxioEnabled == IMA_FALSE) {
3799 						(void) fprintf(stderr,
3800 						    "%s: %s\n", cmdName,
3801 						    gettext("iscsi"
3802 						    " boot and MPxIO"
3803 						    " is disabled, not allowed"
3804 						    " to change number of"
3805 						    " sessions to be"
3806 						    " configured"));
3807 						return (1);
3808 					}
3809 				}
3810 				if (modifyConfiguredSessions(oid,
3811 				    optionList->optarg) != 0) {
3812 					if (iscsiBoot == IMA_TRUE) {
3813 						(void) fprintf(stderr,
3814 						    "%s: %s\n", cmdName,
3815 						    gettext("iscsi boot,"
3816 						    " fail to set configured"
3817 						    " session"));
3818 					}
3819 					return (1);
3820 				}
3821 				break;
3822 
3823 
3824 			case 'H':
3825 				if (iscsiBoot == IMA_TRUE) {
3826 					(void) fprintf(stderr, "%s: %s\n",
3827 					    cmdName, gettext("iscsi boot, not"
3828 					    " allowed to change CHAP name"));
3829 					return (1);
3830 				}
3831 				if (modifyNodeAuthParam(oid, AUTH_NAME,
3832 				    optionList->optarg, funcRet) != 0) {
3833 					return (1);
3834 				}
3835 				break;
3836 
3837 
3838 			case 'd':
3839 				if (iscsiBoot == IMA_TRUE) {
3840 					if (mpxioEnabled == IMA_FALSE) {
3841 						(void) fprintf(stderr,
3842 						    "%s: %s\n", cmdName,
3843 						    gettext("iscsi"
3844 						    " boot and MPxIO"
3845 						    " is disabled, not"
3846 						    " allowed to"
3847 						    " change initiator's"
3848 						    " login params"));
3849 						return (1);
3850 					}
3851 				}
3852 				if (setLoginParameter(oid, DATA_DIGEST,
3853 				    optionList->optarg) != 0) {
3854 					return (1);
3855 				}
3856 				break;
3857 
3858 			case 'h':
3859 				if (iscsiBoot == IMA_TRUE) {
3860 					if (mpxioEnabled == IMA_FALSE) {
3861 						(void) fprintf(stderr,
3862 						    "%s: %s\n", cmdName,
3863 						    gettext("iscsi"
3864 						    " boot and MPxIO"
3865 						    " is disabled, not"
3866 						    " allowed to"
3867 						    " change initiator's"
3868 						    " login params"));
3869 						return (1);
3870 					}
3871 				}
3872 				if (setLoginParameter(oid, HEADER_DIGEST,
3873 				    optionList->optarg) != 0) {
3874 					return (1);
3875 				}
3876 				break;
3877 
3878 			default:
3879 				(void) fprintf(stderr, "%s: %c: %s\n",
3880 				    cmdName, optionList->optval,
3881 				    gettext("unknown option"));
3882 				break;
3883 		}
3884 	}
3885 
3886 	return (ret);
3887 }
3888 
3889 /*
3890  * Modify target parameters
3891  */
3892 static int
3893 modifyTargetParam(cmdOptions_t *options, char *targetName, int *funcRet)
3894 {
3895 	IMA_OID oid;
3896 	IMA_OID targetOid;
3897 	IMA_STATUS status;
3898 	IMA_OID_LIST *targetList;
3899 	SUN_IMA_TARGET_PROPERTIES targetProps;
3900 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
3901 	wchar_t targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
3902 	int ret;
3903 	boolean_t found;
3904 	boolean_t targetAddressSpecified = B_TRUE;
3905 	boolean_t tpgtSpecified = B_FALSE;
3906 	boolean_t isIpv6 = B_FALSE;
3907 	int i;
3908 	iSCSINameCheckStatusType nameCheckStatus;
3909 	IMA_UINT16 port = 0;
3910 	IMA_UINT16 tpgt = 0;
3911 
3912 	IMA_NODE_NAME bootTargetName;
3913 	IMA_INITIATOR_AUTHPARMS bootTargetCHAP;
3914 	IMA_BOOL  iscsiBoot;
3915 	IMA_BOOL  mpxioEnabled;
3916 
3917 	cmdOptions_t *optionList = options;
3918 
3919 	assert(funcRet != NULL);
3920 
3921 	/* Find Sun initiator */
3922 	ret = sunInitiatorFind(&oid);
3923 	if (ret > 0) {
3924 		(void) fprintf(stderr, "%s: %s\n",
3925 		    cmdName, gettext("no initiator found"));
3926 	}
3927 
3928 	if (ret != 0) {
3929 		return (ret);
3930 	}
3931 
3932 	if (parseTarget(targetName,
3933 	    &wcInputObject[0],
3934 	    MAX_ISCSI_NAME_LEN + 1,
3935 	    &targetAddressSpecified,
3936 	    &targetAddress[0],
3937 	    SUN_IMA_IP_ADDRESS_PORT_LEN,
3938 	    &port,
3939 	    &tpgtSpecified,
3940 	    &tpgt,
3941 	    &isIpv6) != PARSE_TARGET_OK) {
3942 		return (1);
3943 	}
3944 
3945 	/* Perform string profile checks */
3946 	nameCheckStatus = iSCSINameStringProfileCheck(wcInputObject);
3947 	iSCSINameCheckStatusDisplay(nameCheckStatus);
3948 	if (nameCheckStatus != iSCSINameCheckOK) {
3949 		return (1);
3950 	}
3951 
3952 	status = IMA_GetTargetOidList(oid, &targetList);
3953 	if (!IMA_SUCCESS(status)) {
3954 		printLibError(status);
3955 		*funcRet = 1;
3956 		return (0);
3957 	}
3958 
3959 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
3960 	if (iscsiBoot == IMA_TRUE) {
3961 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
3962 		if (!IMA_SUCCESS(status)) {
3963 			(void) fprintf(stderr, "%s: %s\n",
3964 			    cmdName, gettext("unable to get MPxIO info"
3965 			    " of root disk"));
3966 			*funcRet = 1;
3967 			return (ret);
3968 		}
3969 		status = SUN_IMA_GetBootTargetName(bootTargetName);
3970 		if (!IMA_SUCCESS(status)) {
3971 			(void) fprintf(stderr, "%s: %s\n",
3972 			    cmdName, gettext("unable to get boot target's"
3973 			    " name"));
3974 			*funcRet = 1;
3975 			return (ret);
3976 		}
3977 		status = SUN_IMA_GetBootTargetAuthParams(&bootTargetCHAP);
3978 		if (!IMA_SUCCESS(status)) {
3979 			(void) fprintf(stderr, "%s: %s\n",
3980 			    cmdName, gettext("unable to get boot target's"
3981 			    " auth param"));
3982 			*funcRet = 1;
3983 			return (ret);
3984 		}
3985 	}
3986 
3987 	/* find target oid */
3988 	for (found = B_FALSE, i = 0; i < targetList->oidCount; i++) {
3989 		status = SUN_IMA_GetTargetProperties(targetList->oids[i],
3990 		    &targetProps);
3991 		if (!IMA_SUCCESS(status)) {
3992 			printLibError(status);
3993 			(void) IMA_FreeMemory(targetList);
3994 			*funcRet = 1;
3995 			return (ret);
3996 		}
3997 
3998 		/*
3999 		 * Compare the target name with the input name
4000 		 */
4001 		if ((targetNamesEqual(wcInputObject, targetProps.imaProps.name)
4002 		    == B_TRUE)) {
4003 			/*
4004 			 * For now, regardless of whether a target address
4005 			 * is specified, we return B_TRUE because
4006 			 * IMA_TARGET_PROPERTIES does not have a field for
4007 			 * specifying address.
4008 			 */
4009 			found = B_TRUE;
4010 			targetOid = targetList->oids[i];
4011 
4012 			if ((targetNamesEqual(bootTargetName, wcInputObject)
4013 			    == B_TRUE) && (iscsiBoot == IMA_TRUE)) {
4014 				/*
4015 				 * iscsi booting, need changed target param is
4016 				 * booting target, for auth param, not allow
4017 				 * to change, for others dependent on mpxio
4018 				 */
4019 
4020 				if ((optionList->optval == 'C') ||
4021 				    (optionList->optval == 'H') ||
4022 				    (optionList->optval == 'B') ||
4023 				    (optionList->optval == 'a')) {
4024 					/*
4025 					 * -C CHAP secret set
4026 					 * -H CHAP name set
4027 					 * -a authentication
4028 					 * -B bi-directional-authentication
4029 					 */
4030 					(void) fprintf(stderr, "%s: %s\n",
4031 					    cmdName, gettext("iscsi boot,"
4032 					    " not allowed to modify"
4033 					    " authentication parameters"
4034 					    "  of boot target"));
4035 					return (1);
4036 				}
4037 				if (mpxioEnabled == IMA_FALSE) {
4038 					(void) fprintf(stderr, "%s: %s\n",
4039 					    cmdName, gettext("iscsi boot and"
4040 					    " MPxIO is disabled, not allowed"
4041 					    " to modify boot target's"
4042 					    " parameters"));
4043 					return (1);
4044 				}
4045 
4046 			}
4047 
4048 			if (modifyIndividualTargetParam(optionList, targetOid,
4049 			    funcRet) != 0) {
4050 				return (ret);
4051 			}
4052 
4053 			/*
4054 			 * Even after finding a matched target, keep going
4055 			 * since there could be multiple target objects
4056 			 * associated with one target name in the system
4057 			 * because of different TPGTs.
4058 			 */
4059 		}
4060 	}
4061 
4062 	/* If the target OID cannot be found create one */
4063 	if (!found) {
4064 		status = SUN_IMA_CreateTargetOid(wcInputObject, &targetOid);
4065 		if (!IMA_SUCCESS(status)) {
4066 			printLibError(status);
4067 			(void) IMA_FreeMemory(targetList);
4068 			*funcRet = 1;
4069 			return (ret);
4070 		}
4071 		if (modifyIndividualTargetParam(optionList, targetOid,
4072 		    funcRet) != 0) {
4073 				return (ret);
4074 		}
4075 	}
4076 
4077 	(void) IMA_FreeMemory(targetList);
4078 	return (ret);
4079 }
4080 
4081 /*
4082  * Add one or more addresses
4083  */
4084 static int
4085 addAddress(int addrType, int operandLen, char *operand[], int *funcRet)
4086 {
4087 	IMA_STATUS status;
4088 	IMA_OID oid, addressOid;
4089 	SUN_IMA_TARGET_ADDRESS address;
4090 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
4091 	int ret;
4092 	int i;
4093 
4094 	assert(funcRet != NULL);
4095 
4096 	/* Find Sun initiator */
4097 	ret = sunInitiatorFind(&oid);
4098 	if (ret > 0) {
4099 		(void) fprintf(stderr, "%s: %s\n",
4100 		    cmdName, gettext("no initiator found"));
4101 	}
4102 
4103 	if (ret != 0) {
4104 		return (ret);
4105 	}
4106 
4107 	/*
4108 	 * Format of discovery address operand:
4109 	 *
4110 	 * <IP address|hostname>:<port>
4111 	 */
4112 	for (i = 0; i < operandLen; i++) {
4113 		/* initialize */
4114 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4115 		(void) memset(&address, 0, sizeof (address));
4116 
4117 		if (mbstowcs(wcInputObject, operand[i],
4118 		    (MAX_ADDRESS_LEN + 1)) == (size_t)-1) {
4119 			(void) fprintf(stderr, "%s: %s\n",
4120 			    cmdName, gettext("conversion error"));
4121 			ret = 1;
4122 			continue;
4123 		}
4124 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
4125 		    != 0) {
4126 			ret = 1;
4127 			continue;
4128 		}
4129 		if (addrType == DISCOVERY_ADDRESS) {
4130 			status = IMA_AddDiscoveryAddress(oid,
4131 			    address.imaStruct, &addressOid);
4132 			if (!IMA_SUCCESS(status)) {
4133 				printLibError(status);
4134 				*funcRet = 1;
4135 				return (ret);
4136 			}
4137 		} else if (addrType == ISNS_SERVER_ADDRESS) {
4138 			status = SUN_IMA_AddISNSServerAddress(address);
4139 			if (!IMA_SUCCESS(status)) {
4140 				printLibError(status);
4141 				*funcRet = 1;
4142 				return (ret);
4143 			}
4144 		}
4145 	}
4146 	return (ret);
4147 }
4148 
4149 /*
4150  * Add one or more static configuration targets
4151  */
4152 static int
4153 addStaticConfig(int operandLen, char *operand[], int *funcRet)
4154 {
4155 	int i;
4156 	boolean_t targetAddressSpecified = B_FALSE;
4157 	boolean_t tpgtSpecified = B_FALSE;
4158 	boolean_t isIpv6 = B_FALSE;
4159 	int ret;
4160 	int addrType;
4161 	IMA_STATUS status;
4162 	IMA_OID oid;
4163 	SUN_IMA_STATIC_DISCOVERY_TARGET staticConfig;
4164 	IMA_UINT16 port = 0;
4165 	IMA_UINT16 tpgt = 0;
4166 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
4167 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4168 	iSCSINameCheckStatusType nameCheckStatus;
4169 	char sAddr[SUN_IMA_IP_ADDRESS_PORT_LEN];
4170 
4171 	assert(funcRet != NULL);
4172 
4173 	/* Find Sun initiator */
4174 	ret = sunInitiatorFind(&oid);
4175 	if (ret > 0) {
4176 		(void) fprintf(stderr, "%s: %s\n",
4177 		    cmdName, gettext("no initiator found"));
4178 	}
4179 
4180 	if (ret != 0) {
4181 		return (ret);
4182 	}
4183 
4184 	/*
4185 	 * Format of static config operand:
4186 	 *  <target-name>,<IP address|hostname>[:port][,tpgt]
4187 	 */
4188 	for (i = 0; i < operandLen; i++) {
4189 		if (parseTarget(operand[i],
4190 		    &staticTargetName[0],
4191 		    MAX_ISCSI_NAME_LEN + 1,
4192 		    &targetAddressSpecified,
4193 		    &staticTargetAddress[0],
4194 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4195 		    &port,
4196 		    &tpgtSpecified,
4197 		    &tpgt,
4198 		    &isIpv6) != PARSE_TARGET_OK) {
4199 			ret = 1;
4200 			continue;
4201 		}
4202 
4203 		if (targetAddressSpecified != B_TRUE) {
4204 			(void) fprintf(stderr, "%s: %s\n",
4205 			    cmdName, gettext("missing target address"));
4206 			*funcRet = 1; /* DIY message fix */
4207 			return (1);
4208 		}
4209 		/* Perform string profile checks */
4210 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4211 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4212 		if (nameCheckStatus != iSCSINameCheckOK) {
4213 			*funcRet = 1; /* DIY message fix */
4214 			return (1);
4215 		}
4216 		(void) wcsncpy(staticConfig.targetName, staticTargetName,
4217 		    MAX_ISCSI_NAME_LEN + 1);
4218 
4219 		(void) wcstombs(sAddr, staticTargetAddress, sizeof (sAddr));
4220 
4221 		if (isIpv6 == B_TRUE) {
4222 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4223 			    id.ipAddress.ipv4Address = B_FALSE;
4224 			addrType = AF_INET6;
4225 		} else {
4226 			staticConfig.targetAddress.imaStruct.hostnameIpAddress.
4227 			    id.ipAddress.ipv4Address = B_TRUE;
4228 			addrType = AF_INET;
4229 		}
4230 
4231 		if (inet_pton(addrType, sAddr, staticConfig.targetAddress.
4232 		    imaStruct.hostnameIpAddress.id.ipAddress.ipAddress) != 1) {
4233 			(void) fprintf(stderr, "%s: %s\n",
4234 			    cmdName, gettext("static config conversion error"));
4235 			ret = 1;
4236 			continue;
4237 		}
4238 
4239 		staticConfig.targetAddress.imaStruct.portNumber = port;
4240 		if (tpgtSpecified == B_TRUE) {
4241 			staticConfig.targetAddress.defaultTpgt = B_FALSE;
4242 			staticConfig.targetAddress.tpgt = tpgt;
4243 		} else {
4244 			staticConfig.targetAddress.defaultTpgt = B_TRUE;
4245 			staticConfig.targetAddress.tpgt = 0;
4246 		}
4247 
4248 		status = SUN_IMA_AddStaticTarget(oid, staticConfig, &oid);
4249 		if (!IMA_SUCCESS(status)) {
4250 			printLibError(status);
4251 			*funcRet = 1;
4252 			return (1);
4253 		}
4254 	}
4255 	return (ret);
4256 }
4257 
4258 /*
4259  * Remove one or more addresses
4260  */
4261 static int
4262 removeAddress(int addrType, int operandLen, char *operand[], int *funcRet)
4263 {
4264 	IMA_STATUS status;
4265 	IMA_OID initiatorOid;
4266 	SUN_IMA_TARGET_ADDRESS address;
4267 	wchar_t wcInputObject[MAX_ADDRESS_LEN + 1];
4268 	int ret;
4269 	int i;
4270 
4271 	assert(funcRet != NULL);
4272 
4273 	/* Find Sun initiator */
4274 	ret = sunInitiatorFind(&initiatorOid);
4275 	if (ret > 0) {
4276 		(void) fprintf(stderr, "%s: %s\n",
4277 		    cmdName, gettext("no initiator found"));
4278 	}
4279 
4280 	if (ret != 0) {
4281 		return (ret);
4282 	}
4283 
4284 	for (i = 0; i < operandLen; i++) {
4285 		/* initialize */
4286 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4287 		(void) memset(&address, 0, sizeof (address));
4288 
4289 		if (mbstowcs(wcInputObject, operand[i],
4290 		    MAX_ADDRESS_LEN + 1) == (size_t)-1) {
4291 			(void) fprintf(stderr, "%s: %s\n",
4292 			    cmdName, gettext("conversion error"));
4293 			ret = 1;
4294 			continue;
4295 		}
4296 
4297 		if (getTargetAddress(addrType, operand[i], &address.imaStruct)
4298 		    != 0) {
4299 			ret = 1;
4300 			continue;
4301 		}
4302 
4303 		if (addrType == DISCOVERY_ADDRESS) {
4304 			status = SUN_IMA_RemoveDiscoveryAddress(address);
4305 			if (!IMA_SUCCESS(status)) {
4306 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4307 					(void) fprintf(stderr, "%s: %s\n",
4308 					    operand[i], gettext("not found"));
4309 				} else {
4310 					printLibError(status);
4311 				}
4312 				*funcRet = 1;
4313 			}
4314 		} else {
4315 			status = SUN_IMA_RemoveISNSServerAddress(address);
4316 			if (!IMA_SUCCESS(status)) {
4317 				printLibError(status);
4318 				*funcRet = 1;
4319 			}
4320 		}
4321 	}
4322 	return (ret);
4323 }
4324 
4325 /*
4326  * Remove one or more static configuration targets
4327  */
4328 static int
4329 removeStaticConfig(int operandLen, char *operand[], int *funcRet)
4330 {
4331 	IMA_STATUS status;
4332 	IMA_OID initiatorOid;
4333 	IMA_OID_LIST *staticTargetList;
4334 	SUN_IMA_STATIC_TARGET_PROPERTIES staticTargetProps;
4335 	wchar_t staticTargetName[MAX_ISCSI_NAME_LEN + 1];
4336 	wchar_t staticTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4337 	int ret;
4338 	boolean_t atLeastFoundOne;
4339 	boolean_t matched;
4340 	boolean_t targetAddressSpecified = B_TRUE;
4341 	boolean_t tpgtSpecified = B_FALSE;
4342 	boolean_t isIpv6 = B_FALSE;
4343 	int i, j;
4344 	IMA_UINT16 port = 0;
4345 	IMA_UINT16 tpgt = 0;
4346 	iSCSINameCheckStatusType nameCheckStatus;
4347 	char tmpStr[SUN_IMA_IP_ADDRESS_PORT_LEN];
4348 	wchar_t tmpTargetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
4349 
4350 	assert(funcRet != NULL);
4351 
4352 	/* Find Sun initiator */
4353 	ret = sunInitiatorFind(&initiatorOid);
4354 	if (ret > 0) {
4355 		(void) fprintf(stderr, "%s: %s\n",
4356 		    cmdName, gettext("no initiator found"));
4357 	}
4358 
4359 	if (ret != 0) {
4360 		return (ret);
4361 	}
4362 
4363 	status = IMA_GetStaticDiscoveryTargetOidList(initiatorOid,
4364 	    &staticTargetList);
4365 	if (!IMA_SUCCESS(status)) {
4366 		printLibError(status);
4367 		*funcRet = 1;
4368 		return (ret);
4369 	}
4370 
4371 	for (i = 0; i < operandLen; i++) {
4372 		if (parseTarget(operand[i],
4373 		    &staticTargetName[0],
4374 		    MAX_ISCSI_NAME_LEN + 1,
4375 		    &targetAddressSpecified,
4376 		    &staticTargetAddress[0],
4377 		    SUN_IMA_IP_ADDRESS_PORT_LEN,
4378 		    &port,
4379 		    &tpgtSpecified,
4380 		    &tpgt,
4381 		    &isIpv6) != PARSE_TARGET_OK) {
4382 			ret = 1;
4383 			continue;
4384 		}
4385 
4386 		/* Perform string profile checks */
4387 		nameCheckStatus = iSCSINameStringProfileCheck(staticTargetName);
4388 		iSCSINameCheckStatusDisplay(nameCheckStatus);
4389 		if (nameCheckStatus != iSCSINameCheckOK) {
4390 			return (1);
4391 		}
4392 
4393 		for (atLeastFoundOne = B_FALSE, j = 0;
4394 		    j < staticTargetList->oidCount;
4395 		    j++) {
4396 			IMA_UINT16 stpgt;
4397 
4398 			matched = B_FALSE;
4399 			status = SUN_IMA_GetStaticTargetProperties(
4400 			    staticTargetList->oids[j], &staticTargetProps);
4401 			if (!IMA_SUCCESS(status)) {
4402 				if (status == IMA_ERROR_OBJECT_NOT_FOUND) {
4403 					/*
4404 					 * When removing multiple static-config
4405 					 * entries we need to expect get
4406 					 * failures. These failures occur when
4407 					 * we are trying to get entry
4408 					 * information we have just removed.
4409 					 * Ignore the failure and continue.
4410 					 */
4411 					ret = 1;
4412 					continue;
4413 				} else {
4414 					printLibError(status);
4415 					(void) IMA_FreeMemory(staticTargetList);
4416 					*funcRet = 1;
4417 					return (ret);
4418 				}
4419 			}
4420 
4421 			stpgt =
4422 			    staticTargetProps.staticTarget.targetAddress.tpgt;
4423 
4424 			/*
4425 			 * Compare the static target name with the input if
4426 			 * one was input
4427 			 */
4428 			if ((targetNamesEqual(
4429 			    staticTargetProps.staticTarget.targetName,
4430 			    staticTargetName) == B_TRUE)) {
4431 				if (targetAddressSpecified == B_FALSE) {
4432 					matched = B_TRUE;
4433 				} else {
4434 
4435 					if (staticTargetProps.staticTarget.
4436 					    targetAddress.imaStruct.
4437 					    hostnameIpAddress.
4438 					    id.ipAddress.ipv4Address ==
4439 					    IMA_TRUE) {
4440 						(void) inet_ntop(AF_INET,
4441 						    staticTargetProps.
4442 						    staticTarget.targetAddress.
4443 						    imaStruct.hostnameIpAddress.
4444 						    id.ipAddress.ipAddress,
4445 						    tmpStr,
4446 						    sizeof (tmpStr));
4447 					} else {
4448 						(void) inet_ntop(AF_INET6,
4449 						    staticTargetProps.
4450 						    staticTarget.targetAddress.
4451 						    imaStruct.hostnameIpAddress.
4452 						    id.ipAddress.ipAddress,
4453 						    tmpStr,
4454 						    sizeof (tmpStr));
4455 					}
4456 
4457 					if (mbstowcs(tmpTargetAddress, tmpStr,
4458 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4459 					    (size_t)-1) {
4460 						(void) fprintf(stderr,
4461 						    "%s: %s\n",
4462 						    cmdName, gettext(
4463 						    "conversion error"));
4464 						ret = 1;
4465 						continue;
4466 					}
4467 
4468 					if ((wcsncmp(tmpTargetAddress,
4469 					    staticTargetAddress,
4470 					    SUN_IMA_IP_ADDRESS_PORT_LEN) ==
4471 					    0) && (staticTargetProps.
4472 					    staticTarget.targetAddress.
4473 					    imaStruct.portNumber == port)) {
4474 						if (tpgtSpecified == B_FALSE) {
4475 							matched = B_TRUE;
4476 						} else {
4477 							if (tpgt == stpgt) {
4478 								matched =
4479 								    B_TRUE;
4480 							}
4481 						}
4482 					}
4483 				}
4484 
4485 				if (matched) {
4486 					status =
4487 					    IMA_RemoveStaticDiscoveryTarget(
4488 					    staticTargetList->oids[j]);
4489 					if (!IMA_SUCCESS(status)) {
4490 						printLibError(status);
4491 						*funcRet = 1;
4492 						return (ret);
4493 					}
4494 					atLeastFoundOne = B_TRUE;
4495 				}
4496 			}
4497 		}
4498 		if (!atLeastFoundOne) {
4499 			(void) fprintf(stderr, gettext("%ws,%ws: %s\n"),
4500 			    staticTargetName, staticTargetAddress,
4501 			    gettext("not found"));
4502 		}
4503 	}
4504 	return (ret);
4505 }
4506 
4507 /*
4508  * Remove one or more target params.
4509  */
4510 static int
4511 removeTargetParam(int operandLen, char *operand[], int *funcRet)
4512 {
4513 	char *commaPos;
4514 	IMA_STATUS status;
4515 	IMA_OID initiatorOid;
4516 	IMA_OID_LIST *targetList;
4517 	SUN_IMA_TARGET_PROPERTIES targetProps;
4518 	wchar_t wcInputObject[MAX_ISCSI_NAME_LEN + 1];
4519 	int ret;
4520 	boolean_t found;
4521 	int i, j;
4522 	IMA_NODE_NAME bootTargetName;
4523 	IMA_BOOL	iscsiBoot = IMA_FALSE;
4524 	IMA_BOOL	mpxioEnabled = IMA_FALSE;
4525 
4526 	/* Get boot session's info */
4527 	(void) SUN_IMA_GetBootIscsi(&iscsiBoot);
4528 	if (iscsiBoot == IMA_TRUE) {
4529 		status = SUN_IMA_GetBootMpxio(&mpxioEnabled);
4530 		if (!IMA_SUCCESS(status)) {
4531 			(void) fprintf(stderr, "%s: %s\n",
4532 			    cmdName, gettext("unable to get MPxIO info of"
4533 			    " root disk"));
4534 			*funcRet = 1;
4535 			return (1);
4536 		}
4537 		status = SUN_IMA_GetBootTargetName(bootTargetName);
4538 		if (!IMA_SUCCESS(status)) {
4539 			(void) fprintf(stderr, "%s: %s\n",
4540 			    cmdName, gettext("unable to get boot"
4541 			    " target's name"));
4542 			*funcRet = 1;
4543 			return (1);
4544 		}
4545 	}
4546 
4547 	assert(funcRet != NULL);
4548 
4549 	/* Find Sun initiator */
4550 	ret = sunInitiatorFind(&initiatorOid);
4551 	if (ret > 0) {
4552 		(void) fprintf(stderr, "%s: %s\n",
4553 		    cmdName, gettext("no initiator found"));
4554 	}
4555 
4556 	if (ret != 0) {
4557 		return (ret);
4558 	}
4559 
4560 	status = IMA_GetTargetOidList(initiatorOid, &targetList);
4561 	if (!IMA_SUCCESS(status)) {
4562 		printLibError(status);
4563 		*funcRet = 1;
4564 		return (ret);
4565 	}
4566 
4567 	for (i = 0; i < operandLen; i++) {
4568 		/* initialize */
4569 		commaPos = strchr(operand[i], ',');
4570 		if (commaPos) {
4571 			/* Ignore IP address. */
4572 			*commaPos = NULL;
4573 		}
4574 		(void) memset(&wcInputObject[0], 0, sizeof (wcInputObject));
4575 		if (mbstowcs(wcInputObject, operand[i],
4576 		    MAX_ISCSI_NAME_LEN + 1) == (size_t)-1) {
4577 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4578 			    gettext("conversion error"));
4579 			ret = 1;
4580 			continue;
4581 		}
4582 
4583 		for (found = B_FALSE, j = 0; j < targetList->oidCount;
4584 		    j++) {
4585 			status = SUN_IMA_GetTargetProperties(
4586 			    targetList->oids[j], &targetProps);
4587 			if (!IMA_SUCCESS(status)) {
4588 				printLibError(status);
4589 				(void) IMA_FreeMemory(targetList);
4590 				*funcRet = 1;
4591 				return (ret);
4592 			}
4593 
4594 			/*
4595 			 * Compare the target name with the input if
4596 			 * one was input
4597 			 */
4598 			if (targetNamesEqual(targetProps.imaProps.name,
4599 			    wcInputObject) == B_TRUE) {
4600 				found = B_TRUE;
4601 				if ((targetNamesEqual(bootTargetName,
4602 				    wcInputObject) == B_TRUE) &&
4603 				    (iscsiBoot == IMA_TRUE)) {
4604 					/*
4605 					 * iscsi booting, need changed target
4606 					 * param is booting target, booting
4607 					 * session mpxio disabled, not
4608 					 * allow to update
4609 					 */
4610 					if (mpxioEnabled == IMA_FALSE) {
4611 						(void) fprintf(stderr,
4612 						    "%s: %s\n", cmdName,
4613 						    gettext("iscsi boot"
4614 						    " with MPxIO disabled,"
4615 						    " not allowed to remove"
4616 						    " boot sess param"));
4617 						ret = 1;
4618 						continue;
4619 					}
4620 
4621 				}
4622 
4623 				status = SUN_IMA_RemoveTargetParam(
4624 				    targetList->oids[j]);
4625 				if (!IMA_SUCCESS(status)) {
4626 					printLibError(status);
4627 					(void) IMA_FreeMemory(targetList);
4628 					*funcRet = 1;
4629 					return (ret);
4630 				}
4631 			}
4632 		}
4633 		if (!found) {
4634 			/* Silently ignoring it? */
4635 			(void) fprintf(stderr, gettext("%ws: %s\n"),
4636 			    wcInputObject, gettext("not found"));
4637 		}
4638 	}
4639 
4640 	(void) IMA_FreeMemory(targetList);
4641 	return (ret);
4642 }
4643 
4644 /*ARGSUSED*/
4645 static int
4646 addFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4647     void *addArgs, int *funcRet)
4648 {
4649 	int ret;
4650 
4651 	assert(funcRet != NULL);
4652 
4653 	switch (object) {
4654 		case DISCOVERY_ADDRESS:
4655 		case ISNS_SERVER_ADDRESS:
4656 			ret = addAddress(object, operandLen, operand, funcRet);
4657 			break;
4658 		case STATIC_CONFIG:
4659 			ret = addStaticConfig(operandLen, operand, funcRet);
4660 			break;
4661 		default:
4662 			(void) fprintf(stderr, "%s: %s\n",
4663 			    cmdName, gettext("unknown object"));
4664 			ret = 1;
4665 			break;
4666 	}
4667 	return (ret);
4668 }
4669 
4670 /*ARGSUSED*/
4671 static int
4672 listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4673     void *addArgs, int *funcRet)
4674 {
4675 	int ret;
4676 
4677 	assert(funcRet != NULL);
4678 
4679 	switch (object) {
4680 	case DISCOVERY:
4681 		ret = listDiscovery(funcRet);
4682 		break;
4683 	case DISCOVERY_ADDRESS:
4684 		ret = listDiscoveryAddress(operandLen, operand, options,
4685 		    funcRet);
4686 		break;
4687 	case ISNS_SERVER_ADDRESS:
4688 		ret = listISNSServerAddress(operandLen, operand, options,
4689 		    funcRet);
4690 		break;
4691 	case NODE:
4692 		ret = listNode(funcRet);
4693 		break;
4694 	case STATIC_CONFIG:
4695 		ret = listStaticConfig(operandLen, operand, funcRet);
4696 		break;
4697 	case TARGET:
4698 		ret = listTarget(operandLen, operand, options, funcRet);
4699 		break;
4700 	case TARGET_PARAM:
4701 		ret = listTargetParam(operandLen, operand, options, funcRet);
4702 		break;
4703 	default:
4704 		(void) fprintf(stderr, "%s: %s\n",
4705 		    cmdName, gettext("unknown object"));
4706 		ret = 1;
4707 		break;
4708 	}
4709 	return (ret);
4710 }
4711 
4712 /*ARGSUSED*/
4713 static int
4714 modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4715     void *addArgs, int *funcRet)
4716 {
4717 	int ret, i;
4718 
4719 	assert(funcRet != NULL);
4720 
4721 	switch (object) {
4722 	case DISCOVERY:
4723 		ret = modifyDiscovery(options, funcRet);
4724 		break;
4725 	case NODE:
4726 		ret = modifyNode(options, funcRet);
4727 		break;
4728 	case TARGET_PARAM:
4729 		i = 0;
4730 		while (operand[i]) {
4731 			ret = modifyTargetParam(options, operand[i], funcRet);
4732 
4733 			if (ret) {
4734 				(void) fprintf(stderr, "%s: %s: %s\n",
4735 				    cmdName, gettext("modify failed"),
4736 				    operand[i]);
4737 				return (ret);
4738 			}
4739 			i++;
4740 		}
4741 
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 /*ARGSUSED*/
4753 static int
4754 removeFunc(int operandLen, char *operand[], int object, cmdOptions_t *options,
4755     void *addArgs, int *funcRet)
4756 {
4757 	int ret;
4758 
4759 	switch (object) {
4760 		case DISCOVERY_ADDRESS:
4761 		case ISNS_SERVER_ADDRESS:
4762 			ret = removeAddress(object, operandLen, operand,
4763 			    funcRet);
4764 			break;
4765 		case STATIC_CONFIG:
4766 			ret = removeStaticConfig(operandLen, operand, funcRet);
4767 			break;
4768 		case TARGET_PARAM:
4769 			ret = removeTargetParam(operandLen, operand, funcRet);
4770 			break;
4771 		default:
4772 			(void) fprintf(stderr, "%s: %s\n",
4773 			    cmdName, gettext("unknown object"));
4774 			ret = 1;
4775 			break;
4776 	}
4777 	return (ret);
4778 }
4779 
4780 static void
4781 iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status)
4782 {
4783 	switch (status) {
4784 		case iSCSINameLenZero:
4785 			(void) fprintf(stderr, "%s: %s\n",
4786 			    cmdName, gettext("empty iSCSI name."));
4787 			break;
4788 		case iSCSINameLenExceededMax:
4789 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4790 			    gettext("iSCSI name exceeded maximum length."));
4791 			break;
4792 		case iSCSINameUnknownType:
4793 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4794 			    gettext("unknown iSCSI name type."));
4795 			break;
4796 		case iSCSINameInvalidCharacter:
4797 			(void) fprintf(stderr, "%s: %s\n",
4798 			    cmdName,
4799 			    gettext("iSCSI name invalid character used"));
4800 			break;
4801 		case iSCSINameIqnFormatError:
4802 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4803 			    gettext("iqn formatting error."));
4804 			break;
4805 		case iSCSINameIqnDateFormatError:
4806 			(void) fprintf(stderr, "%s: %s\n",
4807 			    cmdName, gettext("invalid iqn date." \
4808 			    "  format is: YYYY-MM"));
4809 			break;
4810 		case iSCSINameIqnSubdomainFormatError:
4811 			(void) fprintf(stderr, "%s: %s\n",
4812 			    cmdName, gettext("missing subdomain after \":\""));
4813 			break;
4814 		case iSCSINameIqnInvalidYearError:
4815 			(void) fprintf(stderr, "%s: %s\n",
4816 			    cmdName, gettext("invalid year"));
4817 			break;
4818 		case iSCSINameIqnInvalidMonthError:
4819 			(void) fprintf(stderr, "%s: %s\n",
4820 			    cmdName, gettext("invalid month"));
4821 			break;
4822 		case iSCSINameIqnFQDNError:
4823 			(void) fprintf(stderr, "%s: %s\n",
4824 			    cmdName, gettext("missing reversed fully qualified"\
4825 			    " domain name"));
4826 			break;
4827 		case iSCSINameEUIFormatError:
4828 			(void) fprintf(stderr, "%s: %s\n", cmdName,
4829 			    gettext("eui formatting error."));
4830 			break;
4831 	}
4832 }
4833 
4834 /*
4835  * A convenient function to modify the target parameters of an individual
4836  * target.
4837  *
4838  * Return 0 if successful
4839  * Return 1 if failed
4840  */
4841 static int
4842 modifyIndividualTargetParam(cmdOptions_t *optionList, IMA_OID targetOid,
4843     int *funcRet)
4844 {
4845 	assert(funcRet != NULL);
4846 
4847 	for (; optionList->optval; optionList++) {
4848 		switch (optionList->optval) {
4849 			case 'a':
4850 				if (modifyTargetAuthMethod(targetOid,
4851 				    optionList->optarg, funcRet) != 0) {
4852 					return (1);
4853 				}
4854 				break;
4855 			case 'B':
4856 				if (modifyTargetBidirAuthFlag(targetOid,
4857 				    optionList->optarg, funcRet) != 0) {
4858 					return (1);
4859 				}
4860 				break;
4861 			case 'C':
4862 				if (modifyTargetAuthParam(targetOid,
4863 				    AUTH_PASSWORD, NULL, funcRet) != 0) {
4864 					return (1);
4865 				}
4866 				break;
4867 			case 'd':
4868 				if (setLoginParameter(targetOid, DATA_DIGEST,
4869 				    optionList->optarg) != 0) {
4870 					return (1);
4871 				}
4872 				break;
4873 			case 'h':
4874 				if (setLoginParameter(targetOid, HEADER_DIGEST,
4875 				    optionList->optarg) != 0) {
4876 					return (1);
4877 				}
4878 				break;
4879 			case 'p':
4880 				/* Login parameter */
4881 				if (setLoginParameters(targetOid,
4882 				    optionList->optarg) != 0) {
4883 					return (1);
4884 				}
4885 				break;
4886 			case 'c':
4887 				/* Modify configure sessions */
4888 				if (modifyConfiguredSessions(targetOid,
4889 				    optionList->optarg) != 0) {
4890 					return (1);
4891 				}
4892 				break;
4893 			case 'H':
4894 				if (modifyTargetAuthParam(targetOid, AUTH_NAME,
4895 				    optionList->optarg, funcRet) != 0) {
4896 					return (1);
4897 				}
4898 				break;
4899 		}
4900 	}
4901 
4902 	return (0);
4903 }
4904 
4905 /*
4906  * This helper function could go into a utility module for general use.
4907  */
4908 static int
4909 parseAddress(char *address_port_str,
4910     uint16_t defaultPort,
4911     char *address_str,
4912     size_t address_str_len,
4913     uint16_t *port,
4914     boolean_t *isIpv6)
4915 {
4916 	char port_str[64];
4917 	int tmp_port;
4918 	char *errchr;
4919 
4920 	if (address_port_str[0] == '[') {
4921 		/* IPv6 address */
4922 		char *close_bracket_pos;
4923 		close_bracket_pos = strchr(address_port_str, ']');
4924 		if (!close_bracket_pos) {
4925 			syslog(LOG_USER|LOG_DEBUG,
4926 			    "IP address format error: %s\n", address_str);
4927 			return (PARSE_ADDR_MISSING_CLOSING_BRACKET);
4928 		}
4929 
4930 		*close_bracket_pos = NULL;
4931 		(void) strlcpy(address_str, &address_port_str[1],
4932 		    address_str_len);
4933 
4934 		/* Extract the port number */
4935 		close_bracket_pos++;
4936 		if (*close_bracket_pos == ':') {
4937 			close_bracket_pos++;
4938 			if (*close_bracket_pos != NULL) {
4939 				(void) strlcpy(port_str, close_bracket_pos, 64);
4940 				tmp_port = strtol(port_str, &errchr, 10);
4941 				if (tmp_port == 0 && errchr != NULL) {
4942 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4943 					    cmdName, address_str,
4944 					    close_bracket_pos,
4945 					    gettext("port number invalid"));
4946 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4947 				}
4948 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4949 				    (tmp_port < 0)) {
4950 					/* Port number out of range */
4951 					syslog(LOG_USER|LOG_DEBUG,
4952 					    "Specified port out of range: %d",
4953 					    tmp_port);
4954 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4955 				} else {
4956 					*port = (uint16_t)tmp_port;
4957 				}
4958 			} else {
4959 				*port = defaultPort;
4960 			}
4961 		} else {
4962 			*port = defaultPort;
4963 		}
4964 
4965 		*isIpv6 = B_TRUE;
4966 	} else {
4967 		/* IPv4 address */
4968 		char *colon_pos;
4969 		colon_pos = strchr(address_port_str, ':');
4970 		if (!colon_pos) {
4971 			/* No port number specified. */
4972 			*port = defaultPort;
4973 			(void) strlcpy(address_str, address_port_str,
4974 			    address_str_len);
4975 		} else {
4976 			*colon_pos = (char)NULL;
4977 			(void) strlcpy(address_str, address_port_str,
4978 			    address_str_len);
4979 
4980 			/* Extract the port number */
4981 			colon_pos++;
4982 			if (*colon_pos != NULL) {
4983 
4984 				(void) strlcpy(port_str, colon_pos, 64);
4985 				tmp_port = strtol(port_str, &errchr, 10);
4986 				if (tmp_port == 0 && errchr != NULL) {
4987 					(void) fprintf(stderr, "%s: %s:%s %s\n",
4988 					    cmdName, address_str, colon_pos,
4989 					    gettext("port number invalid"));
4990 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4991 				}
4992 				if ((tmp_port > 0) && (tmp_port > USHRT_MAX) ||
4993 				    (tmp_port < 0)) {
4994 					/* Port number out of range */
4995 					syslog(LOG_USER|LOG_DEBUG,
4996 					    "Specified port out of range: %d",
4997 					    tmp_port);
4998 					return (PARSE_ADDR_PORT_OUT_OF_RANGE);
4999 				} else {
5000 					*port = (uint16_t)tmp_port;
5001 				}
5002 			} else {
5003 				*port = defaultPort;
5004 			}
5005 		}
5006 
5007 		*isIpv6 = B_FALSE;
5008 	}
5009 
5010 	return (PARSE_ADDR_OK);
5011 }
5012 
5013 /*
5014  * This helper function could go into a utility module for general use.
5015  */
5016 iSCSINameCheckStatusType
5017 iSCSINameStringProfileCheck(wchar_t *name)
5018 {
5019 	char mb_name[MAX_ISCSI_NAME_LEN + 1];
5020 	size_t name_len;
5021 	char *tmp;
5022 
5023 	(void) wcstombs(mb_name, name, MAX_ISCSI_NAME_LEN + 1);
5024 
5025 	if ((name_len = strlen(mb_name)) == 0) {
5026 		return (iSCSINameLenZero);
5027 	} else if (name_len > MAX_ISCSI_NAME_LEN) {
5028 		return (iSCSINameLenExceededMax);
5029 	}
5030 
5031 	/*
5032 	 * check for invalid characters
5033 	 * According to RFC 3722 iSCSI name must be either a letter,
5034 	 * a digit or one of the following '-' '.' ':'
5035 	 */
5036 	for (tmp = mb_name; *tmp != NULL; tmp++) {
5037 		if ((isalnum(*tmp) == 0) &&
5038 		    (*tmp != '-') &&
5039 		    (*tmp != '.') &&
5040 		    (*tmp != ':')) {
5041 			return (iSCSINameInvalidCharacter);
5042 		}
5043 	}
5044 
5045 	if (strncmp(mb_name, ISCSI_IQN_NAME_PREFIX,
5046 	    strlen(ISCSI_IQN_NAME_PREFIX)) == 0) {
5047 		/*
5048 		 * If name is of type iqn, check date string and naming
5049 		 * authority.
5050 		 */
5051 		char *strp = NULL;
5052 
5053 		/*
5054 		 * Don't allow the string to end with a colon.  If there is a
5055 		 * colon then there must be a subdomain provided.
5056 		 */
5057 		if (mb_name[strlen(mb_name) - 1] == ':') {
5058 			return (iSCSINameIqnSubdomainFormatError);
5059 		}
5060 
5061 		/* Date string */
5062 		strp = strtok(&mb_name[3], ".");
5063 		if (strp) {
5064 			char tmpYear[5], tmpMonth[3], *endPtr = NULL;
5065 			int year, month;
5066 
5067 			/* Date string should be in YYYY-MM format */
5068 			if (strlen(strp) != strlen("YYYY-MM") ||
5069 			    strp[4] != '-') {
5070 				return (iSCSINameIqnDateFormatError);
5071 			}
5072 
5073 			/*
5074 			 * Validate year.  Only validating that the
5075 			 * year can be converted to a number.  No
5076 			 * validation will be done on year's actual
5077 			 * value.
5078 			 */
5079 			(void) strncpy(tmpYear, strp, 4);
5080 			tmpYear[4] = '\0';
5081 
5082 			errno = 0;
5083 			year = strtol(tmpYear, &endPtr, 10);
5084 			if (errno != 0 || *endPtr != '\0' ||
5085 			    year < 0 || year > 9999) {
5086 				return (iSCSINameIqnInvalidYearError);
5087 			}
5088 
5089 			/*
5090 			 * Validate month is valid.
5091 			 */
5092 			(void) strncpy(tmpMonth, &strp[5], 2);
5093 			tmpMonth[2] = '\0';
5094 			errno = 0;
5095 			month = strtol(tmpMonth, &endPtr, 10);
5096 
5097 			if (errno != 0 || *endPtr != '\0' ||
5098 			    month < 1 || month > 12) {
5099 				return (iSCSINameIqnInvalidMonthError);
5100 			}
5101 
5102 			/*
5103 			 * A reversed FQDN needs to be provided.  We
5104 			 * will only check for a "." followed by more
5105 			 * than two or more characters.  The list of domains is
5106 			 * too large and changes too frequently to
5107 			 * add validation for.
5108 			 */
5109 			strp = strtok(NULL, ".");
5110 			if (!strp || strlen(strp) < 2) {
5111 				return (iSCSINameIqnFQDNError);
5112 			}
5113 
5114 			/* Name authority string */
5115 			strp = strtok(NULL, ":");
5116 			if (strp) {
5117 				return (iSCSINameCheckOK);
5118 			} else {
5119 				return (iSCSINameIqnFQDNError);
5120 			}
5121 		} else {
5122 			return (iSCSINameIqnFormatError);
5123 		}
5124 	} else if (strncmp(mb_name, ISCSI_EUI_NAME_PREFIX,
5125 	    strlen(ISCSI_EUI_NAME_PREFIX)) == 0) {
5126 		/* If name is of type EUI, change its length */
5127 
5128 		if (strlen(mb_name) != ISCSI_EUI_NAME_LEN) {
5129 			return (iSCSINameEUIFormatError);
5130 		}
5131 
5132 		for (tmp = mb_name + strlen(ISCSI_EUI_NAME_PREFIX) + 1;
5133 		    *tmp != '\0'; tmp++) {
5134 			if (isxdigit(*tmp)) {
5135 				continue;
5136 			}
5137 			return (iSCSINameEUIFormatError);
5138 		}
5139 
5140 		return (iSCSINameCheckOK);
5141 	} else {
5142 		return (iSCSINameUnknownType);
5143 	}
5144 }
5145 
5146 /*
5147  * This helper function could go into a utility module for general use.
5148  *
5149  * Returns:
5150  * B_TRUE is the numberStr is an unsigned natural number and within the
5151  * specified bound.
5152  * B_FALSE otherwise.
5153  */
5154 boolean_t
5155 isNaturalNumber(char *numberStr, uint32_t upperBound)
5156 {
5157 	int i;
5158 	int number_str_len;
5159 
5160 	if ((number_str_len = strlen(numberStr)) == 0) {
5161 		return (B_FALSE);
5162 	}
5163 
5164 	for (i = 0; i < number_str_len; i++) {
5165 		if (numberStr[i] < 060 || numberStr[i] > 071) {
5166 			return (B_FALSE);
5167 		}
5168 	}
5169 
5170 	if (atoi(numberStr) > upperBound) {
5171 		return (B_FALSE);
5172 	}
5173 
5174 	return (B_TRUE);
5175 }
5176 
5177 /*
5178  * This helper function could go into a utility module for general use.
5179  * It parses a target string in the format of:
5180  *
5181  * 	<target_name>,[<ip_address>[:port][,tpgt]]
5182  *
5183  * and creates wchar strings for target name and target address. It
5184  * also populates port and tpgt if found.
5185  *
5186  * Returns:
5187  * 	PARSE_TARGET_OK if parsing is successful.
5188  *	PARSE_TARGET_INVALID_TPGT if the specified tpgt is
5189  *	invalid.
5190  * 	PARSE_TARGET_INVALID_ADDR if the address specified is
5191  *	invalid.
5192  */
5193 int
5194 parseTarget(char *targetStr,
5195 		wchar_t *targetNameStr,
5196 		size_t targetNameStrLen,
5197 		boolean_t *targetAddressSpecified,
5198 		wchar_t *targetAddressStr,
5199 		size_t targetAddressStrLen,
5200 		uint16_t *port,
5201 		boolean_t *tpgtSpecified,
5202 		uint16_t *tpgt,
5203 		boolean_t *isIpv6)
5204 {
5205 	char *commaPos;
5206 	char *commaPos2;
5207 	char targetAddress[SUN_IMA_IP_ADDRESS_PORT_LEN];
5208 	int i;
5209 	int lowerCase;
5210 
5211 	(void) memset(targetNameStr, 0,
5212 	    targetNameStrLen * sizeof (wchar_t));
5213 	(void) memset(targetAddressStr, 0,
5214 	    targetAddressStrLen * sizeof (wchar_t));
5215 
5216 	commaPos = strchr(targetStr, ',');
5217 	if (commaPos != NULL) {
5218 		*commaPos = NULL;
5219 		commaPos++;
5220 		*targetAddressSpecified = B_TRUE;
5221 
5222 		/*
5223 		 * Checking of tpgt makes sense only when
5224 		 * the target address/port are specified.
5225 		 */
5226 		commaPos2 = strchr(commaPos, ',');
5227 		if (commaPos2 != NULL) {
5228 			*commaPos2 = NULL;
5229 			commaPos2++;
5230 			if (isNaturalNumber(commaPos2, ISCSI_MAX_TPGT_VALUE) ==
5231 			    B_TRUE) {
5232 				*tpgt = atoi(commaPos2);
5233 				*tpgtSpecified = B_TRUE;
5234 			} else {
5235 				return (PARSE_TARGET_INVALID_TPGT);
5236 			}
5237 		}
5238 
5239 		switch (parseAddress(commaPos, ISCSI_LISTEN_PORT,
5240 		    &targetAddress[0], MAX_ADDRESS_LEN + 1, port, isIpv6)) {
5241 		case PARSE_ADDR_PORT_OUT_OF_RANGE:
5242 			return (PARSE_TARGET_INVALID_ADDR);
5243 		case PARSE_ADDR_OK:
5244 			break;
5245 		default:
5246 			(void) fprintf(stderr, "%s: %s\n",
5247 			    cmdName, gettext("cannot parse target name"));
5248 			return (PARSE_TARGET_INVALID_ADDR);
5249 		}
5250 		(void) mbstowcs(targetAddressStr, targetAddress,
5251 		    targetAddressStrLen);
5252 		for (i = 0; targetAddressStr[i] != 0; i++) {
5253 			lowerCase = tolower(targetAddressStr[i]);
5254 			targetAddressStr[i] = lowerCase;
5255 		}
5256 	} else {
5257 		*targetAddressSpecified = B_FALSE;
5258 		*tpgtSpecified = B_FALSE;
5259 	}
5260 
5261 	(void) mbstowcs(targetNameStr, targetStr, targetNameStrLen);
5262 	for (i = 0; targetNameStr[i] != 0; i++) {
5263 		lowerCase = tolower(targetNameStr[i]);
5264 		targetNameStr[i] = lowerCase;
5265 	}
5266 
5267 	return (PARSE_TARGET_OK);
5268 }
5269 
5270 /*ARGSUSED*/
5271 static void
5272 listCHAPName(IMA_OID oid)
5273 {
5274 	IMA_INITIATOR_AUTHPARMS authParams;
5275 	IMA_STATUS status;
5276 	IMA_BYTE chapName [MAX_CHAP_NAME_LEN + 1];
5277 
5278 	/* Get Chap Name depending upon oid object type */
5279 	if (oid.objectType == IMA_OBJECT_TYPE_LHBA) {
5280 		status = IMA_GetInitiatorAuthParms(oid,
5281 		    IMA_AUTHMETHOD_CHAP, &authParams);
5282 	} else {
5283 		status = SUN_IMA_GetTargetAuthParms(oid,
5284 		    IMA_AUTHMETHOD_CHAP, &authParams);
5285 	}
5286 
5287 	(void) fprintf(stdout, "\n\t\t%s: ", gettext("CHAP Name"));
5288 
5289 	if (IMA_SUCCESS(status)) {
5290 		/*
5291 		 * Default chap name will be the node name.  The default will
5292 		 * be set by the driver.
5293 		 */
5294 		if (authParams.chapParms.nameLength != 0) {
5295 			(void) memset(chapName, 0, sizeof (chapName));
5296 			(void) memcpy(chapName, authParams.chapParms.name,
5297 			    authParams.chapParms.nameLength);
5298 			(void) fprintf(stdout, "%s", chapName);
5299 
5300 		} else {
5301 			(void) fprintf(stdout, "%s", "-");
5302 		}
5303 	} else {
5304 		(void) fprintf(stdout, "%s", "-");
5305 	}
5306 }
5307 
5308 /*
5309  * Prints out see manual page.
5310  * Called out through atexit(3C) so is always last thing displayed.
5311  */
5312 void
5313 seeMan(void)
5314 {
5315 	static int sent = 0;
5316 
5317 	if (sent)
5318 		return;
5319 
5320 	(void) fprintf(stdout, "%s %s(1M)\n",
5321 	    gettext("For more information, please see"), cmdName);
5322 
5323 	sent = 1;
5324 }
5325 
5326 
5327 /*
5328  * main calls a parser that checks syntax of the input command against
5329  * various rules tables.
5330  *
5331  * The parser provides usage feedback based upon same tables by calling
5332  * two usage functions, usage and subUsage, handling command and subcommand
5333  * usage respectively.
5334  *
5335  * The parser handles all printing of usage syntactical errors
5336  *
5337  * When syntax is successfully validated, the parser calls the associated
5338  * function using the subcommands table functions.
5339  *
5340  * Syntax is as follows:
5341  *	command subcommand [options] resource-type [<object>]
5342  *
5343  * The return value from the function is placed in funcRet
5344  */
5345 int
5346 main(int argc, char *argv[])
5347 {
5348 	synTables_t synTables;
5349 	char versionString[VERSION_STRING_MAX_LEN];
5350 	int ret;
5351 	int funcRet = 0;
5352 	void *subcommandArgs = NULL;
5353 
5354 	if (geteuid() != 0) {
5355 		(void) fprintf(stderr, "%s\n", gettext("permission denied"));
5356 		return (1);
5357 	}
5358 
5359 	/* set global command name */
5360 	cmdName = getExecBasename(argv[0]);
5361 
5362 	(void) snprintf(versionString, sizeof (versionString), "%s.%s",
5363 	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
5364 	synTables.versionString = versionString;
5365 	synTables.longOptionTbl = &longOptions[0];
5366 	synTables.subcommandTbl = &subcommands[0];
5367 	synTables.objectTbl = &objects[0];
5368 	synTables.objectRulesTbl = &objectRules[0];
5369 	synTables.optionRulesTbl = &optionRules[0];
5370 
5371 	/* call the CLI parser */
5372 	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
5373 	if (ret == -1) {
5374 		perror(cmdName);
5375 		ret = 1;
5376 	}
5377 
5378 	if (funcRet != 0) {
5379 		(void) fprintf(stderr, "%s: %s\n",
5380 		    cmdName, gettext("Unable to complete operation"));
5381 		ret = 1;
5382 	}
5383 	return (ret);
5384 }
5385