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
cb_qry_parent_uid(void * p1,void * p2)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
cb_qry_child_uids(void * p1,void * p2)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
e2c(lookup_ctrl_t * lcp,isns_type_t type)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
qry_c2e(lookup_ctrl_t * lcp)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
qry_ds2m(lookup_ctrl_t * lcp)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
qry_slf(lookup_ctrl_t * lcp)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
qry_e2i(lookup_ctrl_t * lcp)323 qry_e2i(
324 lookup_ctrl_t *lcp
325 )
326 {
327 return (e2c(lcp, OBJ_ISCSI));
328 }
329
330 static int
qry_e2p(lookup_ctrl_t * lcp)331 qry_e2p(
332 lookup_ctrl_t *lcp
333 )
334 {
335 return (e2c(lcp, OBJ_PORTAL));
336 }
337
338 static int
qry_e2g(lookup_ctrl_t * lcp)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
qry_i2g(lookup_ctrl_t * lcp)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
qry_i2d(lookup_ctrl_t * lcp)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
qry_p2g(lookup_ctrl_t * lcp)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
qry_g2i(lookup_ctrl_t * lcp)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
qry_g2p(lookup_ctrl_t * lcp)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
qry_d2s(lookup_ctrl_t * lcp)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
validate_qry_key(isns_type_t type,isns_tlv_t * key,uint16_t key_len,isns_attr_t * attrs)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
get_op_method(uint32_t tag)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
cb_attrs_match(void * p1,void * p2)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
attrs_match(isns_type_t type,uint32_t uid,isns_attr_t * attrs)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
insert_uid(uint32_t ** pp,uint32_t * np,uint32_t * sp,uint32_t uid)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
qry_and_match(uint32_t ** obj_uids,uint32_t * num_of_objs,uint32_t * size,isns_type_t type,uint32_t src_uid,isns_type_t src_type,isns_attr_t * attrs)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
get_qry_keys(bmp_t * nodes_bmp,uint32_t num_of_nodes,isns_type_t * type,isns_tlv_t * key,uint16_t key_len,uint32_t ** obj_uids,uint32_t * num_of_objs)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
get_qry_ops(uint32_t uid,isns_type_t src_type,isns_type_t op_type,uint32_t ** op_uids,uint32_t * num_of_ops,uint32_t * size)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
get_qry_ops2(uint32_t * nodes_bmp,uint32_t num_of_nodes,isns_type_t op_type,uint32_t ** op_uids,uint32_t * num_of_ops,uint32_t * size)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
get_next_obj(isns_tlv_t * tlv,uint32_t tlv_len,isns_type_t type,uint32_t * uids,uint32_t num)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
cb_qry_rsp(void * p1,void * p2)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
get_qry_attrs(uint32_t uid,isns_type_t type,isns_tlv_t * tlv,uint16_t tlv_len,conn_arg_t * conn)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
get_qry_attrs1(uint32_t uid,isns_type_t type,isns_tlv_t * tlv,uint16_t tlv_len,conn_arg_t * conn)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