xref: /illumos-gate/usr/src/cmd/isns/isnsd/dump.c (revision 55d6cb5d63bcf69dfa47b8c41c770a2d34f169b0)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* This file is getting large unexpectly, a lex & yacc */
28 /* implementation is expected. */
29 
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <pthread.h>
42 
43 #include "isns_server.h"
44 #include "isns_htab.h"
45 #include "isns_msgq.h"
46 #include "isns_obj.h"
47 #include "isns_func.h"
48 #include "isns_dd.h"
49 #include "isns_cache.h"
50 #include "isns_pdu.h"
51 
52 #ifdef DEBUG
53 /*
54  * external variables
55  */
56 extern const int NUM_OF_CHILD[MAX_OBJ_TYPE];
57 extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE];
58 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
59 extern const int NUM_OF_REF[MAX_OBJ_TYPE_FOR_SIZE];
60 
61 extern lookup_ctrl_t *setup_ddid_lcp(lookup_ctrl_t *, uint32_t);
62 extern lookup_ctrl_t *setup_ddsid_lcp(lookup_ctrl_t *, uint32_t);
63 
64 /*
65  * global variables
66  */
67 int verbose_mc = 0;
68 int verbose_tc = 0;
69 int verbose_lock = 0;
70 int verbose_net = 0;
71 int verbose_parser = 0;
72 
73 /*
74  * local variables
75  */
76 static void print_entity(char *, isns_obj_t *);
77 static void print_iscsi(char *, isns_obj_t *);
78 static void print_portal(char *, isns_obj_t *);
79 static void print_pg(char *, isns_obj_t *);
80 static void print_dd(char *, isns_obj_t *);
81 static void print_dds(char *, isns_obj_t *);
82 static void (*const print_func[MAX_OBJ_TYPE])(char *, isns_obj_t *) = {
83 	NULL,
84 	&print_entity,
85 	&print_iscsi,
86 	&print_portal,
87 	&print_pg,
88 	&print_dd,
89 	&print_dds
90 };
91 static int run_cmd(char *);
92 
93 typedef struct {
94 	uint16_t func_id;
95 	char *fname;
96 } isnsp_fnames_t;
97 isnsp_fnames_t fnames[] = {
98 { ISNS_DEV_ATTR_REG, "DevAttrReg" },
99 { ISNS_DEV_ATTR_QRY, "DevAttrQry" },
100 { ISNS_DEV_GET_NEXT, "DevGetNext" },
101 { ISNS_DEV_DEREG, "DevDereg" },
102 { ISNS_SCN_REG, "SCNReg" },
103 { ISNS_SCN_DEREG, "SCNDereg" },
104 { ISNS_DD_REG, "DDReg" },
105 { ISNS_DD_DEREG, "DDDereg" },
106 { ISNS_DDS_REG, "DDSReg" },
107 { ISNS_DDS_DEREG, "DDSDereg" },
108 { ISNS_SCN, "SCN" },
109 { ISNS_ESI, "ESI" },
110 { ISNS_HEARTBEAT, "Heartbeat" },
111 { ISNS_DEV_ATTR_REG_RSP, "DevAttrRegRsp" },
112 { ISNS_DEV_ATTR_QRY_RSP, "DevAttrQryRsp" },
113 { ISNS_DEV_GET_NEXT_RSP, "DevGetNextRsp" },
114 { ISNS_DEV_DEREG_RSP, "DevDeregRsp" },
115 { ISNS_SCN_REG_RSP, "SCNRegRsp" },
116 { ISNS_SCN_DEREG_RSP, "SCNDeregRsp" },
117 { ISNS_SCN_RSP, "SCNRsp" },
118 { ISNS_ESI_RSP, "ESIRsp" },
119 { 0xFFFF, "Unknown" } };
120 
121 static char *
122 get_func_name(
123 	uint16_t id
124 )
125 {
126 	int i = 0;
127 	isnsp_fnames_t *fp = &fnames[i ++];
128 	while (fp->func_id != 0xFFFF) {
129 		if (fp->func_id == id) {
130 			return (fp->fname);
131 		}
132 		fp = &fnames[i ++];
133 	}
134 
135 	return ("UNKNOWN");
136 }
137 
138 static char *
139 get_tlv_tag_name(
140 	uint32_t tag
141 )
142 {
143 	switch (tag) {
144 		case ISNS_DELIMITER_ATTR_ID:
145 			return ("Delimiter");
146 		case ISNS_EID_ATTR_ID:
147 			return ("Entity Identifier");
148 		case ISNS_ENTITY_PROTOCOL_ATTR_ID:
149 			return ("Entity Protocol");
150 		case ISNS_ENTITY_REG_PERIOD_ATTR_ID:
151 			return ("Registration Period");
152 		case ISNS_TIMESTAMP_ATTR_ID:
153 			return ("Timestamp");
154 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
155 			return ("Portal IP Address");
156 		case ISNS_PORTAL_PORT_ATTR_ID:
157 			return ("Portal TCP/UDP Port");
158 		case ISNS_PORTAL_NAME_ATTR_ID:
159 			return ("Portal Symbolic Name");
160 		case ISNS_ESI_INTERVAL_ATTR_ID:
161 			return ("ESI Interval");
162 		case ISNS_ESI_PORT_ATTR_ID:
163 			return ("ESI Port");
164 		case ISNS_SCN_PORT_ATTR_ID:
165 			return ("SCN Port");
166 		case ISNS_PORTAL_SEC_BMP_ATTR_ID:
167 			return ("Portal Security Bitmap");
168 		case ISNS_ISCSI_NAME_ATTR_ID:
169 			return ("iSCSI Name");
170 		case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
171 			return ("iSCSI Node Type");
172 		case ISNS_ISCSI_ALIAS_ATTR_ID:
173 			return ("iSCSI Alias");
174 		case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
175 			return ("iSCSI Auth Method");
176 		case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
177 			return ("iSCSI SCN Bitmap");
178 		case ISNS_PG_ISCSI_NAME_ATTR_ID:
179 			return ("PG iSCSI Name");
180 		case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
181 			return ("PG Portal IP Addr");
182 		case ISNS_PG_PORTAL_PORT_ATTR_ID:
183 			return ("PG Portal TCP/UDP Port");
184 		case ISNS_PG_TAG_ATTR_ID:
185 			return ("PG Tag (PGT)");
186 		case ISNS_PG_INDEX_ATTR_ID:
187 			return ("PG Index");
188 		case ISNS_DD_NAME_ATTR_ID:
189 			return ("DD Name");
190 		case ISNS_DD_ID_ATTR_ID:
191 			return ("DD Index");
192 		case ISNS_DD_ISCSI_INDEX_ATTR_ID:
193 			return ("DD ISCSI Node Index");
194 		case ISNS_DD_ISCSI_NAME_ATTR_ID:
195 			return ("DD ISCSI Node Name");
196 		case ISNS_DD_SET_NAME_ATTR_ID:
197 			return ("DDS Name");
198 		case ISNS_DD_SET_ID_ATTR_ID:
199 			return ("DDS Index");
200 		case ISNS_DD_SET_STATUS_ATTR_ID:
201 			return ("DDS Status");
202 		default:
203 			return ("Unknown");
204 	}
205 }
206 
207 static void
208 dump_pdu(
209 	isns_pdu_t *pdu,
210 	int flag
211 )
212 {
213 	short ver, id, len, flags, xid, seq;
214 
215 	uint8_t *payload = pdu->payload;
216 	isns_resp_t *resp;
217 
218 	/* convert the data */
219 	if (flag) {
220 		ver = ntohs(pdu->version);
221 		id = ntohs(pdu->func_id);
222 		len = ntohs(pdu->payload_len);
223 		flags = ntohs(pdu->flags) & 0xFFFF;
224 		xid = ntohs(pdu->xid);
225 		seq = ntohs(pdu->seq);
226 	} else {
227 		ver = pdu->version;
228 		id = pdu->func_id;
229 		len = pdu->payload_len;
230 		flags = pdu->flags & 0xFFFF;
231 		xid = pdu->xid;
232 		seq = pdu->seq;
233 	}
234 
235 	/* print the pdu header */
236 	printf("iSNSP Version: %d\n", ver);
237 	printf("Function ID: %s\n", get_func_name(id));
238 	printf("PDU Length: %d\n", len);
239 	printf("Flags: %x\n", flags);
240 	printf("    %d... .... .... .... : ISNS_FLAG_CLIENT\n",
241 	    ((flags & ISNS_FLAG_CLIENT) == 0) ? 0 : 1);
242 	printf("    .%d.. .... .... .... : ISNS_FLAG_SERVER\n",
243 	    ((flags & ISNS_FLAG_SERVER) == 0) ? 0 : 1);
244 	printf("    ..%d. .... .... .... : ISNS_FLAG_AUTH_BLK_PRESENTED\n",
245 	    ((flags & ISNS_FLAG_AUTH_BLK_PRESENTED) == 0) ? 0 : 1);
246 	printf("    ...%d .... .... .... : ISNS_FLAG_REPLACE_REG\n",
247 	    ((flags & ISNS_FLAG_REPLACE_REG) == 0) ? 0 : 1);
248 	printf("    .... %d... .... .... : ISNS_FLAG_LAST_PDU\n",
249 	    ((flags & ISNS_FLAG_LAST_PDU) == 0) ? 0 : 1);
250 	printf("    .... .%d.. .... .... : ISNS_FLAG_FIRST_PDU\n",
251 	    ((flags & ISNS_FLAG_FIRST_PDU) == 0) ? 0 : 1);
252 	printf("Transaction ID: %d\n", xid);
253 	printf("Sequence ID: %d\n", seq);
254 
255 	printf("Payload: ...\n");
256 	if (id & ISNS_RSP_MASK) {
257 		resp = (isns_resp_t *)payload;
258 		printf("    ErrorCode: %d\n", ntohl(resp->status));
259 		len -= 4;
260 		payload += 4;
261 	}
262 
263 	/* print the payload */
264 	while (len > 0) {
265 		isns_tlv_t *tlvp;
266 		int t, l;
267 		uint8_t *v;
268 		char *s;
269 		int i;
270 		in6_addr_t *ip;
271 		char pbuff[256] = { 0 };
272 
273 		tlvp = (isns_tlv_t *)payload;
274 
275 		/* convert the data */
276 		t = ntohl(tlvp->attr_id);
277 		l = ntohl(tlvp->attr_len);
278 		v = &(tlvp->attr_value[0]);
279 
280 		/* print payload */
281 		if (l > 0) {
282 			printf("%s: ", get_tlv_tag_name(t));
283 			switch (t) {
284 				case ISNS_EID_ATTR_ID:
285 				case ISNS_ISCSI_NAME_ATTR_ID:
286 				case ISNS_ISCSI_ALIAS_ATTR_ID:
287 				case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
288 				case ISNS_PG_ISCSI_NAME_ATTR_ID:
289 				case ISNS_DD_NAME_ATTR_ID:
290 				case ISNS_DD_SET_NAME_ATTR_ID:
291 					s = (char *)v;
292 					printf("%s\n", s);
293 					break;
294 				case ISNS_ENTITY_PROTOCOL_ATTR_ID:
295 					i = ntohl(*(uint32_t *)v);
296 					printf("%s (%d)\n",
297 					    ((i == 1) ? "No Protocol" :
298 					    ((i == 2) ? "iSCSI" :
299 					    ((i == 3) ? "iFCP" :
300 					    "Others"))),
301 					    i);
302 					break;
303 				case ISNS_PORTAL_IP_ADDR_ATTR_ID:
304 				case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
305 					ip = (in6_addr_t *)v;
306 					inet_ntop(AF_INET6, (void *)ip,
307 					    pbuff, sizeof (pbuff));
308 					printf("%s\n", pbuff);
309 					break;
310 				case ISNS_PORTAL_PORT_ATTR_ID:
311 				case ISNS_ESI_PORT_ATTR_ID:
312 				case ISNS_SCN_PORT_ATTR_ID:
313 					i = ntohl(*(uint32_t *)v);
314 					printf("%d\n", (i & 0x0000FFFF));
315 					printf("    .... .... %d... .... : "
316 					    "0=TCP\n",
317 					    ((i & 0x10000) == 0) ? 0 : 1);
318 					break;
319 				case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
320 					i = ntohl(*(uint32_t *)v);
321 					printf("0x%x\t", i);
322 					if (i & ISNS_CONTROL_NODE_TYPE) {
323 						printf("Control ");
324 					}
325 					if (i & ISNS_INITIATOR_NODE_TYPE) {
326 						printf("Initiator ");
327 					}
328 					if (i & ISNS_TARGET_NODE_TYPE) {
329 						printf("Target ");
330 					}
331 					printf("\n");
332 					break;
333 				case ISNS_PG_TAG_ATTR_ID:
334 				default:
335 					i = ntohl(*(uint32_t *)v);
336 					printf("%d\n", i);
337 					break;
338 			}
339 			printf("    Attribute Tag: %s (%d)\n",
340 			    get_tlv_tag_name(t), t);
341 			printf("    Attribute Length: %d\n", l);
342 		} else {
343 			printf("%s: (%d)\n", get_tlv_tag_name(t), t);
344 		}
345 
346 		len -= (sizeof (uint32_t) * 2 + l);
347 		payload += (sizeof (uint32_t) * 2 + l);
348 	}
349 }
350 
351 void
352 dump_pdu1(
353 	isns_pdu_t *pdu
354 )
355 {
356 	if (verbose_net) {
357 		printf("### PDU RECEIVED ###\n");
358 		dump_pdu(pdu, 0);
359 	}
360 }
361 
362 void
363 dump_pdu2(
364 	isns_pdu_t *pdu
365 )
366 {
367 	if (verbose_net) {
368 		printf("### PDU SENT ###\n");
369 		dump_pdu(pdu, 1);
370 	}
371 }
372 
373 void
374 dump_db(
375 )
376 {
377 #if 0
378 	isns_list_t *list, *lista, *listb;
379 	isns_dds_t *dds;
380 	isns_dd_t *dd;
381 	isns_iscsi2_t *iscsi2;
382 
383 	printf("### DUMP DATABASE ###\n");
384 	/* dump dds(s) */
385 	list = dds_list;
386 	while (list != NULL) {
387 		dds = list->obj.dds;
388 		printf("[DDS:%d]%s(%s)\n", dds->id, dds->name,
389 		    dds->status ? "enabled" : "disabled");
390 		lista = dds->dd_list;
391 		/* dd(s) that belong to this dds */
392 		while (lista != NULL) {
393 			dd = lista->obj.dd;
394 			printf("\t[DD:%d]%s\n", dd->id, dd->name);
395 			lista = lista->next;
396 		}
397 		list = list->next;
398 	}
399 	/* dump dd(s) */
400 	list = dd_list;
401 	while (list != NULL) {
402 		dd = list->obj.dd;
403 		printf("[DD:%d]%s\n", dd->id, dd->name);
404 		/* dds(s) this dd belongs to */
405 		lista = dd->dds_list;
406 		while (lista != NULL) {
407 			dds = lista->obj.dds;
408 			printf("\t[DDS:%d]%s\n", dds->id, dds->name);
409 			lista = lista->next;
410 		}
411 		/* node(s) that this dd have */
412 		listb = dd->iscsi_list;
413 		while (listb != NULL) {
414 			iscsi2 = listb->obj.iscsi2;
415 			printf("\t[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name);
416 			listb = listb->next;
417 		}
418 		list = list->next;
419 	}
420 	/* dump node(s) */
421 	list = iscsi_list;
422 	while (list != NULL) {
423 		iscsi2 = list->obj.iscsi2;
424 		printf("[ISCSI:%d]%s\n", iscsi2->id, iscsi2->name);
425 		lista = iscsi2->dd_list;
426 		/* dd(s) that this node belongs to */
427 		while (lista != NULL) {
428 			dd = lista->obj.dd;
429 			printf("\t[DD:%d]%s\n", dd->id, dd->name);
430 			lista = lista->next;
431 		}
432 		list = list->next;
433 	}
434 #endif
435 }
436 
437 static void
438 test_cli_help(
439 )
440 {
441 	printf("list          - list all of storage node.\n");
442 	printf("list dd  [id] - list all of dd or one with member.\n");
443 	printf("list dds [id] - list all of dd-set or one with member.\n");
444 
445 	printf("\n");
446 	printf("new dd  <name>  - create a dd with name.\n");
447 	printf("new dds <name>  - create a dd-set with name.\n");
448 	printf("new ddn  <id> <name>  - create a dd with id and name.\n");
449 	printf("new ddsn <id> <name>  - create a dd-set with id and name.\n");
450 	printf("del dd   <id>   - delete a dd.\n");
451 	printf("del dds  <id>   - delete a dd-set.\n");
452 
453 	printf("\n");
454 	printf("add dd   <dd_id>  <node_name> - add a node to dd.\n");
455 	printf("add ddn  <dd_id>  <node_id>   - add a node to dd.\n");
456 	printf("add ddsn <dds_id> <dd_id>     - add a dd to dd-set.\n");
457 	printf("remove dd   <dd_id> <node_name> - remove a node from dd.\n");
458 	printf("remove ddn  <dd_id> <node_id>   - remove a node from dd.\n");
459 	printf("remove ddsn <dds_id> <dd_id>    - remove a dd from dd-set.\n");
460 
461 	printf("\n");
462 	printf("enable  <dds_id> - enable a dd-set.\n");
463 	printf("disable <dds_id> - disable a dd-set.\n");
464 
465 	printf("\n");
466 	printf("file <f> - loading command from a file.\n");
467 	printf("pause    - suspend batch until enter key is pressed.\n");
468 
469 	printf("help   - print this help.\n");
470 	printf("quit   - stop iSNS server and quit.\n");
471 }
472 
473 static enum {
474 	CMD_LIST, CMD_LISTNE, CMD_LISTP, CMD_LISTPG,
475 	CMD_LISTDD, CMD_LISTDDS, CMD_LISTDDN, CMD_LISTDDSN,
476 	CMD_NEWDD, CMD_NEWDDS, CMD_NEWDDN, CMD_NEWDDSN,
477 	CMD_DELDD, CMD_DELDDS,
478 	CMD_ENABLE, CMD_DISABLE,
479 	CMD_ADDDD, CMD_ADDDDN, CMD_ADDDDSN,
480 	CMD_REMDD, CMD_REMDDN, CMD_REMDDSN,
481 	CMD_VIEW,
482 	CMD_FILE, CMD_PAUSE,
483 	CMD_HELP,
484 	CMD_VERBOSE_MEMORY, CMD_VERBOSE_NET,
485 	CMD_VERBOSE_PARSER, CMD_VERBOSE_TIME,
486 	CMD_VERBOSE_LOCK,
487 	CMD_QUIT,
488 	CMD_NONE, CMD_INVALID
489 };
490 
491 static int
492 getcmd(
493 	int *argc, int *argv, char *cmd
494 )
495 {
496 	int j = 0;
497 	char tmp[256] = { 0 };
498 	*argc = 0;
499 	while (*cmd == ' ') cmd ++;
500 
501 	if (*cmd == 0) {
502 		return (CMD_NONE);
503 	} else if (*cmd == '?') {
504 		return (CMD_HELP);
505 	}
506 
507 	/* list, list dd, list dds, list dd 0 */
508 	if (strncmp(cmd, "list ", 5) == 0) {
509 		cmd += 5;
510 		while (*cmd == ' ') cmd ++;
511 		if (*cmd == 0) {
512 			return (CMD_LIST);
513 		} else if (*cmd == 'p') {
514 			cmd ++;
515 			while (*cmd == ' ') cmd ++;
516 			if (*cmd == 0) {
517 				return (CMD_LISTP);
518 			}
519 		} else if (*cmd == 'g') {
520 			cmd ++;
521 			while (*cmd == ' ') cmd ++;
522 			if (*cmd == 0) {
523 				return (CMD_LISTPG);
524 			}
525 		} else if (*cmd == 'e') {
526 			cmd ++;
527 			while (*cmd == ' ') cmd ++;
528 			if (*cmd == 0) {
529 				return (CMD_LISTNE);
530 			}
531 		} else if (strncmp(cmd, "dds ", 4) == 0) {
532 			cmd += 4;
533 			while (*cmd == ' ') cmd ++;
534 			if (*cmd == 0) {
535 				return (CMD_LISTDDS);
536 			}
537 			j = 0;
538 			while (*cmd >= '0' && *cmd <= '9') {
539 				tmp[j++] = *cmd ++;
540 			}
541 			tmp[j] = 0;
542 			while (*cmd == ' ') cmd ++;
543 			if (*cmd == 0 && j > 0) {
544 				argv[(*argc)++] = atoi(tmp);
545 				return (CMD_LISTDDSN);
546 			}
547 		} else if (strncmp(cmd, "dd ", 3) == 0) {
548 			cmd += 3;
549 			while (*cmd == ' ') cmd ++;
550 			if (*cmd == 0) {
551 				return (CMD_LISTDD);
552 			}
553 			j = 0;
554 			while (*cmd >= '0' && *cmd <= '9') {
555 				tmp[j++] = *cmd ++;
556 			}
557 			tmp[j] = 0;
558 			while (*cmd == ' ') cmd ++;
559 			if (*cmd == 0 && j > 0) {
560 				argv[(*argc)++] = atoi(tmp);
561 				return (CMD_LISTDDN);
562 			}
563 		}
564 		return (CMD_INVALID);
565 	}
566 
567 	/* view 0 */
568 	if (strncmp(cmd, "view ", 5) == 0) {
569 		cmd += 5;
570 		while (*cmd == ' ') cmd ++;
571 		j = 0;
572 		while (*cmd >= '0' && *cmd <= '9') {
573 			tmp[j++] = *cmd ++;
574 		}
575 		tmp[j] = 0;
576 		while (*cmd == ' ') cmd ++;
577 		if (*cmd == 0 && j > 0) {
578 			argv[(*argc)++] = atoi(tmp);
579 			return (CMD_VIEW);
580 		}
581 		return (CMD_INVALID);
582 	}
583 
584 	/* add dd name */
585 	/* add ddn/ddsn id id */
586 	if (strncmp(cmd, "add ", 4) == 0) {
587 		int addcmd = CMD_INVALID;
588 		cmd += 4;
589 		while (*cmd == ' ') cmd ++;
590 		if (strncmp(cmd, "dd ", 3) == 0) {
591 			cmd += 3;
592 			addcmd = CMD_ADDDD;
593 		} else if (strncmp(cmd, "ddn ", 4) == 0) {
594 			cmd += 4;
595 			addcmd = CMD_ADDDDN;
596 		} else if (strncmp(cmd, "ddsn ", 5) == 0) {
597 			cmd += 5;
598 			addcmd = CMD_ADDDDSN;
599 		} else {
600 			return (CMD_INVALID);
601 		}
602 		while (*cmd == ' ') cmd ++;
603 		j = 0;
604 		while (*cmd >= '0' && *cmd <= '9') {
605 			tmp[j++] = *cmd ++;
606 		}
607 		tmp[j] = 0;
608 		if (j > 0) {
609 			argv[(*argc)++] = atoi(tmp);
610 		} else {
611 			return (CMD_INVALID);
612 		}
613 		while (*cmd == ' ') cmd ++;
614 		if (*cmd != 0) {
615 			switch (addcmd) {
616 			case CMD_ADDDDN:
617 			case CMD_ADDDDSN:
618 				j = 0;
619 				while (*cmd >= '0' && *cmd <= '9') {
620 					tmp[j++] = *cmd ++;
621 				}
622 				tmp[j] = 0;
623 				while (*cmd == ' ') cmd ++;
624 				if (*cmd == 0 && j > 0) {
625 					argv[(*argc)++] = atoi(tmp);
626 				} else {
627 					return (CMD_INVALID);
628 				}
629 				break;
630 			case CMD_ADDDD:
631 				j = strlen(cmd);
632 				while (j > 0) {
633 					/* get rid of trail blank space */
634 					if (cmd[j - 1] == ' ') {
635 						cmd[--j] = 0;
636 					} else {
637 						break;
638 					}
639 				}
640 				if (j > 0) {
641 					cmd[j] = 0;
642 					argv[(*argc)++] = (int)cmd;
643 				} else {
644 					return (CMD_INVALID);
645 				}
646 				break;
647 			}
648 			return (addcmd);
649 		}
650 		return (CMD_INVALID);
651 	}
652 
653 	/* remove dd name */
654 	/* remove ddn/ddsn id id */
655 	if (strncmp(cmd, "remove ", 7) == 0) {
656 		int rmcmd = CMD_INVALID;
657 		cmd += 7;
658 		while (*cmd == ' ') cmd ++;
659 		if (strncmp(cmd, "dd ", 3) == 0) {
660 			cmd += 3;
661 			while (*cmd == ' ') cmd ++;
662 			rmcmd = CMD_REMDD;
663 		} else if (strncmp(cmd, "ddn ", 4) == 0) {
664 			cmd += 4;
665 			while (*cmd == ' ') cmd ++;
666 			rmcmd = CMD_REMDDN;
667 		} else if (strncmp(cmd, "ddsn ", 5) == 0) {
668 			cmd += 5;
669 			while (*cmd == ' ') cmd ++;
670 			rmcmd = CMD_REMDDSN;
671 		} else {
672 			return (CMD_INVALID);
673 		}
674 		j = 0;
675 		while (*cmd >= '0' && *cmd <= '9') {
676 			tmp[j++] = *cmd ++;
677 		}
678 		tmp[j] = 0;
679 		if (j > 0) {
680 			argv[(*argc)++] = atoi(tmp);
681 		} else {
682 			return (CMD_INVALID);
683 		}
684 		while (*cmd == ' ') cmd ++;
685 		if (*cmd != 0) {
686 			switch (rmcmd) {
687 			case CMD_REMDDN:
688 			case CMD_REMDDSN:
689 				j = 0;
690 				while (*cmd >= '0' && *cmd <= '9') {
691 					tmp[j++] = *cmd ++;
692 				}
693 				tmp[j] = 0;
694 				while (*cmd == ' ') cmd ++;
695 				if (*cmd == 0 && j > 0) {
696 					argv[(*argc)++] = atoi(tmp);
697 				} else {
698 					return (CMD_INVALID);
699 				}
700 				break;
701 			case CMD_REMDD:
702 				j = strlen(cmd);
703 				while (j > 0) {
704 					/* get rid of trail blank space */
705 					if (cmd[j - 1] == ' ') {
706 						cmd[--j] = 0;
707 					} else {
708 						break;
709 					}
710 				}
711 				if (j > 0) {
712 					cmd[j] = 0;
713 					argv[(*argc)++] = (int)cmd;
714 				} else {
715 					return (CMD_INVALID);
716 				}
717 				break;
718 			}
719 			return (rmcmd);
720 		}
721 		return (CMD_INVALID);
722 	}
723 
724 	/* new dd, new dds */
725 	if (strncmp(cmd, "new ", 4) == 0) {
726 		int newcmd = CMD_INVALID;
727 		cmd += 4;
728 		while (*cmd == ' ') cmd ++;
729 		if (strncmp(cmd, "dd ", 3) == 0) {
730 			cmd += 3;
731 			newcmd = CMD_NEWDD;
732 		} else if (strncmp(cmd, "dds ", 4) == 0) {
733 			cmd += 4;
734 			newcmd = CMD_NEWDDS;
735 		} else if (strncmp(cmd, "ddn ", 4) == 0) {
736 			cmd += 4;
737 			newcmd = CMD_NEWDDN;
738 		} else if (strncmp(cmd, "ddsn ", 5) == 0) {
739 			cmd += 5;
740 			newcmd = CMD_NEWDDSN;
741 		}
742 		if (newcmd != CMD_INVALID) {
743 			while (*cmd == ' ') cmd ++;
744 			if (*cmd == 0) {
745 				return (newcmd);
746 			}
747 			switch (newcmd) {
748 			case CMD_NEWDDN:
749 			case CMD_NEWDDSN:
750 				j = 0;
751 				while (*cmd >= '0' && *cmd <= '9') {
752 					tmp[j++] = *cmd ++;
753 				}
754 				tmp[j] = 0;
755 				if (*cmd == ' ' && j > 0) {
756 					argv[(*argc)++] = atoi(tmp);
757 				} else {
758 					return (CMD_INVALID);
759 				}
760 			case CMD_NEWDD:
761 			case CMD_NEWDDS:
762 				while (*cmd == ' ') cmd ++;
763 				if (*cmd != 0) {
764 					j = strlen(cmd);
765 				} else {
766 					j = 0;
767 				}
768 				while (j > 0) {
769 					/* get rid of trail blank space */
770 					if (cmd[j - 1] == ' ') {
771 						cmd[--j] = 0;
772 					} else {
773 						break;
774 					}
775 				}
776 				if (j > 0) {
777 					cmd[j] = 0;
778 					argv[(*argc)++] = (int)cmd;
779 				}
780 			}
781 			return (newcmd);
782 		}
783 		return (CMD_INVALID);
784 	}
785 
786 	/* del dd, del dds, disable 0 */
787 	if (strncmp(cmd, "del ", 4) == 0) {
788 		int delcmd = CMD_INVALID;
789 		cmd += 4;
790 		while (*cmd == ' ') cmd ++;
791 		if (strncmp(cmd, "dds ", 4) == 0) {
792 			cmd += 4;
793 			delcmd = CMD_DELDDS;
794 		} else if (strncmp(cmd, "dd ", 3) == 0) {
795 			cmd += 3;
796 			delcmd = CMD_DELDD;
797 		}
798 		if (delcmd != CMD_INVALID) {
799 			while (*cmd == ' ') cmd ++;
800 			j = 0;
801 			while (*cmd >= '0' && *cmd <= '9') {
802 				tmp[j++] = *cmd ++;
803 			}
804 			tmp[j] = 0;
805 			while (*cmd == ' ') cmd ++;
806 			if (*cmd == 0 && j > 0) {
807 				argv[(*argc)++] = atoi(tmp);
808 				return (delcmd);
809 			}
810 		}
811 		return (CMD_INVALID);
812 	}
813 
814 	/* enable 0 */
815 	if (strncmp(cmd, "enable ", 7) == 0) {
816 		cmd += 7;
817 		while (*cmd == ' ') cmd ++;
818 		j = 0;
819 		while (*cmd >= '0' && *cmd <= '9') {
820 			tmp[j++] = *cmd ++;
821 		}
822 		tmp[j] = 0;
823 		while (*cmd == ' ') cmd ++;
824 		if (*cmd == 0 && j > 0) {
825 			argv[(*argc)++] = atoi(tmp);
826 			return (CMD_ENABLE);
827 		}
828 		return (CMD_INVALID);
829 	}
830 
831 	/* disable 0 */
832 	if (strncmp(cmd, "disable ", 8) == 0) {
833 		cmd += 8;
834 		while (*cmd == ' ') cmd ++;
835 		j = 0;
836 		while (*cmd >= '0' && *cmd <= '9') {
837 			tmp[j++] = *cmd ++;
838 		}
839 		tmp[j] = 0;
840 		while (*cmd == ' ') cmd ++;
841 		if (*cmd == 0 && j > 0) {
842 			argv[(*argc)++] = atoi(tmp);
843 			return (CMD_DISABLE);
844 		}
845 		return (CMD_INVALID);
846 	}
847 
848 	/* file */
849 	if (strncmp(cmd, "file ", 5) == 0) {
850 		cmd += 5;
851 		while (*cmd == ' ') cmd ++;
852 		if (*cmd != 0) {
853 			j = strlen(cmd);
854 		} else {
855 			j = 0;
856 		}
857 		while (j > 0) {
858 			/* get rid of trail blank space */
859 			if (cmd[j - 1] == ' ') {
860 				cmd[--j] = 0;
861 			} else {
862 				break;
863 			}
864 		}
865 		if (j > 0) {
866 			cmd[j] = 0;
867 			argv[(*argc)++] = (int)cmd;
868 			return (CMD_FILE);
869 		}
870 		return (CMD_INVALID);
871 	}
872 
873 	/* pause */
874 	if (strncmp(cmd, "pause ", 6) == 0) {
875 		cmd += 6;
876 		while (*cmd == ' ') cmd ++;
877 		if (*cmd == 0) {
878 			return (CMD_PAUSE);
879 		}
880 		return (CMD_INVALID);
881 	}
882 
883 	/* help */
884 	if (strncmp(cmd, "help ", 5) == 0) {
885 		cmd += 5;
886 		while (*cmd == ' ') cmd ++;
887 		if (*cmd == 0) {
888 			return (CMD_HELP);
889 		}
890 		return (CMD_INVALID);
891 	}
892 
893 	/* verbose */
894 	if (strncmp(cmd, "verbose ", 8) == 0) {
895 		cmd += 8;
896 		while (*cmd == ' ') cmd ++;
897 		if (*cmd == 0) {
898 			return (CMD_VERBOSE_PARSER);
899 		} else if (*cmd == 'm') {
900 			cmd ++;
901 			while (*cmd == ' ') cmd ++;
902 			if (*cmd == 0) {
903 				return (CMD_VERBOSE_MEMORY);
904 			}
905 		} else if (*cmd == 'n') {
906 			cmd ++;
907 			while (*cmd == ' ') cmd ++;
908 			if (*cmd == 0) {
909 				return (CMD_VERBOSE_NET);
910 			}
911 		} else if (*cmd == 'p') {
912 			cmd ++;
913 			while (*cmd == ' ') cmd ++;
914 			if (*cmd == 0) {
915 				return (CMD_VERBOSE_PARSER);
916 			}
917 		} else if (*cmd == 't') {
918 			cmd ++;
919 			while (*cmd == ' ') cmd ++;
920 			if (*cmd == 0) {
921 				return (CMD_VERBOSE_TIME);
922 			}
923 		} else if (*cmd == 'l') {
924 			cmd ++;
925 			while (*cmd == ' ') cmd ++;
926 			if (*cmd == 0) {
927 				return (CMD_VERBOSE_LOCK);
928 			}
929 		}
930 		return (CMD_INVALID);
931 	}
932 
933 	/* quit */
934 	if (strncmp(cmd, "quit ", 5) == 0) {
935 		cmd += 5;
936 		while (*cmd == ' ') cmd ++;
937 		if (*cmd == 0) {
938 			return (CMD_QUIT);
939 		}
940 		return (CMD_INVALID);
941 	}
942 
943 	return (CMD_INVALID);
944 }
945 
946 static void
947 print_entity(
948 	char *ident,
949 	isns_obj_t *obj
950 )
951 {
952 	uint32_t uid;
953 	uchar_t *eid;
954 	uint32_t *cuid;
955 	int i, num;
956 
957 	eid = obj->attrs[
958 	    ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)].value.ptr;
959 	uid = get_obj_uid(obj);
960 
961 	if (ident != NULL) {
962 		printf("%s%d\t%s\n", ident, uid, (const char *)eid);
963 	} else {
964 		printf("%d\t%s\n", uid, (const char *)eid);
965 	}
966 
967 	i = 0;
968 	while (i < NUM_OF_CHILD[obj->type]) {
969 		cuid = get_child_n(obj, i);
970 		if (ident != NULL) {
971 			printf("%s\t%s%d:", "child", i);
972 		} else {
973 			printf("\t%s%d:", "child", i);
974 		}
975 		if (cuid != NULL) {
976 			num = *cuid ++;
977 		} else {
978 			num = 0;
979 		}
980 		while (num > 0) {
981 			printf("\t%d", *cuid ++);
982 			num --;
983 		}
984 		printf("\n");
985 		i ++;
986 	}
987 }
988 
989 static void
990 print_iscsi(
991 	char *ident,
992 	isns_obj_t *obj
993 )
994 {
995 	uchar_t *name = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]
996 	    .value.ptr;
997 	uchar_t *alias = obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_ALIAS_ATTR_ID)]
998 	    .value.ptr;
999 	uint32_t type = obj->attrs[
1000 	    ATTR_INDEX_ISCSI(ISNS_ISCSI_NODE_TYPE_ATTR_ID)].value.ui;
1001 	uint32_t uid = get_obj_uid(obj);
1002 	uint32_t puid = get_parent_uid(obj);
1003 
1004 	if (!alias) {
1005 		alias = (uchar_t *)"-";
1006 	}
1007 
1008 	if (ident != NULL) {
1009 		printf("%s%d[%d]\t%s\n", ident,
1010 		    uid, puid, (const char *)name);
1011 		printf("%s\t%s", ident, alias);
1012 	} else {
1013 		printf("%d[%d]\t%s\n",
1014 		    uid, puid, (const char *)name);
1015 		printf("\t%s", alias);
1016 	}
1017 	if (IS_TYPE_TARGET(type)) {
1018 		printf("\tTarget");
1019 	}
1020 	if (IS_TYPE_INITIATOR(type)) {
1021 		printf("\tInitiator");
1022 	}
1023 	if (IS_TYPE_CONTROL(type)) {
1024 		printf("\tControl");
1025 	}
1026 	if (IS_TYPE_UNKNOWN(type)) {
1027 		printf("\t-");
1028 	}
1029 	printf("\n");
1030 }
1031 
1032 static void
1033 print_portal(
1034 	char *ident,
1035 	isns_obj_t *obj
1036 )
1037 {
1038 	char pbuff[256] = { 0 };
1039 	in6_addr_t *ip = obj->attrs[
1040 	    ATTR_INDEX_PORTAL(ISNS_PORTAL_IP_ADDR_ATTR_ID)].value.ip;
1041 	uint32_t port = obj->attrs[
1042 	    ATTR_INDEX_PORTAL(ISNS_PORTAL_PORT_ATTR_ID)].value.ui;
1043 	uint32_t uid = get_obj_uid(obj);
1044 	uint32_t puid = get_parent_uid(obj);
1045 
1046 	inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff));
1047 	if (ident != NULL) {
1048 		printf("%s%d[%d]\t%s:%d", ident,
1049 		    uid, puid, pbuff, PORT_NUMBER(port));
1050 	} else {
1051 		printf("%d[%d]\t%s:%d",
1052 		    uid, puid, pbuff, PORT_NUMBER(port));
1053 	}
1054 	printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP");
1055 }
1056 
1057 static void
1058 print_pg(
1059 	char *ident,
1060 	isns_obj_t *obj
1061 )
1062 {
1063 	uint32_t ref;
1064 	int i;
1065 
1066 	char pbuff[256] = { 0 };
1067 	uchar_t *name = obj->attrs[ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID)]
1068 	    .value.ptr;
1069 	in6_addr_t *ip = obj->attrs[
1070 	    ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)].value.ip;
1071 	uint32_t port = obj->attrs[
1072 	    ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID)].value.ui;
1073 	uint32_t tag = obj->attrs[
1074 	    ATTR_INDEX_PG(ISNS_PG_TAG_ATTR_ID)].value.ui;
1075 	uint32_t uid = get_obj_uid(obj);
1076 	uint32_t puid = get_parent_uid(obj);
1077 
1078 	inet_ntop(AF_INET6, (void *)ip, pbuff, sizeof (pbuff));
1079 	if (ident != NULL) {
1080 		printf("%s%d[%d]\t[%d] %s\n", ident,
1081 		    uid, puid, tag, (const char *)name);
1082 		printf("%s\t%s:%d", ident, pbuff, PORT_NUMBER(port));
1083 	} else {
1084 		printf("%d[%d]\t[%d] %s\n",
1085 		    uid, puid, tag, (const char *)name);
1086 		printf("\t%s:%d", pbuff, PORT_NUMBER(port));
1087 	}
1088 	printf(" %s\n", IS_PORT_UDP(port) ? "UDP" : "TCP");
1089 
1090 	if (NUM_OF_REF[obj->type] > 0) {
1091 		if (ident != NULL) {
1092 			printf("%s\t%s:", "ref");
1093 		} else {
1094 			printf("\t%s:", "ref");
1095 		}
1096 	}
1097 	i = 0;
1098 	while (i < NUM_OF_REF[obj->type]) {
1099 		ref = get_ref_n(obj, i);
1100 		printf("\t%d", ref);
1101 		i ++;
1102 	}
1103 	if (i > 0) {
1104 		printf("\n");
1105 	}
1106 }
1107 
1108 static void
1109 print_dd(
1110 	char *ident,
1111 	isns_obj_t *obj
1112 )
1113 {
1114 	uchar_t *name = obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)]
1115 	    .value.ptr;
1116 	uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DD]].value.ui;
1117 
1118 	if (ident != NULL) {
1119 		printf("%s%d\t%s\n", ident, uid, (const char *)name);
1120 	} else {
1121 		printf("%d\t%s\n", uid, (const char *)name);
1122 	}
1123 }
1124 
1125 static void
1126 print_dds(
1127 	char *ident,
1128 	isns_obj_t *obj
1129 )
1130 {
1131 	uchar_t *name = obj->attrs[ATTR_INDEX_DDS(
1132 	    ISNS_DD_SET_NAME_ATTR_ID)].value.ptr;
1133 	uint32_t uid = obj->attrs[UID_ATTR_INDEX[OBJ_DDS]].value.ui;
1134 	uint32_t enabled = obj->attrs[ATTR_INDEX_DDS(
1135 	    ISNS_DD_SET_STATUS_ATTR_ID)].value.ui;
1136 
1137 	if (ident != NULL) {
1138 		printf("%s%d\t%s\t\t(%s)\n", ident, uid,
1139 		    (const char *)name, enabled ? "enabled" : "disabled");
1140 	} else {
1141 		printf("%d\t%s\t\t(%s)\n", uid,
1142 		    (const char *)name, enabled ? "enabled" : "disabled");
1143 	}
1144 }
1145 
1146 void
1147 print_object(
1148 	char *ident,
1149 	isns_obj_t *obj
1150 )
1151 {
1152 	print_func[obj->type](ident, obj);
1153 }
1154 
1155 /*ARGSUSED*/
1156 static int
1157 cb_print_obj_n(
1158 	void *p1,
1159 	void *p2
1160 )
1161 {
1162 	isns_obj_t *obj = (isns_obj_t *)p1;
1163 	print_func[obj->type](NULL, obj);
1164 
1165 	return (0);
1166 }
1167 
1168 static void
1169 list_pg(
1170 )
1171 {
1172 	cache_dump_htab(OBJ_PG);
1173 }
1174 
1175 static void
1176 list_portal(
1177 )
1178 {
1179 	cache_dump_htab(OBJ_PORTAL);
1180 }
1181 
1182 static void
1183 list_node(
1184 )
1185 {
1186 	cache_dump_htab(OBJ_ISCSI);
1187 }
1188 
1189 static void
1190 list_entity(
1191 )
1192 {
1193 	cache_dump_htab(OBJ_ENTITY);
1194 }
1195 
1196 static void
1197 list_dd(
1198 )
1199 {
1200 	cache_dump_htab(OBJ_DD);
1201 }
1202 
1203 static void
1204 list_ddn(
1205 	uint32_t uid
1206 )
1207 {
1208 	lookup_ctrl_t lc;
1209 
1210 	bmp_t *p;
1211 	uint32_t n;
1212 
1213 	if (uid != 0) {
1214 		setup_ddid_lcp(&lc, uid);
1215 		cache_lookup(&lc, &uid, cb_print_obj_n);
1216 	}
1217 
1218 	if (uid != 0) {
1219 		printf("--------------------------------\n");
1220 		get_dd_matrix(uid, &p, &n);
1221 		SET_UID_LCP(&lc, OBJ_ISCSI, 0);
1222 		FOR_EACH_MEMBER(p, n, uid, {
1223 			lc.data[0].ui = uid;
1224 			cache_lookup(&lc, NULL, cb_print_obj_n);
1225 		});
1226 		free(p);
1227 	} else {
1228 		printf("no such dd.\n");
1229 	}
1230 }
1231 
1232 static void
1233 list_ddsn(
1234 	uint32_t uid
1235 )
1236 {
1237 	lookup_ctrl_t lc;
1238 
1239 	bmp_t *p;
1240 	uint32_t n;
1241 
1242 	if (uid != 0) {
1243 		setup_ddsid_lcp(&lc, uid);
1244 		cache_lookup(&lc, &uid, cb_print_obj_n);
1245 	}
1246 
1247 	if (uid != 0) {
1248 		printf("--------------------------------\n");
1249 		get_dds_matrix(uid, &p, &n);
1250 		SET_UID_LCP(&lc, OBJ_DD, 0);
1251 		FOR_EACH_MEMBER(p, n, uid, {
1252 			lc.data[0].ui = uid;
1253 			cache_lookup(&lc, NULL, cb_print_obj_n);
1254 		});
1255 		free(p);
1256 	} else {
1257 		printf("no such dd-set.\n");
1258 	}
1259 }
1260 
1261 static void
1262 list_dds(
1263 )
1264 {
1265 	cache_dump_htab(OBJ_DDS);
1266 }
1267 
1268 static void
1269 new_dd_dds(
1270 	int cmd_id,
1271 	int argc,
1272 	int *argv
1273 )
1274 {
1275 	uint32_t buff[256];
1276 	isns_pdu_t *pdu = (isns_pdu_t *)buff;
1277 	uint8_t *payload = &pdu->payload[0];
1278 	uint16_t payload_len = 0;
1279 	isns_tlv_t *tlv;
1280 
1281 	int len = 0;
1282 	uint32_t uid = 0;
1283 	char *name;
1284 
1285 	conn_arg_t conn;
1286 
1287 	pdu->version = ISNSP_VERSION;
1288 
1289 	/* source attribute */
1290 	tlv = (isns_tlv_t *)payload;
1291 	tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID);
1292 	tlv->attr_len = htonl(32);
1293 	strcpy((char *)tlv->attr_value, "i am a control node.");
1294 	payload += 8 + 32;
1295 	payload_len += 8 + 32;
1296 
1297 	/* key attributes */
1298 
1299 	/* delimiter */
1300 	tlv = (isns_tlv_t *)payload;
1301 	tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID);
1302 	tlv->attr_len = htonl(0);
1303 	payload += 8 + 0;
1304 	payload_len += 8 + 0;
1305 
1306 	/* operating attributes */
1307 	switch (cmd_id) {
1308 	case CMD_NEWDD:
1309 		pdu->func_id = ISNS_DD_REG;
1310 		if (argc == 1) {
1311 			name = (char *)argv[0];
1312 			len = strlen(name) + 1;
1313 			len += 4 - (len % 4);
1314 		}
1315 		tlv = (isns_tlv_t *)payload;
1316 		tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID);
1317 		tlv->attr_len = htonl(len);
1318 		if (len > 0) {
1319 			strcpy((char *)tlv->attr_value, name);
1320 		}
1321 		payload_len += 8 + len;
1322 		break;
1323 	case CMD_NEWDDS:
1324 		pdu->func_id = ISNS_DDS_REG;
1325 		if (argc == 1) {
1326 			name = (char *)argv[0];
1327 			len = strlen(name) + 1;
1328 			len += 4 - (len % 4);
1329 		}
1330 		tlv = (isns_tlv_t *)payload;
1331 		tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID);
1332 		tlv->attr_len = htonl(len);
1333 		if (len > 0) {
1334 			strcpy((char *)tlv->attr_value, name);
1335 		}
1336 		payload_len += 8 + len;
1337 		break;
1338 	case CMD_NEWDDN:
1339 		pdu->func_id = ISNS_DD_REG;
1340 		switch (argc) {
1341 		case 2:
1342 			name = (char *)argv[1];
1343 			len = strlen(name) + 1;
1344 			len += 4 - (len % 4);
1345 		case 1:
1346 			uid = argv[0];
1347 		}
1348 		tlv = (isns_tlv_t *)payload;
1349 		tlv->attr_id = htonl(ISNS_DD_NAME_ATTR_ID);
1350 		tlv->attr_len = htonl(len);
1351 		if (len > 0) {
1352 			strcpy((char *)tlv->attr_value, name);
1353 		}
1354 		payload += 8 + len;
1355 		payload_len += 8 + len;
1356 		if (uid > 0) {
1357 			tlv = (isns_tlv_t *)payload;
1358 			tlv->attr_id = htonl(ISNS_DD_ID_ATTR_ID);
1359 			tlv->attr_len = htonl(4);
1360 			*(uint32_t *)tlv->attr_value = htonl(uid);
1361 			payload_len += 8 + 4;
1362 		}
1363 		break;
1364 	case CMD_NEWDDSN:
1365 		pdu->func_id = ISNS_DDS_REG;
1366 		switch (argc) {
1367 		case 2:
1368 			name = (char *)argv[1];
1369 			len = strlen(name) + 1;
1370 			len += 4 - (len % 4);
1371 		case 1:
1372 			uid = argv[0];
1373 		}
1374 		tlv = (isns_tlv_t *)payload;
1375 		tlv->attr_id = htonl(ISNS_DD_SET_NAME_ATTR_ID);
1376 		tlv->attr_len = htonl(len);
1377 		if (len > 0) {
1378 			strcpy((char *)tlv->attr_value, name);
1379 		}
1380 		payload_len += 8 + len;
1381 		payload += 8 + len;
1382 		if (uid > 0) {
1383 			tlv = (isns_tlv_t *)payload;
1384 			tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID);
1385 			tlv->attr_len = htonl(4);
1386 			*(uint32_t *)tlv->attr_value = htonl(uid);
1387 			payload_len += 8 + 4;
1388 		}
1389 		break;
1390 	default:
1391 		break;
1392 	}
1393 
1394 	pdu->payload_len = payload_len;
1395 
1396 	dump_pdu1(pdu);
1397 
1398 	conn.in_packet.pdu = pdu;
1399 	conn.out_packet.pdu = NULL;
1400 	conn.out_packet.sz = 0;
1401 
1402 	if (packet_split_verify(&conn) == 0) {
1403 		cache_lock(conn.lock);
1404 		conn.handler(&conn);
1405 		conn.ec = cache_unlock(conn.lock, conn.ec);
1406 	}
1407 
1408 	if (conn.out_packet.pdu != NULL) {
1409 		pdu_update_code(conn.out_packet.pdu,
1410 		    &conn.out_packet.pl, conn.ec);
1411 		dump_pdu2(conn.out_packet.pdu);
1412 		free(conn.out_packet.pdu);
1413 	} else if (conn.ec != 0) {
1414 		printf("operation failed[%d].\n", conn.ec);
1415 	}
1416 }
1417 
1418 static void
1419 del_dd_dds(
1420 	int cmd_id,
1421 	int uid
1422 )
1423 {
1424 	uint32_t buff[256];
1425 	isns_pdu_t *pdu = (isns_pdu_t *)buff;
1426 	uint8_t *payload = &pdu->payload[0];
1427 	uint16_t payload_len = 0;
1428 	isns_tlv_t *tlv;
1429 
1430 	uint32_t tag;
1431 
1432 	conn_arg_t conn;
1433 
1434 	if (uid == 0) {
1435 		return;
1436 	}
1437 
1438 	pdu->version = ISNSP_VERSION;
1439 
1440 	if (cmd_id == CMD_DELDD) {
1441 		tag = ISNS_DD_ID_ATTR_ID;
1442 		pdu->func_id = ISNS_DD_DEREG;
1443 	} else {
1444 		tag = ISNS_DD_SET_ID_ATTR_ID;
1445 		pdu->func_id = ISNS_DDS_DEREG;
1446 	}
1447 
1448 	/* source attribute */
1449 	tlv = (isns_tlv_t *)payload;
1450 	tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID);
1451 	tlv->attr_len = htonl(32);
1452 	strcpy((char *)tlv->attr_value, "i am a control node.");
1453 	payload_len += 8 + 32;
1454 	payload += 8 + 32;
1455 
1456 	/* key attributes */
1457 	tlv = (isns_tlv_t *)payload;
1458 	tlv->attr_id = htonl(tag);
1459 	tlv->attr_len = htonl(4);
1460 	*(uint32_t *)tlv->attr_value = htonl(uid);
1461 	payload_len += 8 + 4;
1462 	payload += 8 + 4;
1463 
1464 	/* delimiter */
1465 	tlv = (isns_tlv_t *)payload;
1466 	tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID);
1467 	tlv->attr_len = htonl(0);
1468 	payload_len += 8 + 0;
1469 	payload += 8 + 0;
1470 
1471 	/* operating attributes */
1472 
1473 	pdu->payload_len = payload_len;
1474 
1475 	dump_pdu1(pdu);
1476 
1477 	conn.in_packet.pdu = pdu;
1478 	conn.out_packet.pdu = NULL;
1479 	conn.out_packet.sz = 0;
1480 
1481 	if (packet_split_verify(&conn) == 0) {
1482 		cache_lock(conn.lock);
1483 		conn.handler(&conn);
1484 		conn.ec = cache_unlock(conn.lock, conn.ec);
1485 	}
1486 
1487 	if (conn.out_packet.pdu != NULL) {
1488 		pdu_update_code(conn.out_packet.pdu,
1489 		    &conn.out_packet.pl, conn.ec);
1490 		dump_pdu2(conn.out_packet.pdu);
1491 		free(conn.out_packet.pdu);
1492 	} else if (conn.ec != 0) {
1493 		printf("operation failed[%d].\n", conn.ec);
1494 	}
1495 }
1496 
1497 static void
1498 update_dds(
1499 	int cmd_id,
1500 	int uid
1501 )
1502 {
1503 	uint32_t buff[256];
1504 	isns_pdu_t *pdu = (isns_pdu_t *)buff;
1505 	uint8_t *payload = &pdu->payload[0];
1506 	uint16_t payload_len = 0;
1507 	isns_tlv_t *tlv;
1508 
1509 	conn_arg_t conn;
1510 
1511 	if (uid == 0) {
1512 		return;
1513 	}
1514 
1515 	pdu->version = ISNSP_VERSION;
1516 
1517 	pdu->func_id = ISNS_DDS_REG;
1518 
1519 	/* source attribute */
1520 	tlv = (isns_tlv_t *)payload;
1521 	tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID);
1522 	tlv->attr_len = htonl(32);
1523 	strcpy((char *)tlv->attr_value, "i am a control node.");
1524 	payload_len += 8 + 32;
1525 	payload += 8 + 32;
1526 
1527 	/* key attributes */
1528 	tlv = (isns_tlv_t *)payload;
1529 	tlv->attr_id = htonl(ISNS_DD_SET_ID_ATTR_ID);
1530 	tlv->attr_len = htonl(4);
1531 	*(uint32_t *)tlv->attr_value = htonl(uid);
1532 	payload_len += 8 + 4;
1533 	payload += 8 + 4;
1534 
1535 	/* delimiter */
1536 	tlv = (isns_tlv_t *)payload;
1537 	tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID);
1538 	tlv->attr_len = htonl(0);
1539 	payload_len += 8 + 0;
1540 	payload += 8 + 0;
1541 
1542 	/* operating attributes */
1543 	tlv = (isns_tlv_t *)payload;
1544 	tlv->attr_id = htonl(ISNS_DD_SET_STATUS_ATTR_ID);
1545 	tlv->attr_len = htonl(4);
1546 	if (cmd_id == CMD_ENABLE) {
1547 		*(uint32_t *)tlv->attr_value = htonl(1);
1548 	} else {
1549 		*(uint32_t *)tlv->attr_value = htonl(0);
1550 	}
1551 	payload_len += 8 + 4;
1552 
1553 	pdu->payload_len = payload_len;
1554 
1555 	dump_pdu1(pdu);
1556 
1557 	conn.in_packet.pdu = pdu;
1558 	conn.out_packet.pdu = NULL;
1559 	conn.out_packet.sz = 0;
1560 
1561 	if (packet_split_verify(&conn) == 0) {
1562 		cache_lock(conn.lock);
1563 		conn.handler(&conn);
1564 		conn.ec = cache_unlock(conn.lock, conn.ec);
1565 	}
1566 
1567 	if (conn.out_packet.pdu != NULL) {
1568 		pdu_update_code(conn.out_packet.pdu,
1569 		    &conn.out_packet.pl, conn.ec);
1570 		dump_pdu2(conn.out_packet.pdu);
1571 		free(conn.out_packet.pdu);
1572 	} else if (conn.ec != 0) {
1573 		printf("operation failed[%d].\n", conn.ec);
1574 	}
1575 }
1576 
1577 static void
1578 update_member(
1579 	int cmd_id,
1580 	int *argv
1581 )
1582 {
1583 	uint32_t buff[256];
1584 	isns_pdu_t *pdu = (isns_pdu_t *)buff;
1585 	uint8_t *payload = &pdu->payload[0];
1586 	uint16_t payload_len = 0;
1587 	isns_tlv_t *tlv;
1588 	uint32_t key_tag, op_tag, op_len;
1589 
1590 	uint32_t uid = argv[0];
1591 	uint32_t m_id;
1592 	char *m_name;
1593 
1594 	conn_arg_t conn;
1595 
1596 	if (uid == 0) {
1597 		printf("operation failed.\n");
1598 		return;
1599 	}
1600 
1601 	pdu->version = ISNSP_VERSION;
1602 
1603 	switch (cmd_id) {
1604 	case CMD_ADDDD:
1605 	case CMD_ADDDDN:
1606 		pdu->func_id = ISNS_DD_REG;
1607 		break;
1608 	case CMD_REMDD:
1609 	case CMD_REMDDN:
1610 		pdu->func_id = ISNS_DD_DEREG;
1611 		break;
1612 	case CMD_ADDDDSN:
1613 		pdu->func_id = ISNS_DDS_REG;
1614 		break;
1615 	case CMD_REMDDSN:
1616 		pdu->func_id = ISNS_DDS_DEREG;
1617 		break;
1618 	}
1619 	switch (cmd_id) {
1620 	case CMD_ADDDD:
1621 	case CMD_REMDD:
1622 		key_tag = ISNS_DD_ID_ATTR_ID;
1623 		op_tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
1624 		m_name = (char *)argv[1];
1625 		op_len = strlen(m_name);
1626 		op_len += 4 - (op_len % 4);
1627 		break;
1628 	case CMD_ADDDDN:
1629 	case CMD_REMDDN:
1630 		key_tag = ISNS_DD_ID_ATTR_ID;
1631 		op_tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
1632 		m_id = argv[1];
1633 		op_len = 4;
1634 		break;
1635 	case CMD_ADDDDSN:
1636 	case CMD_REMDDSN:
1637 		key_tag = ISNS_DD_SET_ID_ATTR_ID;
1638 		op_tag = ISNS_DD_ID_ATTR_ID;
1639 		m_id = argv[1];
1640 		op_len = 4;
1641 		break;
1642 	}
1643 
1644 	/* source attribute */
1645 	tlv = (isns_tlv_t *)payload;
1646 	tlv->attr_id = htonl(ISNS_ISCSI_NAME_ATTR_ID);
1647 	tlv->attr_len = htonl(32);
1648 	strcpy((char *)tlv->attr_value, "i am a control node.");
1649 	payload_len += 8 + 32;
1650 	payload += 8 + 32;
1651 
1652 	/* key attributes */
1653 	tlv = (isns_tlv_t *)payload;
1654 	tlv->attr_id = htonl(key_tag);
1655 	tlv->attr_len = htonl(4);
1656 	*(uint32_t *)tlv->attr_value = htonl(uid);
1657 	payload_len += 8 + 4;
1658 	payload += 8 + 4;
1659 
1660 	/* delimiter */
1661 	tlv = (isns_tlv_t *)payload;
1662 	tlv->attr_id = htonl(ISNS_DELIMITER_ATTR_ID);
1663 	tlv->attr_len = htonl(0);
1664 	payload_len += 8 + 0;
1665 	payload += 8 + 0;
1666 
1667 	/* operating attributes */
1668 	tlv = (isns_tlv_t *)payload;
1669 	tlv->attr_id = htonl(op_tag);
1670 	tlv->attr_len = htonl(op_len);
1671 	switch (cmd_id) {
1672 	case CMD_ADDDD:
1673 	case CMD_REMDD:
1674 		strcpy((char *)tlv->attr_value, m_name);
1675 		break;
1676 	case CMD_ADDDDN:
1677 	case CMD_ADDDDSN:
1678 	case CMD_REMDDN:
1679 	case CMD_REMDDSN:
1680 		*(uint32_t *)tlv->attr_value = htonl(m_id);
1681 		break;
1682 	}
1683 	payload_len += 8 + op_len;
1684 
1685 	pdu->payload_len = payload_len;
1686 
1687 	dump_pdu1(pdu);
1688 
1689 	conn.in_packet.pdu = pdu;
1690 	conn.out_packet.pdu = NULL;
1691 	conn.out_packet.sz = 0;
1692 
1693 	if (packet_split_verify(&conn) == 0) {
1694 		cache_lock(conn.lock);
1695 		conn.handler(&conn);
1696 		conn.ec = cache_unlock(conn.lock, conn.ec);
1697 	}
1698 
1699 	if (conn.out_packet.pdu != NULL) {
1700 		pdu_update_code(conn.out_packet.pdu,
1701 		    &conn.out_packet.pl, conn.ec);
1702 		dump_pdu2(conn.out_packet.pdu);
1703 		free(conn.out_packet.pdu);
1704 	} else if (conn.ec != 0) {
1705 		printf("operation failed[%d].\n", conn.ec);
1706 	}
1707 }
1708 
1709 static void
1710 cmd_file(
1711 	char *file
1712 )
1713 {
1714 	char i = 0, ch, cmd[256];
1715 	FILE *f = fopen(file, "r");
1716 	if (f != NULL) {
1717 		while ((ch = fgetc(f)) != 0 && ch != EOF) {
1718 			if (ch == '\t') {
1719 				cmd[i++] = ' ';
1720 			} else if (ch != '\n') {
1721 				cmd[i++] = ch;
1722 			} else {
1723 				cmd[i ++] = ' ';
1724 				cmd[i] = 0;
1725 				i = 0;
1726 				printf("%s\n", cmd);
1727 				if (run_cmd(cmd) != 0) {
1728 					break;
1729 				}
1730 			}
1731 		}
1732 		fclose(f);
1733 	} else {
1734 		printf("Cannot open file %s.\n", file);
1735 	}
1736 }
1737 
1738 static int
1739 run_cmd(
1740 	char *cmd
1741 )
1742 {
1743 	int argc, argv[32];
1744 	int cmd_id;
1745 	cmd_id = getcmd(&argc, argv, cmd);
1746 	switch (cmd_id) {
1747 		case CMD_LIST:
1748 			list_node();
1749 			break;
1750 		case CMD_LISTNE:
1751 			list_entity();
1752 			break;
1753 		case CMD_LISTP:
1754 			list_portal();
1755 			break;
1756 		case CMD_LISTPG:
1757 			list_pg();
1758 			break;
1759 		case CMD_LISTDD:
1760 			list_dd();
1761 			break;
1762 		case CMD_LISTDDS:
1763 			list_dds();
1764 			break;
1765 		case CMD_LISTDDN:
1766 			list_ddn(argv[0]);
1767 			break;
1768 		case CMD_LISTDDSN:
1769 			list_ddsn(argv[0]);
1770 			break;
1771 		case CMD_NEWDD:
1772 		case CMD_NEWDDS:
1773 		case CMD_NEWDDN:
1774 		case CMD_NEWDDSN:
1775 			new_dd_dds(cmd_id, argc, argv);
1776 			break;
1777 		case CMD_DELDD:
1778 		case CMD_DELDDS:
1779 			del_dd_dds(cmd_id, argv[0]);
1780 			break;
1781 		case CMD_ENABLE:
1782 		case CMD_DISABLE:
1783 			update_dds(cmd_id, argv[0]);
1784 			break;
1785 		case CMD_ADDDD:
1786 		case CMD_ADDDDN:
1787 		case CMD_ADDDDSN:
1788 		case CMD_REMDD:
1789 		case CMD_REMDDN:
1790 		case CMD_REMDDSN:
1791 			update_member(cmd_id, argv);
1792 			break;
1793 		case CMD_PAUSE:
1794 			printf("Press enter to continue...");
1795 			getchar();
1796 			break;
1797 		case CMD_FILE:
1798 			cmd_file((char *)argv[0]);
1799 			break;
1800 		case CMD_HELP:
1801 			test_cli_help();
1802 			break;
1803 		case CMD_VERBOSE_MEMORY:
1804 			verbose_mc = !verbose_mc;
1805 			break;
1806 		case CMD_VERBOSE_NET:
1807 			verbose_net = !verbose_net;
1808 			break;
1809 		case CMD_VERBOSE_TIME:
1810 			verbose_tc = !verbose_tc;
1811 			break;
1812 		case CMD_VERBOSE_LOCK:
1813 			verbose_lock = !verbose_lock;
1814 			break;
1815 		case CMD_VERBOSE_PARSER:
1816 			verbose_parser = !verbose_parser;
1817 			break;
1818 		case CMD_QUIT:
1819 			/* clean up cli */
1820 			/* notify sys control */
1821 			shutdown_server();
1822 			return (1);
1823 		case CMD_NONE:
1824 			break;
1825 		default:
1826 			printf("invalid command\n");
1827 			break;
1828 	}
1829 	if (cmd_id != CMD_NONE) {
1830 		printf("\n>");
1831 	} else {
1832 		printf(">");
1833 	}
1834 	return (0);
1835 }
1836 
1837 /*ARGSUSED*/
1838 void *cli_test(void *arg) {
1839 	char i = 0, ch, cmd[256];
1840 
1841 	printf("iSNS Server test CLI.\n");
1842 	printf("Copyright 2007 Sun Microsystems, Inc.\n");
1843 
1844 	printf("\n>");
1845 	while ((ch = getchar()) != 0 && ch != EOF) {
1846 		if (ch == '\t') {
1847 			cmd[i++] = ' ';
1848 		} else if (ch != '\n') {
1849 			cmd[i++] = ch;
1850 		} else {
1851 			cmd[i ++] = ' ';
1852 			cmd[i] = 0;
1853 			i = 0;
1854 			if (run_cmd(cmd) != 0) {
1855 				break;
1856 			}
1857 		}
1858 	}
1859 
1860 	return (NULL);
1861 }
1862 #endif
1863