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