xref: /illumos-gate/usr/src/cmd/isns/isnsd/qry.c (revision 125be069be21bcb7b94bd4525c19eb424bc56276)
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 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "isns_server.h"
32 #include "isns_func.h"
33 #include "isns_msgq.h"
34 #include "isns_htab.h"
35 #include "isns_cache.h"
36 #include "isns_obj.h"
37 #include "isns_dd.h"
38 #include "isns_pdu.h"
39 #include "isns_qry.h"
40 
41 /*
42  * external variables
43  */
44 extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE];
45 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
46 extern const int NUM_OF_CHILD[MAX_OBJ_TYPE];
47 extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE];
48 
49 /*
50  * global variables
51  */
52 const int TAG_RANGE[MAX_OBJ_TYPE][3] = {
53 	{ 0, 0 },
54 	{ ENTITY_KEY, LAST_TAG_ENTITY, ENTITY_END },
55 	{ ISCSI_KEY, LAST_TAG_ISCSI, ISCSI_END },
56 	{ PORTAL_KEY1, LAST_TAG_PORTAL, PORTAL_END },
57 	{ PG_KEY1, LAST_TAG_PG, PG_END },
58 	{ DD_KEY, LAST_TAG_DD, DD_END },
59 	{ DDS_KEY, LAST_TAG_DDS, DDS_END }
60 };
61 
62 /*
63  * local variables
64  */
65 typedef int (*qry_func_t)(lookup_ctrl_t *);
66 
67 /* Edge functions of each adjacent object */
68 static int qry_c2e(lookup_ctrl_t *);
69 static int qry_ds2m(lookup_ctrl_t *);
70 static int qry_slf(lookup_ctrl_t *);
71 static int qry_e2i(lookup_ctrl_t *);
72 static int qry_e2p(lookup_ctrl_t *);
73 static int qry_e2g(lookup_ctrl_t *);
74 static int qry_i2g(lookup_ctrl_t *);
75 static int qry_i2d(lookup_ctrl_t *);
76 static int qry_p2g(lookup_ctrl_t *);
77 static int qry_g2i(lookup_ctrl_t *);
78 static int qry_g2p(lookup_ctrl_t *);
79 static int qry_d2s(lookup_ctrl_t *);
80 
81 /* The directed cyclic graph of query procedure. */
82 /* __|____e_________i_________p_________g_________d_________s____ */
83 /* e | qry_slf...qry_e2i...qry_e2p...qry_e2g...NULL......NULL.... */
84 /* i | qry_c2e...qry_slf...NULL......qry_i2g...qry_i2d...NULL.... */
85 /* p | qry_c2e...NULL......qry_slf...qry_p2g...NULL......NULL.... */
86 /* g | qry_c2e...qry_g2i...qry_g2p...qry_slf...NULL......NULL.... */
87 /* d | NULL......qry_ds2m..NULL......NULL......qry_slf...qry_d2s. */
88 /* s | NULL......NULL......NULL......NULL......qry_ds2m..qry_slf. */
89 
90 /* The type of spanning tree of query graph. */
91 typedef struct adjvex {
92 	qry_func_t f;
93 	isns_type_t t;
94 	struct adjvex const *v;
95 } adjvex_t;
96 
97 /* The solid edges in the spanning tree. */
98 static const adjvex_t v_slf = { &qry_slf,  0,		NULL };
99 static const adjvex_t v_c2e = { &qry_c2e,  OBJ_ENTITY,	NULL };
100 static const adjvex_t v_e2i = { &qry_e2i,  OBJ_ISCSI,	NULL };
101 static const adjvex_t v_e2p = { &qry_e2p,  OBJ_PORTAL,	NULL };
102 static const adjvex_t v_e2g = { &qry_e2g,  OBJ_PG,	NULL };
103 static const adjvex_t v_i2g = { &qry_i2g,  OBJ_PG,	NULL };
104 static const adjvex_t v_i2d = { &qry_i2d,  OBJ_DD,	NULL };
105 static const adjvex_t v_p2g = { &qry_p2g,  OBJ_PG,	NULL };
106 static const adjvex_t v_g2i = { &qry_g2i,  OBJ_ISCSI,	NULL };
107 static const adjvex_t v_g2p = { &qry_g2p,  OBJ_PORTAL,	NULL };
108 static const adjvex_t v_d2s = { &qry_d2s,  OBJ_DDS,	NULL };
109 static const adjvex_t v_d2i = { &qry_ds2m, OBJ_ISCSI,	NULL };
110 static const adjvex_t v_s2d = { &qry_ds2m, OBJ_DD,	NULL };
111 
112 /* The virtual edges in the spanning tree. */
113 static const adjvex_t v_i2p = { &qry_i2g,  OBJ_PG,    &v_g2p };
114 static const adjvex_t v_i2s = { &qry_i2d,  OBJ_DD,    &v_d2s };
115 
116 static const adjvex_t v_g2d = { &qry_g2i,  OBJ_ISCSI, &v_i2d };
117 static const adjvex_t v_g2s = { &qry_g2i,  OBJ_ISCSI, &v_i2s };
118 
119 static const adjvex_t v_p2i = { &qry_p2g,  OBJ_PG,    &v_g2i };
120 static const adjvex_t v_p2d = { &qry_p2g,  OBJ_PG,    &v_g2d };
121 static const adjvex_t v_p2s = { &qry_p2g,  OBJ_PG,    &v_g2s };
122 
123 static const adjvex_t v_e2d = { &qry_e2i,  OBJ_ISCSI, &v_i2d };
124 static const adjvex_t v_e2s = { &qry_e2i,  OBJ_ISCSI, &v_i2s };
125 
126 static const adjvex_t v_d2e = { &qry_ds2m, OBJ_ISCSI, &v_c2e };
127 static const adjvex_t v_d2p = { &qry_ds2m, OBJ_ISCSI, &v_i2p };
128 static const adjvex_t v_d2g = { &qry_ds2m, OBJ_ISCSI, &v_i2g };
129 
130 static const adjvex_t v_s2e = { &qry_ds2m, OBJ_DD,    &v_d2e };
131 static const adjvex_t v_s2i = { &qry_ds2m, OBJ_DD,    &v_d2i };
132 static const adjvex_t v_s2p = { &qry_ds2m, OBJ_DD,    &v_d2p };
133 static const adjvex_t v_s2g = { &qry_ds2m, OBJ_DD,    &v_d2g };
134 
135 /* the vector of query graph */
136 static const adjvex_t *qry_puzzle[MAX_OBJ_TYPE][MAX_OBJ_TYPE] = {
137 { NULL },
138 { NULL, &v_slf, &v_e2i, &v_e2p, &v_e2g, &v_e2d, &v_e2s },
139 { NULL, &v_c2e, &v_slf, &v_i2p, &v_i2g, &v_i2d, &v_i2s },
140 { NULL, &v_c2e, &v_p2i, &v_slf, &v_p2g, &v_p2d, &v_p2s },
141 { NULL, &v_c2e, &v_g2i, &v_g2p, &v_slf, &v_g2d, &v_g2s },
142 { NULL, &v_d2e, &v_d2i, &v_d2p, &v_d2g, &v_slf, &v_d2s },
143 { NULL, &v_s2e, &v_s2i, &v_s2p, &v_s2g, &v_s2d, &v_slf }
144 };
145 
146 static int
147 cb_qry_parent_uid(
148 	void *p1,
149 	/* LINTED E_FUNC_ARG_UNUSED */
150 	void *p2
151 )
152 {
153 	uint32_t puid = get_parent_uid((isns_obj_t *)p1);
154 	return ((int)puid);
155 }
156 
157 static int
158 cb_qry_child_uids(
159 	void *p1,
160 	void *p2
161 )
162 {
163 	isns_obj_t *obj = (isns_obj_t *)p1;
164 	lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
165 	isns_type_t type = lcp->data[1].ui;
166 	uint32_t *uidp = get_child_t(obj, type);
167 	uint32_t num = 0;
168 	uint32_t *p;
169 
170 	if (uidp != NULL && *uidp > 0) {
171 		num = *uidp;
172 		p = malloc(num * sizeof (*p));
173 		if (p != NULL) {
174 			uidp ++;
175 			(void) memcpy(p, uidp, num * sizeof (*p));
176 			lcp->id[2] = num;
177 			lcp->data[2].ptr = (uchar_t *)p;
178 		} else {
179 			return (ISNS_RSP_INTERNAL_ERROR);
180 		}
181 	}
182 
183 	return (0);
184 }
185 
186 static int
187 e2c(
188 	lookup_ctrl_t *lcp,
189 	isns_type_t type
190 )
191 {
192 	int ec = 0;
193 
194 	uint32_t uid = lcp->curr_uid; /* last child */
195 	uint32_t num_of_child;
196 	uint32_t *uids;
197 
198 	uint32_t tmp_uid = 0;
199 
200 	/* the first times of query */
201 	if (uid == 0) {
202 		lcp->data[1].ui = type;
203 		ec = cache_lookup(lcp, NULL, cb_qry_child_uids);
204 	}
205 
206 	num_of_child = lcp->id[2];
207 	uids = (uint32_t *)lcp->data[2].ptr;
208 
209 	while (num_of_child > 0) {
210 		if (*uids > uid) {
211 			tmp_uid = *uids;
212 			break;
213 		}
214 		uids ++;
215 		num_of_child --;
216 	}
217 
218 	uid = tmp_uid;
219 
220 	/* no more child, clean up memory */
221 	if (uid == 0) {
222 		lcp->data[1].ui = 0;
223 		lcp->id[2] = 0;
224 		lcp->data[2].ptr = NULL;
225 
226 		/* free up the memory */
227 		free(uids);
228 	}
229 
230 	/* save it for returning and querying next uid */
231 	lcp->curr_uid = uid;
232 
233 	return (ec);
234 }
235 
236 static int
237 qry_c2e(
238 	lookup_ctrl_t *lcp
239 )
240 {
241 	uint32_t uid;
242 
243 	/* child object has only one parent */
244 	if (lcp->curr_uid == 0) {
245 		uid = (uint32_t)cache_lookup(lcp, NULL,
246 		    cb_qry_parent_uid);
247 	} else {
248 		uid = 0;
249 	}
250 
251 	/* save the result for returnning */
252 	lcp->curr_uid = uid;
253 
254 	return (0);
255 }
256 
257 static int
258 qry_ds2m(
259 	lookup_ctrl_t *lcp
260 )
261 {
262 	int ec = 0;
263 
264 	uint32_t uid = lcp->curr_uid; /* last member */
265 	isns_type_t type = lcp->type;
266 	uint32_t ds_id = lcp->data[0].ui;
267 
268 	uint32_t tmp_uid;
269 
270 	uint32_t n;
271 	bmp_t *p;
272 
273 	/* the first times of query */
274 	if (uid == 0) {
275 		ec = (type == OBJ_DD) ?
276 		    get_dd_matrix(ds_id, &p, &n) :
277 		    get_dds_matrix(ds_id, &p, &n);
278 		lcp->id[1] = n;
279 		lcp->data[1].ptr = (uchar_t *)p;
280 	} else {
281 		n = lcp->id[1];
282 		p = (bmp_t *)lcp->data[1].ptr;
283 	}
284 
285 	FOR_EACH_MEMBER(p, n, tmp_uid, {
286 		if (tmp_uid > uid) {
287 			lcp->curr_uid = tmp_uid;
288 			return (ec);
289 		}
290 	});
291 
292 	/* no more member, clean up memory */
293 	lcp->id[1] = 0;
294 	lcp->data[1].ptr = NULL;
295 
296 	/* free up the matrix */
297 	free(p);
298 
299 	lcp->curr_uid = 0;
300 
301 	return (ec);
302 }
303 
304 static int
305 qry_slf(
306 	lookup_ctrl_t *lcp
307 )
308 {
309 	uint32_t uid;
310 
311 	if (lcp->curr_uid == 0) {
312 		uid = lcp->data[0].ui;
313 	} else {
314 		uid = 0;
315 	}
316 
317 	lcp->curr_uid = uid;
318 
319 	return (0);
320 }
321 
322 static int
323 qry_e2i(
324 	lookup_ctrl_t *lcp
325 )
326 {
327 	return (e2c(lcp, OBJ_ISCSI));
328 }
329 
330 static int
331 qry_e2p(
332 	lookup_ctrl_t *lcp
333 )
334 {
335 	return (e2c(lcp, OBJ_PORTAL));
336 }
337 
338 static int
339 qry_e2g(
340 	lookup_ctrl_t *lcp
341 )
342 {
343 	uint32_t uid = lcp->curr_uid; /* last pg */
344 
345 	htab_t *htab = cache_get_htab(OBJ_PG);
346 
347 	lookup_ctrl_t lc;
348 	uint32_t puid;
349 
350 	SET_UID_LCP(&lc, OBJ_PG, 0);
351 
352 	/* this is a shortcut */
353 	FOR_EACH_ITEM(htab, uid, {
354 		lc.data[0].ui = uid;
355 		puid = (uint32_t)cache_lookup(&lc, NULL,
356 		    cb_qry_parent_uid);
357 		if (puid == lcp->data[0].ui) {
358 			/* keep the current uid */
359 			lcp->curr_uid = uid;
360 			return (0);
361 		}
362 	});
363 
364 	lcp->curr_uid = 0;
365 
366 	return (0);
367 }
368 
369 static int
370 qry_i2g(
371 	lookup_ctrl_t *lcp
372 )
373 {
374 	int ec = 0;
375 
376 	uint32_t uid = lcp->curr_uid; /* last pg */
377 	lookup_ctrl_t lc;
378 
379 	/* the first times of query */
380 	if (uid == 0) {
381 		lcp->id[1] = ISNS_ISCSI_NAME_ATTR_ID;
382 		ec = cache_lookup(lcp, NULL, cb_clone_attrs);
383 	}
384 
385 	if (lcp->data[1].ptr != NULL) {
386 		/* pg lookup */
387 		lc.curr_uid = uid;
388 		lc.type = OBJ_PG;
389 		lc.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID);
390 		lc.op[0] = OP_STRING;
391 		lc.data[0].ptr = lcp->data[1].ptr;
392 		lc.op[1] = 0;
393 
394 		uid = is_obj_there(&lc);
395 	} else {
396 		uid = 0;
397 	}
398 
399 	/* no more pg, update lcp with pg object */
400 	if (uid == 0) {
401 		lcp->id[1] = 0;
402 
403 		/* clean up the memory */
404 		if (lcp->data[1].ptr != NULL) {
405 			free(lcp->data[1].ptr);
406 			/* reset it */
407 			lcp->data[1].ptr = NULL;
408 		}
409 	}
410 
411 	/* save it for returning and querying next pg */
412 	lcp->curr_uid = uid;
413 
414 	return (ec);
415 }
416 
417 static int
418 qry_i2d(
419 	lookup_ctrl_t *lcp
420 )
421 {
422 	uint32_t dd_id = lcp->curr_uid; /* last dd_id */
423 	uint32_t uid = lcp->data[0].ui;
424 
425 	dd_id = get_dd_id(uid, dd_id);
426 
427 	/* save it for returning and getting next dd */
428 	lcp->curr_uid = dd_id;
429 
430 	return (0);
431 }
432 
433 static int
434 qry_p2g(
435 	lookup_ctrl_t *lcp
436 )
437 {
438 	int ec = 0;
439 
440 	uint32_t uid = lcp->curr_uid; /* last pg */
441 	lookup_ctrl_t lc;
442 
443 	/* the first time of query */
444 	if (uid == 0) {
445 		/* use 1&2 for the portal ip address & port */
446 		lcp->id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID;
447 		lcp->id[2] = ISNS_PORTAL_PORT_ATTR_ID;
448 		ec = cache_lookup(lcp, NULL, cb_clone_attrs);
449 	}
450 
451 	if (lcp->data[1].ip != NULL) {
452 		/* pg lookup */
453 		lc.curr_uid = uid;
454 		lc.type = OBJ_PG;
455 		lc.id[0] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID);
456 		lc.op[0] = OP_MEMORY_IP6;
457 		lc.data[0].ip = lcp->data[1].ip;
458 		lc.id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID);
459 		lc.op[1] = OP_INTEGER;
460 		lc.data[1].ui = lcp->data[2].ui;
461 		lc.op[2] = 0;
462 
463 		uid = is_obj_there(&lc);
464 	} else {
465 		uid = 0;
466 	}
467 
468 	/* no more pg, clean up memory */
469 	if (uid == 0) {
470 		lcp->id[1] = 0;
471 		lcp->id[2] = 0;
472 
473 		/* clean up the memory */
474 		if (lcp->data[1].ip != NULL) {
475 			free(lcp->data[1].ip);
476 			/* reset it */
477 			lcp->data[1].ip = NULL;
478 		}
479 		lcp->data[2].ui = 0;
480 	}
481 
482 	/* save it for returning and next query */
483 	lcp->curr_uid = uid;
484 
485 	return (ec);
486 }
487 
488 static int
489 qry_g2i(
490 	lookup_ctrl_t *lcp
491 )
492 {
493 	int ec = 0;
494 
495 	uint32_t uid = lcp->curr_uid; /* last node */
496 	lookup_ctrl_t lc;
497 
498 	/* the first time of query */
499 	if (uid == 0) {
500 		/* use slot 1 for the storage node name */
501 		lcp->id[1] = ISNS_PG_ISCSI_NAME_ATTR_ID;
502 		ec = cache_lookup(lcp, NULL, cb_clone_attrs);
503 
504 		if (lcp->data[1].ptr != NULL) {
505 			/* iscsi node lookup */
506 			lc.curr_uid = uid;
507 			lc.type = OBJ_ISCSI;
508 			lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
509 			lc.op[0] = OP_STRING;
510 			lc.data[0].ptr = lcp->data[1].ptr;
511 			lc.op[1] = 0;
512 
513 			uid = is_obj_there(&lc);
514 
515 			/* no longer need it, clean it up */
516 			free(lcp->data[1].ptr);
517 			lcp->data[1].ptr = NULL;
518 		}
519 		/* no longer need it, reset it */
520 		lcp->id[1] = 0;
521 	} else {
522 		/* one pg has maximum number of one storage node */
523 		uid = 0;
524 	}
525 
526 	/* save it for returning and next query */
527 	lcp->curr_uid = uid;
528 
529 	return (ec);
530 }
531 
532 static int
533 qry_g2p(
534 	lookup_ctrl_t *lcp
535 )
536 {
537 	int ec = 0;
538 
539 	uint32_t uid = lcp->curr_uid; /* last portal */
540 	lookup_ctrl_t lc;
541 
542 	/* the first times of query */
543 	if (uid == 0) {
544 		/* use 1&2 for the portal ip addr and port */
545 		lcp->id[1] = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID;
546 		lcp->id[2] = ISNS_PG_PORTAL_PORT_ATTR_ID;
547 		ec = cache_lookup(lcp, NULL, cb_clone_attrs);
548 
549 		if (lcp->data[1].ip != NULL) {
550 			/* portal lookup */
551 			lc.curr_uid = uid;
552 			lc.type = OBJ_PORTAL;
553 			lc.id[0] = ATTR_INDEX_PORTAL(
554 			    ISNS_PORTAL_IP_ADDR_ATTR_ID);
555 			lc.op[0] = OP_MEMORY_IP6;
556 			lc.data[0].ip = lcp->data[1].ip;
557 			lc.id[1] = ATTR_INDEX_PORTAL(
558 			    ISNS_PORTAL_PORT_ATTR_ID);
559 			lc.op[1] = OP_INTEGER;
560 			lc.data[1].ui = lcp->data[2].ui;
561 			lc.op[2] = 0;
562 
563 			uid = is_obj_there(&lc);
564 
565 			/* no longer need it, reset it */
566 			free(lcp->data[1].ip);
567 			lcp->data[1].ip = NULL;
568 		}
569 		/* no longer need it, reset it */
570 		lcp->id[1] = 0;
571 		lcp->id[2] = 0;
572 		lcp->data[2].ui = 0;
573 	} else {
574 		/* one pg has maximum number of one portal */
575 		uid = 0;
576 	}
577 
578 	/* save it for returning and next query */
579 	lcp->curr_uid = uid;
580 
581 	return (ec);
582 }
583 
584 static int
585 qry_d2s(
586 	lookup_ctrl_t *lcp
587 )
588 {
589 	uint32_t dds_id = lcp->curr_uid; /* last dds */
590 	uint32_t dd_id = lcp->data[0].ui;
591 
592 	dds_id = get_dds_id(dd_id, dds_id);
593 
594 	/* save it for returning and for getting next dds */
595 	lcp->curr_uid = dds_id;
596 
597 	return (0);
598 }
599 
600 int
601 validate_qry_key(
602 	isns_type_t type,
603 	isns_tlv_t *key,
604 	uint16_t key_len,
605 	isns_attr_t *attrs
606 )
607 {
608 	int ec = 0;
609 
610 	uint32_t tag;
611 	uint32_t min_tag, max_tag;
612 
613 	isns_attr_t *attr;
614 
615 	min_tag = TAG_RANGE[type][0];
616 	max_tag = TAG_RANGE[type][2];
617 
618 	while (key_len != 0 && ec == 0) {
619 		tag = key->attr_id;
620 		if (tag < min_tag || tag > max_tag) {
621 			ec = ISNS_RSP_MSG_FORMAT_ERROR;
622 		} else if (key->attr_len > 0 && attrs != NULL) {
623 			attr = &attrs[tag - min_tag]; /* ATTR_INDEX_xxx */
624 			ec = extract_attr(attr, key, 0);
625 			if (ec == ISNS_RSP_INVALID_REGIS) {
626 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
627 			}
628 		}
629 		NEXT_TLV(key, key_len);
630 	}
631 
632 	return (ec);
633 }
634 
635 static lookup_method_t
636 get_op_method(
637 	uint32_t tag
638 )
639 {
640 	lookup_method_t method = 0;
641 
642 	switch (tag) {
643 	/* OP_STRING */
644 	case ISNS_EID_ATTR_ID:
645 	case ISNS_PORTAL_NAME_ATTR_ID:
646 	case ISNS_ISCSI_ALIAS_ATTR_ID:
647 	case ISNS_DD_SET_NAME_ATTR_ID:
648 	case ISNS_DD_NAME_ATTR_ID:
649 	case ISNS_ISCSI_NAME_ATTR_ID:
650 	case ISNS_PG_ISCSI_NAME_ATTR_ID:
651 	case ISNS_ISCSI_AUTH_METHOD_ATTR_ID:
652 		method = OP_STRING;
653 		break;
654 	/* OP_MEMORY_IP6 */
655 	case ISNS_MGMT_IP_ADDR_ATTR_ID:
656 	case ISNS_PORTAL_IP_ADDR_ATTR_ID:
657 	case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
658 		method = OP_MEMORY_IP6;
659 		break;
660 	/* OP_INTEGER */
661 	case ISNS_ENTITY_PROTOCOL_ATTR_ID:
662 	case ISNS_VERSION_RANGE_ATTR_ID:
663 	case ISNS_ENTITY_REG_PERIOD_ATTR_ID:
664 	case ISNS_ENTITY_INDEX_ATTR_ID:
665 	case ISNS_PORTAL_PORT_ATTR_ID:
666 	case ISNS_ESI_INTERVAL_ATTR_ID:
667 	case ISNS_ESI_PORT_ATTR_ID:
668 	case ISNS_PORTAL_INDEX_ATTR_ID:
669 	case ISNS_SCN_PORT_ATTR_ID:
670 	case ISNS_ISCSI_NODE_TYPE_ATTR_ID:
671 	case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
672 	case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
673 	case ISNS_PG_PORTAL_PORT_ATTR_ID:
674 	case ISNS_PG_TAG_ATTR_ID:
675 	case ISNS_PG_INDEX_ATTR_ID:
676 	case ISNS_DD_SET_ID_ATTR_ID:
677 	case ISNS_DD_SET_STATUS_ATTR_ID:
678 	case ISNS_DD_ID_ATTR_ID:
679 	/* all other attrs */
680 	default:
681 		method = OP_INTEGER;
682 		break;
683 	}
684 
685 	return (method);
686 }
687 
688 static int
689 cb_attrs_match(
690 	void *p1,
691 	void *p2
692 )
693 {
694 	isns_obj_t *obj = (isns_obj_t *)p1;
695 	isns_attr_t *attrs = (isns_attr_t *)
696 	    ((lookup_ctrl_t *)p2)->data[1].ptr;
697 
698 	lookup_ctrl_t lc;
699 	int match = 1; /* 0: not match, otherwise: match */
700 
701 	int i;
702 
703 	lc.op[1] = 0;
704 
705 	for (i = 0; match != 0 && i < NUM_OF_ATTRS[obj->type]; i++) {
706 		if (attrs->tag != 0 && attrs->len > 0) {
707 			lc.id[0] = i;
708 			lc.op[0] = get_op_method(attrs->tag);
709 			lc.data[0].ptr = attrs->value.ptr;
710 			match = key_cmp(&lc, obj) == 0 ? 1 : 0;
711 		}
712 		attrs ++;
713 	}
714 
715 	return (match);
716 }
717 
718 static int
719 attrs_match(
720 	isns_type_t type,
721 	uint32_t uid,
722 	isns_attr_t *attrs
723 )
724 {
725 	int match; /* 0: not match, otherwise: match */
726 	lookup_ctrl_t lc;
727 
728 	SET_UID_LCP(&lc, type, uid);
729 
730 	lc.data[1].ptr = (uchar_t *)attrs;
731 
732 	match = cache_lookup(&lc, NULL, cb_attrs_match);
733 
734 	return (match);
735 }
736 
737 static int
738 insert_uid(
739 	uint32_t **pp,
740 	uint32_t *np,
741 	uint32_t *sp,
742 	uint32_t uid
743 )
744 {
745 	int ec = 0;
746 
747 	uint32_t *p = *pp;
748 	uint32_t n = *np;
749 	uint32_t s = *sp;
750 
751 	uint32_t u;
752 	uint32_t *t;
753 
754 	/* check for duplication */
755 	if (n > 0 && uid <= p[n - 1]) {
756 		while (n-- > 0) {
757 			if (p[n] == uid) {
758 				return (0);
759 			}
760 		}
761 		n = *np;
762 		u = p[n - 1];
763 		p[n - 1] = uid;
764 		uid = u;
765 	}
766 
767 
768 	if (s == n) {
769 		s = (s == 0) ? 8 : s * 2;
770 		t = (uint32_t *)realloc(p, s * sizeof (uint32_t));
771 		if (t != NULL) {
772 			p = t;
773 			*pp = p;
774 			*sp = s;
775 		} else {
776 			ec = ISNS_RSP_INTERNAL_ERROR;
777 		}
778 	}
779 
780 	if (ec == 0) {
781 		p[n ++] = uid;
782 		*np = n;
783 	}
784 
785 	return (ec);
786 }
787 
788 static int
789 qry_and_match(
790 	uint32_t **obj_uids,
791 	uint32_t *num_of_objs,
792 	uint32_t *size,
793 	isns_type_t type,
794 	uint32_t src_uid,
795 	isns_type_t src_type,
796 	isns_attr_t *attrs
797 )
798 {
799 	int ec = 0;
800 
801 	lookup_ctrl_t lc = { 0 }; /* !!! need to be empty */
802 	uint32_t uid;
803 
804 	const adjvex_t *vex;
805 
806 	/* circular list */
807 	uint32_t *p[2], n[2], s[2];
808 	int i, j;
809 
810 	uint32_t *p1, n1;
811 	uint32_t *p2, n2, s2;
812 	isns_type_t t;
813 
814 	/* initialize the circular list */
815 	i = 0;
816 	j = 1;
817 
818 	p[i] = *obj_uids;
819 	n[i] = *num_of_objs;
820 	s[i] = *size;
821 
822 	p[j] = malloc(8 * sizeof (uint32_t));
823 	p[j][0] = src_uid;
824 	n[j] = 1;
825 	s[j] = 8;
826 
827 	/* initial object type of being queried */
828 	t = src_type;
829 
830 	vex = qry_puzzle[src_type][type];
831 
832 	do {
833 		/* shift one on the circular list */
834 		i = (i + 1) & 1;
835 		j = (j + 1) & 1;
836 
837 		p1 = p[i]; n1 = n[i];
838 		p2 = p[j]; n2 = n[j]; s2 = s[j];
839 
840 		/* prepare lookup control */
841 		lc.type = t;
842 		lc.id[0] = UID_ATTR_INDEX[t];
843 		lc.op[0] = OP_INTEGER;
844 
845 		/* result object type */
846 		t = vex->t;
847 
848 		FOR_EACH_OBJS(p1, n1, uid, {
849 			/* start query */
850 			lc.data[0].ui = uid;
851 			ec = vex->f(&lc);
852 			uid = lc.curr_uid;
853 			while (ec == 0 && uid != 0) {
854 				if (attrs == NULL ||
855 				    attrs_match(type, uid, attrs) != 0) {
856 					ec = insert_uid(&p2, &n2, &s2, uid);
857 				}
858 				if (ec == 0) {
859 					ec = vex->f(&lc);
860 					uid = lc.curr_uid;
861 				} else {
862 					n1 = n2 = 0; /* force break */
863 				}
864 			}
865 		});
866 		if (ec == 0) {
867 			vex = vex->v;
868 		} else {
869 			vex = NULL; /* force break */
870 		}
871 		/* push back */
872 		p[j] = p2; n[j] = n2; s[j] = s2;
873 		/* reset the number of objects */
874 		n[i] = 0;
875 	} while (vex != NULL);
876 
877 	/* clean up the memory */
878 	free(p1);
879 	if (ec != 0) {
880 		free(p2);
881 		p2 = NULL;
882 		n2 = 0;
883 		s2 = 0;
884 	}
885 
886 	*obj_uids = p2;
887 	*num_of_objs = n2;
888 	*size = s2;
889 
890 	return (ec);
891 }
892 
893 int
894 get_qry_keys(
895 	bmp_t *nodes_bmp,
896 	uint32_t num_of_nodes,
897 	isns_type_t *type,
898 	isns_tlv_t *key,
899 	uint16_t key_len,
900 	uint32_t **obj_uids,
901 	uint32_t *num_of_objs
902 )
903 {
904 	int ec = 0;
905 	union {
906 		isns_obj_t o;
907 		isns_entity_t e;
908 		isns_iscsi_t i;
909 		isns_portal_t p;
910 		isns_pg_t g;
911 		isns_dd_t d;
912 		isns_dds_t s;
913 	} an_obj = { 0 };
914 	isns_attr_t *attrs;
915 
916 	htab_t *htab;
917 	uint32_t node_uid;
918 
919 	uint32_t size;
920 
921 	*obj_uids = NULL;
922 	*num_of_objs = 0;
923 	size = 0;
924 
925 	/* get the object type identified by the key */
926 	*type = TLV2TYPE(key);
927 	if (*type == 0) {
928 		return (ISNS_RSP_INVALID_QRY);
929 	}
930 
931 	attrs = &an_obj.o.attrs[0];
932 	/* validate the Message Key */
933 	ec = validate_qry_key(*type, key, key_len, attrs);
934 	if (ec != 0) {
935 		return (ec);
936 	}
937 
938 	if (nodes_bmp != NULL) {
939 		FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, {
940 			ec = qry_and_match(
941 			    obj_uids, num_of_objs, &size, *type,
942 			    node_uid, OBJ_ISCSI, attrs);
943 			if (ec != 0) {
944 				return (ec);
945 			}
946 		});
947 	} else {
948 		node_uid = 0;
949 		htab = cache_get_htab(OBJ_ISCSI);
950 		FOR_EACH_ITEM(htab, node_uid, {
951 			ec = qry_and_match(
952 			    obj_uids, num_of_objs, &size, *type,
953 			    node_uid, OBJ_ISCSI, attrs);
954 			if (ec != 0) {
955 				return (ec);
956 			}
957 		});
958 	}
959 
960 	return (ec);
961 }
962 
963 int
964 get_qry_ops(
965 	uint32_t uid,
966 	isns_type_t src_type,
967 	isns_type_t op_type,
968 	uint32_t **op_uids,
969 	uint32_t *num_of_ops,
970 	uint32_t *size
971 )
972 {
973 	int ec = 0;
974 
975 	*num_of_ops = 0;
976 
977 	ec = qry_and_match(
978 	    op_uids, num_of_ops, size, op_type,
979 	    uid, src_type, NULL);
980 
981 	return (ec);
982 }
983 
984 int
985 get_qry_ops2(
986 	uint32_t *nodes_bmp,
987 	uint32_t num_of_nodes,
988 	isns_type_t op_type,
989 	uint32_t **op_uids,
990 	uint32_t *num_of_ops,
991 	uint32_t *size
992 )
993 {
994 	int ec = 0;
995 
996 	uint32_t node_uid;
997 
998 	htab_t *htab;
999 
1000 	*num_of_ops = 0;
1001 
1002 	if (nodes_bmp != NULL) {
1003 		FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, {
1004 			ec = qry_and_match(
1005 			    op_uids, num_of_ops, size, op_type,
1006 			    node_uid, OBJ_ISCSI, NULL);
1007 			if (ec != 0) {
1008 				return (ec);
1009 			}
1010 		});
1011 	} else {
1012 		node_uid = 0;
1013 		htab = cache_get_htab(OBJ_ISCSI);
1014 		FOR_EACH_ITEM(htab, node_uid, {
1015 			ec = qry_and_match(
1016 			    op_uids, num_of_ops, size, op_type,
1017 			    node_uid, OBJ_ISCSI, NULL);
1018 			if (ec != 0) {
1019 				return (ec);
1020 			}
1021 		});
1022 	}
1023 
1024 	return (ec);
1025 }
1026 
1027 uint32_t
1028 get_next_obj(
1029 	isns_tlv_t *tlv,
1030 	uint32_t tlv_len,
1031 	isns_type_t type,
1032 	uint32_t *uids,
1033 	uint32_t num
1034 )
1035 {
1036 	lookup_ctrl_t lc;
1037 
1038 	uint32_t tag;
1039 	uint8_t *value;
1040 
1041 	uint32_t old = 0;
1042 	uint32_t min = 0;
1043 	uint32_t uid, diff;
1044 	uint32_t pre_diff = 0xFFFFFFFF;
1045 
1046 	lc.curr_uid = 0;
1047 	lc.type = type;
1048 	lc.op[1] = 0;
1049 	lc.op[2] = 0;
1050 
1051 	if (tlv_len > 8) {
1052 		tag = tlv->attr_id;
1053 		value = tlv->attr_value;
1054 		switch (tag) {
1055 		case ISNS_EID_ATTR_ID:
1056 			lc.id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
1057 			lc.op[0] = OP_STRING;
1058 			lc.data[0].ptr = (uchar_t *)value;
1059 			break;
1060 		case ISNS_ISCSI_NAME_ATTR_ID:
1061 			lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
1062 			lc.op[0] = OP_STRING;
1063 			lc.data[0].ptr = (uchar_t *)value;
1064 			break;
1065 		case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
1066 			lc.id[0] = ATTR_INDEX_ISCSI(
1067 			    ISNS_ISCSI_NODE_INDEX_ATTR_ID);
1068 			lc.op[0] = OP_INTEGER;
1069 			lc.data[0].ui = ntohl(*(uint32_t *)value);
1070 			break;
1071 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
1072 			lc.id[0] = ATTR_INDEX_PORTAL(
1073 			    ISNS_PORTAL_IP_ADDR_ATTR_ID);
1074 			lc.op[0] = OP_MEMORY_IP6;
1075 			lc.data[0].ip = (in6_addr_t *)value;
1076 			NEXT_TLV(tlv, tlv_len);
1077 			if (tlv_len > 8 &&
1078 			    ((tag = tlv->attr_id) ==
1079 			    ISNS_PORTAL_PORT_ATTR_ID)) {
1080 				value = tlv->attr_value;
1081 				lc.id[1] = ATTR_INDEX_PORTAL(
1082 				    ISNS_PORTAL_PORT_ATTR_ID);
1083 				lc.op[1] = OP_INTEGER;
1084 				lc.data[1].ui = ntohl(*(uint32_t *)value);
1085 			} else {
1086 				return (0);
1087 			}
1088 			break;
1089 		case ISNS_PORTAL_INDEX_ATTR_ID:
1090 			lc.id[0] = ATTR_INDEX_PORTAL(ISNS_PORTAL_INDEX_ATTR_ID);
1091 			lc.op[0] = OP_INTEGER;
1092 			lc.data[0].ui = ntohl(*(uint32_t *)value);
1093 			break;
1094 		case ISNS_PG_INDEX_ATTR_ID:
1095 			lc.id[0] = ATTR_INDEX_PG(ISNS_PG_INDEX_ATTR_ID);
1096 			lc.op[0] = OP_INTEGER;
1097 			lc.data[0].ui = ntohl(*(uint32_t *)value);
1098 			break;
1099 		default:
1100 			return (0);
1101 		}
1102 
1103 		old = is_obj_there(&lc);
1104 		if (old == 0) {
1105 			return (0);
1106 		}
1107 	}
1108 
1109 	while (num > 0) {
1110 		uid = uids[-- num];
1111 		if (uid > old) {
1112 			diff = uid - old;
1113 			if (diff < pre_diff) {
1114 				min = uid;
1115 				pre_diff = diff;
1116 			}
1117 		}
1118 	}
1119 
1120 	return (min);
1121 }
1122 
1123 static int
1124 cb_qry_rsp(
1125 	void *p1,
1126 	void *p2
1127 )
1128 {
1129 	int ec = 0;
1130 
1131 	isns_obj_t *obj = (isns_obj_t *)p1;
1132 	lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
1133 
1134 	uint16_t tlv_len = lcp->id[1];
1135 	isns_tlv_t *tlv = (isns_tlv_t *)lcp->data[1].ptr;
1136 	conn_arg_t *conn = (conn_arg_t *)lcp->data[2].ptr;
1137 
1138 	isns_type_t type = obj->type;
1139 	uint32_t min_tag = TAG_RANGE[type][0];
1140 	uint32_t mid_tag = TAG_RANGE[type][1];
1141 	uint32_t max_tag = TAG_RANGE[type][2];
1142 
1143 	isns_attr_t *attr;
1144 	uint32_t tag;
1145 	uint32_t id;
1146 	uint32_t len;
1147 	void *value;
1148 
1149 	isns_pdu_t *rsp = conn->out_packet.pdu;
1150 	size_t pl = conn->out_packet.pl;
1151 	size_t sz = conn->out_packet.sz;
1152 
1153 	do {
1154 		if (tlv->attr_len == 0) {
1155 			tag = tlv->attr_id;
1156 			if (tag <= mid_tag) {
1157 				id = ATTR_INDEX(tag, type);
1158 				attr = &obj->attrs[id];
1159 				len = attr->len;
1160 				value = (void *)attr->value.ptr;
1161 				ec = pdu_add_tlv(&rsp, &pl, &sz,
1162 				    tag, len, value, 0);
1163 			}
1164 		}
1165 		NEXT_TLV(tlv, tlv_len);
1166 	} while (ec == 0 &&
1167 	    tlv_len >= 8 &&
1168 	    tlv->attr_id >= min_tag &&
1169 	    tlv->attr_id <= max_tag);
1170 
1171 	conn->out_packet.pdu = rsp;
1172 	conn->out_packet.pl = pl;
1173 	conn->out_packet.sz = sz;
1174 
1175 	return (ec);
1176 }
1177 
1178 int
1179 get_qry_attrs(
1180 	uint32_t uid,
1181 	isns_type_t type,
1182 	isns_tlv_t *tlv,
1183 	uint16_t tlv_len,
1184 	conn_arg_t *conn
1185 )
1186 {
1187 	int ec = 0;
1188 
1189 	lookup_ctrl_t lc;
1190 
1191 	SET_UID_LCP(&lc, type, uid);
1192 
1193 	lc.id[1] = tlv_len;
1194 	lc.data[1].ptr = (uchar_t *)tlv;
1195 	lc.data[2].ptr = (uchar_t *)conn;
1196 
1197 	ec = cache_lookup(&lc, NULL, cb_qry_rsp);
1198 
1199 	return (ec);
1200 }
1201 
1202 int
1203 get_qry_attrs1(
1204 	uint32_t uid,
1205 	isns_type_t type,
1206 	isns_tlv_t *tlv,
1207 	uint16_t tlv_len,
1208 	conn_arg_t *conn
1209 )
1210 {
1211 	isns_tlv_t *tmp = tlv;
1212 	uint32_t tmp_len = tlv_len;
1213 
1214 	/* clear the length of all of tlv */
1215 	while (tmp_len > 8) {
1216 		tmp->attr_len = 0;
1217 		NEXT_TLV(tmp, tmp_len);
1218 	}
1219 
1220 	return (get_qry_attrs(uid, type, tlv, tlv_len, conn));
1221 }
1222