xref: /illumos-gate/usr/src/cmd/isns/isnsd/func.c (revision f3041bfa)
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 <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 
34 #include "isns_server.h"
35 #include "isns_msgq.h"
36 #include "isns_func.h"
37 #include "isns_cache.h"
38 #include "isns_obj.h"
39 #include "isns_dd.h"
40 #include "isns_pdu.h"
41 #include "isns_qry.h"
42 #include "isns_scn.h"
43 #include "isns_utils.h"
44 #include "isns_cfg.h"
45 #include "isns_esi.h"
46 #include "isns_provider.h"
47 #include "isns_log.h"
48 
49 /*
50  * extern global variables
51  */
52 #ifdef DEBUG
53 extern int verbose_mc;
54 extern int verbose_tc;
55 #endif
56 extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE];
57 extern const int NUM_OF_CHILD[MAX_OBJ_TYPE];
58 extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE];
59 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
60 extern const int TAG_RANGE[MAX_OBJ_TYPE][3];
61 
62 /* scn message queue */
63 extern msg_queue_t *scn_q;
64 
65 /*
66  * extern functions.
67  */
68 
69 /*
70  * local variables
71  */
72 
73 /*
74  * local functions.
75  */
76 static int dev_attr_reg(conn_arg_t *);
77 static int dev_attr_qry(conn_arg_t *);
78 static int dev_get_next(conn_arg_t *);
79 static int dev_dereg(conn_arg_t *);
80 static int scn_reg(conn_arg_t *);
81 static int scn_dereg(conn_arg_t *);
82 static int dd_reg(conn_arg_t *);
83 static int dd_dereg(conn_arg_t *);
84 static int dds_reg(conn_arg_t *);
85 static int dds_dereg(conn_arg_t *);
86 static int msg_error(conn_arg_t *);
87 
88 /*
89  * ****************************************************************************
90  *
91  * packet_get_source:
92  *	get the source attributes of the packet.
93  *
94  * conn	- the argument of the connection.
95  * return - error code.
96  *
97  * ****************************************************************************
98  */
99 static int
100 packet_get_source(
101 	conn_arg_t *conn
102 )
103 {
104 	int ec = 0;
105 
106 	isns_pdu_t *pdu = conn->in_packet.pdu;
107 	isns_tlv_t *source = pdu_get_source(pdu);
108 
109 	if (source == NULL) {
110 		ec = ISNS_RSP_SRC_ABSENT;
111 	} else if (source->attr_id != ISNS_ISCSI_NAME_ATTR_ID ||
112 	    source->attr_len == 0) {
113 		ec = ISNS_RSP_SRC_UNKNOWN;
114 	}
115 
116 	if (ec == 0) {
117 		conn->in_packet.source = source;
118 	}
119 
120 	return (ec);
121 }
122 
123 /*
124  * ****************************************************************************
125  *
126  * packet_get_key:
127  *	get the key attributes of the packet.
128  *
129  * conn	- the argument of the connection.
130  * return - error code.
131  *
132  * ****************************************************************************
133  */
134 static int
135 packet_get_key(
136 	conn_arg_t *conn
137 )
138 {
139 	int ec = 0;
140 
141 	isns_pdu_t *pdu = conn->in_packet.pdu;
142 	isns_tlv_t *key;
143 	size_t key_len;
144 
145 	key = pdu_get_key(pdu, &key_len);
146 
147 	conn->in_packet.key = key;
148 	conn->in_packet.key_len = key_len;
149 
150 	return (ec);
151 }
152 
153 /*
154  * ****************************************************************************
155  *
156  * packet_get_operand:
157  *	get the operating attributes of the packet.
158  *
159  * conn	- the argument of the connection.
160  * return - error code.
161  *
162  * ****************************************************************************
163  */
164 static int
165 packet_get_operand(
166 	conn_arg_t *conn
167 )
168 {
169 	int ec = 0;
170 
171 	isns_pdu_t *pdu = conn->in_packet.pdu;
172 	isns_tlv_t *op;
173 	size_t op_len;
174 
175 	op = pdu_get_operand(pdu, &op_len);
176 
177 	conn->in_packet.op = op;
178 	conn->in_packet.op_len = op_len;
179 
180 	return (ec);
181 }
182 
183 /*
184  * ****************************************************************************
185  *
186  * packet_split_verify:
187  *	split and verify the packet, get the apporiate locking type and
188  *	function handler for the packet.
189  *
190  * conn	- the argument of the connection.
191  * return - error code.
192  *
193  * ****************************************************************************
194  */
195 int
196 packet_split_verify(
197 	conn_arg_t *conn
198 )
199 {
200 	int ec = 0;
201 
202 	isns_pdu_t *pdu = conn->in_packet.pdu;
203 
204 	int (*handler)(conn_arg_t *) = msg_error;
205 	int lock = CACHE_NO_ACTION;
206 
207 	if (pdu->version != ISNSP_VERSION) {
208 		ec = ISNS_RSP_VER_NOT_SUPPORTED;
209 	} else {
210 		switch (pdu->func_id) {
211 		case ISNS_DEV_ATTR_REG:
212 			lock = CACHE_WRITE;
213 			handler = dev_attr_reg;
214 			break;
215 		case ISNS_DEV_ATTR_QRY:
216 			lock = CACHE_READ;
217 			handler = dev_attr_qry;
218 			break;
219 		case ISNS_DEV_GET_NEXT:
220 			lock = CACHE_READ;
221 			handler = dev_get_next;
222 			break;
223 		case ISNS_DEV_DEREG:
224 			lock = CACHE_WRITE;
225 			handler = dev_dereg;
226 			break;
227 		case ISNS_SCN_REG:
228 			if (scn_q != NULL) {
229 				lock = CACHE_WRITE;
230 				handler = scn_reg;
231 			} else {
232 				ec = ISNS_RSP_SCN_REGIS_REJECTED;
233 			}
234 			break;
235 		case ISNS_SCN_DEREG:
236 			if (scn_q != NULL) {
237 				lock = CACHE_WRITE;
238 				handler = scn_dereg;
239 			} else {
240 				ec = ISNS_RSP_SCN_REGIS_REJECTED;
241 			}
242 			break;
243 		case ISNS_SCN_EVENT:
244 			ec = ISNS_RSP_MSG_NOT_SUPPORTED;
245 			break;
246 		case ISNS_DD_REG:
247 			lock = CACHE_WRITE;
248 			handler = dd_reg;
249 			break;
250 		case ISNS_DD_DEREG:
251 			lock = CACHE_WRITE;
252 			handler = dd_dereg;
253 			break;
254 		case ISNS_DDS_REG:
255 			lock = CACHE_WRITE;
256 			handler = dds_reg;
257 			break;
258 		case ISNS_DDS_DEREG:
259 			lock = CACHE_WRITE;
260 			handler = dds_dereg;
261 			break;
262 		default:
263 			ec = ISNS_RSP_MSG_NOT_SUPPORTED;
264 			break;
265 		}
266 	}
267 
268 	if (ISNS_OPERATION_TYPE_ENABLED()) {
269 		char buf[INET6_ADDRSTRLEN];
270 		struct sockaddr_storage *ssp = &conn->ss;
271 		struct sockaddr_in *sinp = (struct sockaddr_in *)ssp;
272 		if (ssp->ss_family == AF_INET) {
273 			(void) inet_ntop(AF_INET, (void *)&(sinp->sin_addr),
274 			    buf, sizeof (buf));
275 		} else {
276 			(void) inet_ntop(AF_INET6, (void *)&(sinp->sin_addr),
277 			    buf, sizeof (buf));
278 		}
279 		ISNS_OPERATION_TYPE((uintptr_t)buf, pdu->func_id);
280 	}
281 
282 	conn->lock = lock;
283 	conn->handler = handler;
284 
285 	/* packet split & verify */
286 	if (ec == 0) {
287 		ec = packet_get_source(conn);
288 		if (ec == 0) {
289 			ec = packet_get_key(conn);
290 			if (ec == 0) {
291 				ec = packet_get_operand(conn);
292 			}
293 		}
294 	}
295 
296 	conn->ec = ec;
297 
298 	return (ec);
299 }
300 
301 /*
302  * ****************************************************************************
303  *
304  * setup_key_lcp:
305  *	setup the lookup control data for looking up the object
306  *	which the key attributes identify.
307  *
308  * lcp	- the pointer of the lookup control data.
309  * key	- the key attributes.
310  * key_len	- the length of the key attributes.
311  * return	- the pointer of the lookup control data or
312  *		  NULL if there is an error.
313  *
314  * ****************************************************************************
315  */
316 static int
317 setup_key_lcp(
318 	lookup_ctrl_t *lcp,
319 	isns_tlv_t *key,
320 	uint16_t key_len
321 )
322 {
323 	int ec = 0;
324 
325 	uint8_t *value = &key->attr_value[0];
326 
327 	lcp->curr_uid = 0;
328 	lcp->op[0] = 0;
329 
330 	switch (key->attr_id) {
331 	case ISNS_EID_ATTR_ID:
332 		if (key->attr_len >= 4) {
333 			lcp->type = OBJ_ENTITY;
334 			lcp->id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
335 			lcp->op[0] = OP_STRING;
336 			lcp->data[0].ptr = (uchar_t *)value;
337 			lcp->op[1] = 0;
338 		}
339 		break;
340 	case ISNS_ISCSI_NAME_ATTR_ID:
341 		if (key->attr_len >= 4) {
342 			lcp->type = OBJ_ISCSI;
343 			lcp->id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
344 			lcp->op[0] = OP_STRING;
345 			lcp->data[0].ptr = (uchar_t *)value;
346 			lcp->op[1] = 0;
347 		} else {
348 			ec = ISNS_RSP_MSG_FORMAT_ERROR;
349 		}
350 		break;
351 	case ISNS_PORTAL_IP_ADDR_ATTR_ID:
352 		if (key->attr_len == sizeof (in6_addr_t)) {
353 			lcp->id[0] = ATTR_INDEX_PORTAL(
354 			    ISNS_PORTAL_IP_ADDR_ATTR_ID);
355 			lcp->op[0] = OP_MEMORY_IP6;
356 			lcp->data[0].ip = (in6_addr_t *)value;
357 			NEXT_TLV(key, key_len);
358 			if (key_len <= 8 ||
359 			    key->attr_len != 4 ||
360 			    key->attr_id != ISNS_PORTAL_PORT_ATTR_ID) {
361 				return (ISNS_RSP_MSG_FORMAT_ERROR);
362 			}
363 			lcp->type = OBJ_PORTAL;
364 			value = &key->attr_value[0];
365 			lcp->id[1] = ATTR_INDEX_PORTAL(
366 			    ISNS_PORTAL_PORT_ATTR_ID);
367 			lcp->op[1] = OP_INTEGER;
368 			lcp->data[1].ui = ntohl(*(uint32_t *)value);
369 			lcp->op[2] = 0;
370 		} else {
371 			ec = ISNS_RSP_MSG_FORMAT_ERROR;
372 		}
373 		break;
374 	case ISNS_PG_ISCSI_NAME_ATTR_ID:
375 		if (key->attr_len < 4) {
376 			return (ISNS_RSP_MSG_FORMAT_ERROR);
377 		}
378 		lcp->id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID);
379 		lcp->op[0] = OP_STRING;
380 		lcp->data[0].ptr = (uchar_t *)value;
381 		NEXT_TLV(key, key_len);
382 		if (key_len <= 8 ||
383 		    key->attr_len != sizeof (in6_addr_t) ||
384 		    key->attr_id != ISNS_PG_PORTAL_IP_ADDR_ATTR_ID) {
385 			return (ISNS_RSP_MSG_FORMAT_ERROR);
386 		}
387 		value = &key->attr_value[0];
388 		lcp->id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID);
389 		lcp->op[1] = OP_MEMORY_IP6;
390 		lcp->data[1].ip = (in6_addr_t *)value;
391 		NEXT_TLV(key, key_len);
392 		if (key_len <= 8 ||
393 		    key->attr_len != 4 ||
394 		    key->attr_id != ISNS_PG_PORTAL_PORT_ATTR_ID) {
395 			return (ISNS_RSP_MSG_FORMAT_ERROR);
396 		}
397 		value = &key->attr_value[0];
398 		lcp->id[2] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID);
399 		lcp->op[2] = OP_INTEGER;
400 		lcp->data[2].ui = ntohl(*(uint32_t *)value);
401 		lcp->type = OBJ_PG;
402 		break;
403 	default:
404 		lcp->type = 0; /* invalid */
405 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
406 	}
407 
408 	return (ec);
409 }
410 
411 /*
412  * ****************************************************************************
413  *
414  * rsp_add_op:
415  *	add the operating attributes to the response packet.
416  *
417  * conn	- the argument of the connection.
418  * obj	- the object which is being added as operating attributes.
419  * return - error code.
420  *
421  * ****************************************************************************
422  */
423 static int
424 rsp_add_op(
425 	conn_arg_t *conn,
426 	isns_obj_t *obj
427 )
428 {
429 	int ec = 0;
430 
431 	isns_attr_t *attr;
432 	int i;
433 
434 	isns_pdu_t *rsp = conn->out_packet.pdu;
435 	size_t pl = conn->out_packet.pl;
436 	size_t sz = conn->out_packet.sz;
437 
438 	i = 0;
439 	while (i < NUM_OF_ATTRS[obj->type] &&
440 	    ec == 0) {
441 		attr = &obj->attrs[i];
442 		/* there is an attribute, send it back */
443 		if (attr->tag != 0) {
444 			ec = pdu_add_tlv(&rsp, &pl, &sz,
445 			    attr->tag, attr->len,
446 			    (void *)attr->value.ptr, 0);
447 		}
448 		i ++;
449 	}
450 
451 	conn->out_packet.pdu = rsp;
452 	conn->out_packet.pl = pl;
453 	conn->out_packet.sz = sz;
454 
455 	return (ec);
456 }
457 
458 /*
459  * ****************************************************************************
460  *
461  * rsp_add_key:
462  *	add the key attributes to the response packet.
463  *
464  * conn	- the argument of the connection.
465  * entity - the object which is being added as key attributes.
466  * return - error code.
467  *
468  * ****************************************************************************
469  */
470 static int
471 rsp_add_key(
472 	conn_arg_t *conn,
473 	isns_obj_t *entity
474 )
475 {
476 	int ec = 0;
477 
478 	isns_tlv_t *key = conn->in_packet.key;
479 	size_t key_len = conn->in_packet.key_len;
480 	uint32_t tag = ISNS_EID_ATTR_ID;
481 	isns_attr_t *attr = &entity->attrs[ATTR_INDEX_ENTITY(tag)];
482 	uint32_t len = attr->len;
483 
484 	isns_pdu_t *rsp = conn->out_packet.pdu;
485 	size_t pl = conn->out_packet.pl;
486 	size_t sz = conn->out_packet.sz;
487 
488 	if (key_len == 0) {
489 		ec = pdu_add_tlv(&rsp, &pl, &sz,
490 		    tag, len, (void *)attr->value.ptr, 0);
491 	} else {
492 		while (key_len >= 8 &&
493 		    ec == 0) {
494 			if (key->attr_id == ISNS_EID_ATTR_ID) {
495 				ec = pdu_add_tlv(&rsp, &pl, &sz,
496 				    tag, len,
497 				    (void *)attr->value.ptr, 0);
498 			} else {
499 				ec = pdu_add_tlv(&rsp, &pl, &sz,
500 				    key->attr_id, key->attr_len,
501 				    (void *)key->attr_value, 1);
502 			}
503 			NEXT_TLV(key, key_len);
504 		}
505 	}
506 
507 	if (ec == 0) {
508 		ec = pdu_add_tlv(&rsp, &pl, &sz,
509 		    ISNS_DELIMITER_ATTR_ID, 0, NULL, 0);
510 	}
511 
512 	conn->out_packet.pdu = rsp;
513 	conn->out_packet.pl = pl;
514 	conn->out_packet.sz = sz;
515 
516 	if (ec == 0) {
517 		ec = rsp_add_op(conn, entity);
518 	}
519 
520 	return (ec);
521 }
522 
523 /*
524  * ****************************************************************************
525  *
526  * rsp_add_tlv:
527  *	add one attribute with TLV format to the response packet.
528  *
529  * conn	- the argument of the connection.
530  * tag	- the tag of the attribute.
531  * len	- the length of the attribute.
532  * value- the value of the attribute.
533  * pflag- the flag of the value, 0: value; 1: pointer to value
534  * return - error code.
535  *
536  * ****************************************************************************
537  */
538 static int
539 rsp_add_tlv(
540 	conn_arg_t *conn,
541 	uint32_t tag,
542 	uint32_t len,
543 	void *value,
544 	int pflag
545 )
546 {
547 	int ec = 0;
548 
549 	isns_pdu_t *rsp = conn->out_packet.pdu;
550 	size_t pl = conn->out_packet.pl;
551 	size_t sz = conn->out_packet.sz;
552 
553 	ec = pdu_add_tlv(&rsp, &pl, &sz, tag, len, value, pflag);
554 
555 	conn->out_packet.pdu = rsp;
556 	conn->out_packet.pl = pl;
557 	conn->out_packet.sz = sz;
558 
559 	return (ec);
560 }
561 
562 /*
563  * ****************************************************************************
564  *
565  * rsp_add_tlvs:
566  *	add attributes with TLV format to the response packet.
567  *
568  * conn	- the argument of the connection.
569  * tlv	- the attributes with TLV format being added.
570  * tlv_len - the length of the attributes.
571  * return - error code.
572  *
573  * ****************************************************************************
574  */
575 static int
576 rsp_add_tlvs(
577 	conn_arg_t *conn,
578 	isns_tlv_t *tlv,
579 	uint32_t tlv_len
580 )
581 {
582 	int ec = 0;
583 
584 	uint32_t tag;
585 	uint32_t len;
586 	void *value;
587 
588 	while (tlv_len >= 8 &&
589 	    ec == 0) {
590 		tag = tlv->attr_id;
591 		len = tlv->attr_len;
592 		value = (void *)tlv->attr_value;
593 
594 		ec = rsp_add_tlv(conn, tag, len, value, 1);
595 
596 		NEXT_TLV(tlv, tlv_len);
597 	}
598 
599 	return (ec);
600 }
601 
602 /*
603  * ****************************************************************************
604  *
605  * dev_attr_reg:
606  *	function which handles the isnsp DEV_ATTR_REG message.
607  *
608  * conn	- the argument of the connection.
609  * return - 0: the message requires response.
610  *
611  * ****************************************************************************
612  */
613 static int
614 dev_attr_reg(
615 	conn_arg_t *conn
616 )
617 {
618 	int ec = 0;
619 
620 	isns_pdu_t *pdu = conn->in_packet.pdu;
621 	isns_tlv_t *source = conn->in_packet.source;
622 	isns_tlv_t *key = conn->in_packet.key;
623 	uint16_t key_len = conn->in_packet.key_len;
624 	isns_tlv_t *op = conn->in_packet.op;
625 	uint16_t op_len = conn->in_packet.op_len;
626 
627 	boolean_t replace =
628 	    ((pdu->flags & ISNS_FLAG_REPLACE_REG) == ISNS_FLAG_REPLACE_REG);
629 
630 	lookup_ctrl_t lc, lc_key;
631 	uchar_t *iscsi_name;
632 	int ctrl;
633 
634 	isns_obj_t *ety = NULL;	/* network entity object */
635 	isns_type_t ptype;	/* parent object type */
636 	uint32_t puid;		/* parent object UID */
637 	void const **child[MAX_CHILD_TYPE] = { NULL };   /* children */
638 	int ety_update, obj_update;
639 	isns_attr_t *eid_attr;
640 
641 	isns_obj_t *obj;	/* child object */
642 	isns_type_t ctype;	/* child object type */
643 	uint32_t uid;		/* child object uid */
644 	isns_attr_t pgt[3] = { NULL };
645 
646 	void const **vpp = NULL;
647 	int i = 0;
648 
649 	isnslog(LOG_DEBUG, "dev_attr_reg", "entered (replace: %d)", replace);
650 
651 	ec = pdu_reset_rsp(&conn->out_packet.pdu,
652 	    &conn->out_packet.pl,
653 	    &conn->out_packet.sz);
654 	if (ec != 0) {
655 		goto reg_done;
656 	}
657 
658 	iscsi_name = (uchar_t *)&source->attr_value[0];
659 	ctrl = is_control_node(iscsi_name);
660 	lc_key.type = 0;
661 	if (key != NULL) {
662 		/* validate key attributes and make lcp for */
663 		/* the object identified by key attributes. */
664 		ec = setup_key_lcp(&lc, key, key_len);
665 		if (ec == 0 && lc.type != 0) {
666 			lc_key = lc;
667 			/* object is not found */
668 			if ((uid = is_obj_there(&lc)) == 0) {
669 				/* error if it is a network entity */
670 				if (lc.type != OBJ_ENTITY) {
671 					ec = ISNS_RSP_INVALID_REGIS;
672 				}
673 			/* validate for the source attribute before */
674 			/* update or replace the network entity object */
675 			} else if (ctrl == 0 &&
676 #ifndef SKIP_SRC_AUTH
677 			    reg_auth_src(lc.type, uid, iscsi_name) == 0) {
678 #else
679 			    0) {
680 #endif
681 				ec = ISNS_RSP_SRC_UNAUTHORIZED;
682 			/* de-register the network entity if replace is true */
683 			} else if (replace != 0) {
684 				UPDATE_LCP_UID(&lc, uid);
685 				ec = dereg_object(&lc, 0);
686 				/* generate a SCN */
687 				if (ec == 0) {
688 					(void) queue_msg_set(scn_q,
689 					    SCN_TRIGGER, NULL);
690 				}
691 			}
692 		}
693 	}
694 	if (ec != 0) {
695 		goto reg_done;
696 	}
697 
698 	/* register the network entity object */
699 	ec = reg_get_entity(&ety, &op, &op_len);
700 	if (ec != 0) {
701 		goto reg_done;
702 	}
703 	if (ety == NULL && lc_key.type != OBJ_ENTITY) {
704 		ety = make_default_entity();
705 	} else if (ety == NULL ||
706 	    (lc_key.type == OBJ_ENTITY &&
707 	    key_cmp(&lc_key, ety) != 0)) {
708 		/* the eid in key attribute and */
709 		/* op attribute must be the same */
710 		ec = ISNS_RSP_INVALID_REGIS;
711 		goto reg_done;
712 	}
713 	if (ety == NULL || rsp_add_key(conn, ety) != 0) {
714 		ec = ISNS_RSP_INTERNAL_ERROR;
715 	} else {
716 		eid_attr = &ety->attrs[ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID)];
717 		ec = register_object(ety, &puid, &ety_update);
718 		ptype = OBJ_ENTITY;
719 	}
720 	if (ec == 0 && ety_update == 0) {
721 		/* newly registered, reset the pointer */
722 		ety = NULL;
723 	}
724 
725 	/* register the reset of objects which are specified in */
726 	/* operating attributes */
727 	while (ec == 0 &&
728 	    (ec = reg_get_obj(&obj, &pgt[0], &op, &op_len)) == 0 &&
729 	    obj != NULL &&
730 	    (ec = rsp_add_op(conn, obj)) == 0) {
731 		ctype = obj->type;
732 		/* set the parent object UID */
733 		(void) set_parent_obj(obj, puid);
734 		/* register it */
735 		ec = register_object(obj, &uid, &obj_update);
736 		if (ec == 0) {
737 			if (obj_update == 0 ||
738 			    is_obj_online(obj) == 0) {
739 				/* update the ref'd object */
740 				(void) update_ref_obj(obj);
741 				/* add the newly registered object info */
742 				/* to child info array of the parent object */
743 				ec = buff_child_obj(ptype, ctype, obj, child);
744 			} else {
745 				if (ctrl == 0 &&
746 #ifndef SKIP_SRC_AUTH
747 				    puid != get_parent_uid(obj)) {
748 #else
749 				    0) {
750 #endif
751 					ec = ISNS_RSP_SRC_UNAUTHORIZED;
752 				}
753 				/* it was for updating an existing object */
754 				free_one_object(obj);
755 			}
756 		} else {
757 			/* failed registering it */
758 			free_one_object(obj);
759 		}
760 	}
761 
762 	/* update the portal group object for the associations between */
763 	/* the newly registered objects and previously registered objects */
764 	if (ec == 0) {
765 		ec = verify_ref_obj(ptype, puid, child);
766 	}
767 	if (ec != 0) {
768 		goto reg_done;
769 	}
770 
771 	/* update the children list of the parent object */
772 	while (i < MAX_CHILD_TYPE) {
773 		vpp = child[i];
774 		if (vpp != NULL) {
775 			break;
776 		}
777 		i ++;
778 	}
779 	if (vpp != NULL) {
780 		ec = update_child_obj(ptype, puid, child, 1);
781 	} else {
782 #ifndef SKIP_SRC_AUTH
783 		ec = ISNS_RSP_INVALID_REGIS;
784 #else
785 		/* for interop-ability, we cannot treat this as */
786 		/* an error, instead, remove the network entity */
787 		SET_UID_LCP(&lc, OBJ_ENTITY, puid);
788 		ec = dereg_object(&lc, 0);
789 		goto reg_done;
790 #endif
791 	}
792 	if (ec != 0) {
793 		goto reg_done;
794 	}
795 	/* add esi entry */
796 	if (ety_update != 0) {
797 		(void) esi_remove(puid);
798 	}
799 	ec = esi_add(puid, eid_attr->value.ptr, eid_attr->len);
800 
801 reg_done:
802 	conn->ec = ec;
803 	free_one_object(ety);
804 	uid = 0;
805 	while (uid < MAX_CHILD_TYPE) {
806 		if (child[uid] != NULL) {
807 			free(child[uid]);
808 		}
809 		uid ++;
810 	}
811 
812 	if (ec != 0) {
813 		isnslog(LOG_DEBUG, "dev_attr_reg", "error code: %d", ec);
814 	}
815 
816 	return (0);
817 }
818 
819 /*
820  * ****************************************************************************
821  *
822  * dev_attr_qry:
823  *	function which handles the isnsp DEV_ATTR_QRY message.
824  *
825  * conn	- the argument of the connection.
826  * return - 0: the message requires response.
827  *
828  * ****************************************************************************
829  */
830 static int
831 dev_attr_qry(
832 	conn_arg_t *conn
833 )
834 {
835 	int ec = 0;
836 
837 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
838 	isns_tlv_t *source = conn->in_packet.source;
839 	isns_tlv_t *key = conn->in_packet.key;
840 	uint16_t key_len = conn->in_packet.key_len;
841 	isns_tlv_t *op = conn->in_packet.op;
842 	uint16_t op_len = conn->in_packet.op_len;
843 
844 	uchar_t *iscsi_name;
845 
846 	bmp_t *nodes_bmp = NULL;
847 	uint32_t num_of_nodes;
848 	uint32_t *key_uids = NULL;
849 	uint32_t num_of_keys;
850 	isns_type_t key_type;
851 
852 	uint32_t key_uid;
853 	uint32_t op_uid;
854 
855 	uint32_t size_of_ops;
856 	uint32_t num_of_ops;
857 	uint32_t *op_uids = NULL;
858 	isns_type_t op_type;
859 
860 	isns_tlv_t *tlv;
861 	uint16_t tlv_len;
862 
863 	isnslog(LOG_DEBUG, "dev_attr_qry", "entered");
864 
865 	ec = pdu_reset_rsp(&conn->out_packet.pdu,
866 	    &conn->out_packet.pl,
867 	    &conn->out_packet.sz);
868 	if (ec != 0) {
869 		goto qry_done;
870 	}
871 
872 	/*
873 	 * RFC 4171 section 5.7.5.2:
874 	 * If no Operating Attributes are included in the original query, then
875 	 * all Operating Attributes SHALL be returned in the response. ???
876 	 */
877 	if (op_len == 0) {
878 		goto qry_done;
879 	}
880 
881 	iscsi_name = (uchar_t *)&source->attr_value[0];
882 	if (is_control_node(iscsi_name) == 0) {
883 		ec = get_scope(iscsi_name, &nodes_bmp, &num_of_nodes);
884 		if (ec != 0 || nodes_bmp == NULL) {
885 			goto qry_done;
886 		}
887 	}
888 
889 	size_of_ops = 0;
890 	if (key != NULL) {
891 		/*
892 		 * Return the original message key.
893 		 */
894 		ec = rsp_add_tlvs(conn, key, key_len);
895 		if (ec != 0) {
896 			goto qry_done;
897 		}
898 
899 		/*
900 		 * Delimiter
901 		 */
902 		ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0);
903 		if (ec != 0) {
904 			goto qry_done;
905 		}
906 
907 		/*
908 		 * Query objects which match the Key Attributes.
909 		 */
910 		ec = get_qry_keys(nodes_bmp, num_of_nodes, &key_type,
911 		    key, key_len, &key_uids, &num_of_keys);
912 		if (ec != 0 || key_uids == NULL) {
913 			goto qry_done;
914 		}
915 
916 		/*
917 		 * Iterate thru each object identified by the message key.
918 		 */
919 		tlv = op;
920 		tlv_len = op_len;
921 		FOR_EACH_OBJS(key_uids, num_of_keys, key_uid, {
922 			/*
923 			 * Iterate thru each Operating Attributes.
924 			 */
925 			op = tlv;
926 			op_len = tlv_len;
927 			FOR_EACH_OP(op, op_len, op_type, {
928 				if (op_type == 0) {
929 					ec = ISNS_RSP_INVALID_QRY;
930 					goto qry_done;
931 				}
932 				ec = get_qry_ops(key_uid, key_type,
933 				    op_type, &op_uids,
934 				    &num_of_ops, &size_of_ops);
935 				if (ec != 0) {
936 					goto qry_done;
937 				}
938 				/*
939 				 * Iterate thru each object for the Operating
940 				 * Attributes again.
941 				 */
942 				FOR_EACH_OBJS(op_uids, num_of_ops, op_uid, {
943 					ec = get_qry_attrs(op_uid, op_type,
944 					    op, op_len, conn);
945 					if (ec != 0) {
946 						goto qry_done;
947 					}
948 				});
949 			});
950 		});
951 	} else {
952 		/*
953 		 * Iterate thru each Operating Attributes.
954 		 */
955 		FOR_EACH_OP(op, op_len, op_type, {
956 			ec = get_qry_ops2(nodes_bmp, num_of_nodes,
957 			    op_type, &op_uids,
958 			    &num_of_ops, &size_of_ops);
959 			if (ec != 0) {
960 				goto qry_done;
961 			}
962 			/*
963 			 * Iterate thru each object for the Operating
964 			 * Attributes again.
965 			 */
966 			FOR_EACH_OBJS(op_uids, num_of_ops, op_uid, {
967 				ec = get_qry_attrs(op_uid, op_type,
968 				    op, op_len, conn);
969 				if (ec != 0) {
970 					goto qry_done;
971 				}
972 			});
973 		});
974 	}
975 
976 qry_done:
977 	conn->ec = ec;
978 
979 	if (ec != 0) {
980 		isnslog(LOG_DEBUG, "dev_attr_qry", "error code: %d", ec);
981 	}
982 
983 	free(nodes_bmp);
984 	free(key_uids);
985 	free(op_uids);
986 
987 	return (0);
988 }
989 
990 /*
991  * ****************************************************************************
992  *
993  * dev_get_next:
994  *	function which handles the isnsp DEV_GET_NEXT message.
995  *
996  * conn	- the argument of the connection.
997  * return - 0: the message requires response.
998  *
999  * ****************************************************************************
1000  */
1001 static int
1002 dev_get_next(
1003 	conn_arg_t *conn
1004 )
1005 {
1006 	int ec = 0;
1007 
1008 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1009 	isns_tlv_t *source = conn->in_packet.source;
1010 	isns_tlv_t *key = conn->in_packet.key;
1011 	uint16_t key_len = conn->in_packet.key_len;
1012 	isns_tlv_t *op = conn->in_packet.op;
1013 	uint16_t op_len = conn->in_packet.op_len;
1014 
1015 	uchar_t *iscsi_name;
1016 
1017 	bmp_t *nodes_bmp = NULL;
1018 	uint32_t num_of_nodes;
1019 
1020 	isns_type_t key_type;
1021 	isns_type_t op_type;
1022 	uint32_t size_of_obj;
1023 	uint32_t num_of_obj;
1024 	uint32_t *obj_uids = NULL;
1025 
1026 	uint32_t uid;
1027 
1028 	isnslog(LOG_DEBUG, "dev_get_next", "entered");
1029 
1030 	ec = pdu_reset_rsp(&conn->out_packet.pdu,
1031 	    &conn->out_packet.pl,
1032 	    &conn->out_packet.sz);
1033 	if (ec != 0) {
1034 		goto get_next_done;
1035 	}
1036 
1037 	iscsi_name = (uchar_t *)&source->attr_value[0];
1038 	if (is_control_node(iscsi_name) == 0) {
1039 		ec = get_scope(iscsi_name, &nodes_bmp, &num_of_nodes);
1040 		if (nodes_bmp == NULL) {
1041 			ec = ISNS_RSP_NO_SUCH_ENTRY;
1042 		}
1043 		if (ec != 0) {
1044 			goto get_next_done;
1045 		}
1046 	}
1047 
1048 	/*
1049 	 * Get Message Key type and validate the Message Key.
1050 	 */
1051 	key_type = TLV2TYPE(key);
1052 	if (key_type == 0) {
1053 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
1054 		goto get_next_done;
1055 	}
1056 	ec = validate_qry_key(key_type, key, key_len, NULL);
1057 	if (ec != 0) {
1058 		goto get_next_done;
1059 	}
1060 
1061 	size_of_obj = 0;
1062 	if (op != NULL) {
1063 		/*
1064 		 * Query the objects which match the Operating Attributes.
1065 		 */
1066 		ec = get_qry_keys(nodes_bmp, num_of_nodes, &op_type,
1067 		    op, op_len, &obj_uids, &num_of_obj);
1068 		if (op_type != key_type) {
1069 			ec = ISNS_RSP_MSG_FORMAT_ERROR;
1070 		}
1071 	} else {
1072 		/*
1073 		 * Query the objects which match the Message Key type.
1074 		 */
1075 		ec = get_qry_ops2(nodes_bmp, num_of_nodes,
1076 		    key_type, &obj_uids, &num_of_obj, &size_of_obj);
1077 	}
1078 	if (ec != 0) {
1079 		goto get_next_done;
1080 	}
1081 
1082 	/*
1083 	 * Get the object which is next to the one indicated by the
1084 	 * Message Key.
1085 	 */
1086 	uid = get_next_obj(key, key_len, key_type, obj_uids, num_of_obj);
1087 	if (uid == 0) {
1088 		ec = ISNS_RSP_NO_SUCH_ENTRY;
1089 		goto get_next_done;
1090 	}
1091 
1092 	/*
1093 	 * Message Key
1094 	 */
1095 	if ((ec = get_qry_attrs1(uid, key_type, key, key_len, conn)) != 0) {
1096 		goto get_next_done;
1097 	}
1098 
1099 	/*
1100 	 * Delimiter
1101 	 */
1102 	if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)) != 0) {
1103 		goto get_next_done;
1104 	}
1105 
1106 	/*
1107 	 * Operating Attributes
1108 	 */
1109 	if (op != NULL) {
1110 		ec = get_qry_attrs(uid, op_type, op, op_len, conn);
1111 	}
1112 
1113 get_next_done:
1114 	conn->ec = ec;
1115 
1116 	if (ec != 0 && ec != ISNS_RSP_NO_SUCH_ENTRY) {
1117 		isnslog(LOG_DEBUG, "dev_get_next", "error code: %d", ec);
1118 	}
1119 
1120 	free(nodes_bmp);
1121 	free(obj_uids);
1122 
1123 	return (0);
1124 }
1125 
1126 /*
1127  * ****************************************************************************
1128  *
1129  * dev_dereg:
1130  *	function which handles the isnsp DEV_DEREG message.
1131  *
1132  * conn	- the argument of the connection.
1133  * return - 0: the message requires response.
1134  *
1135  * ****************************************************************************
1136  */
1137 static int
1138 dev_dereg(
1139 	conn_arg_t *conn
1140 )
1141 {
1142 	int ec = 0;
1143 
1144 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1145 	isns_tlv_t *source = conn->in_packet.source;
1146 	/* isns_tlv_t *key = conn->in_packet.key; */
1147 	/* uint16_t key_len = conn->in_packet.key_len; */
1148 	isns_tlv_t *op = conn->in_packet.op;
1149 	uint16_t op_len = conn->in_packet.op_len;
1150 
1151 	uchar_t *iscsi_name;
1152 	int ctrl;
1153 	uint32_t puid;
1154 
1155 	lookup_ctrl_t lc;
1156 	uint8_t *value;
1157 
1158 	isnslog(LOG_DEBUG, "dev_dereg", "entered");
1159 
1160 	iscsi_name = (uchar_t *)&source->attr_value[0];
1161 	ctrl = is_control_node(iscsi_name);
1162 	if (ctrl == 0) {
1163 		puid = is_parent_there(iscsi_name);
1164 	}
1165 
1166 	while (op_len > 8 && ec == 0) {
1167 		lc.curr_uid = 0;
1168 		value = &op->attr_value[0];
1169 		switch (op->attr_id) {
1170 		case ISNS_EID_ATTR_ID:
1171 			lc.id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID);
1172 			lc.op[0] = OP_STRING;
1173 			lc.data[0].ptr = (uchar_t *)value;
1174 			lc.op[1] = 0;
1175 			lc.type = OBJ_ENTITY;
1176 			break;
1177 		case ISNS_ISCSI_NAME_ATTR_ID:
1178 			lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID);
1179 			lc.op[0] = OP_STRING;
1180 			lc.data[0].ptr = (uchar_t *)value;
1181 			lc.op[1] = 0;
1182 			lc.type = OBJ_ISCSI;
1183 			break;
1184 		case ISNS_ISCSI_NODE_INDEX_ATTR_ID:
1185 			lc.id[0] = ATTR_INDEX_ISCSI(
1186 			    ISNS_ISCSI_NODE_INDEX_ATTR_ID);
1187 			lc.op[0] = OP_INTEGER;
1188 			lc.data[0].ui = ntohl(*(uint32_t *)value);
1189 			lc.op[1] = 0;
1190 			lc.type = OBJ_ISCSI;
1191 			break;
1192 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
1193 			lc.id[0] = ATTR_INDEX_PORTAL(
1194 			    ISNS_PORTAL_IP_ADDR_ATTR_ID);
1195 			lc.op[0] = OP_MEMORY_IP6;
1196 			lc.data[0].ip = (in6_addr_t *)value;
1197 			NEXT_TLV(op, op_len);
1198 			if (op_len > 8 &&
1199 			    op->attr_id == ISNS_PORTAL_PORT_ATTR_ID) {
1200 				value = &op->attr_value[0];
1201 				lc.id[1] = ATTR_INDEX_PORTAL(
1202 				    ISNS_PORTAL_PORT_ATTR_ID);
1203 				lc.op[1] = OP_INTEGER;
1204 				lc.data[1].ui = ntohl(*(uint32_t *)value);
1205 				lc.op[2] = 0;
1206 				lc.type = OBJ_PORTAL;
1207 			} else {
1208 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1209 			}
1210 			break;
1211 		case ISNS_PORTAL_INDEX_ATTR_ID:
1212 			lc.id[0] = ATTR_INDEX_PORTAL(
1213 			    ISNS_PORTAL_INDEX_ATTR_ID);
1214 			lc.op[0] = OP_INTEGER;
1215 			lc.data[0].ui = ntohl(*(uint32_t *)value);
1216 			lc.op[1] = 0;
1217 			lc.type = OBJ_PORTAL;
1218 			break;
1219 		default:
1220 			ec = ISNS_RSP_MSG_FORMAT_ERROR;
1221 			break;
1222 		}
1223 		if (ec == 0 &&
1224 		    (ec = dereg_object(&lc, 0)) == 0) {
1225 			if (ctrl == 0 &&
1226 #ifndef SKIP_SRC_AUTH
1227 			    lc.curr_uid != 0 &&
1228 			    puid != lc.curr_uid) {
1229 #else
1230 			    0) {
1231 #endif
1232 				ec = ISNS_RSP_SRC_UNAUTHORIZED;
1233 			} else {
1234 				NEXT_TLV(op, op_len);
1235 			}
1236 		}
1237 	}
1238 
1239 	conn->ec = ec;
1240 
1241 	if (ec != 0) {
1242 		isnslog(LOG_DEBUG, "dev_dereg", "error code: %d", ec);
1243 	}
1244 
1245 	return (0);
1246 }
1247 
1248 /*
1249  * ****************************************************************************
1250  *
1251  * scn_reg:
1252  *	function which handles the isnsp SCN_REG message.
1253  *
1254  * conn	- the argument of the connection.
1255  * return - 0: the message requires response.
1256  *
1257  * ****************************************************************************
1258  */
1259 static int
1260 scn_reg(
1261 	conn_arg_t *conn
1262 )
1263 {
1264 	int ec = 0;
1265 
1266 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1267 	/* isns_tlv_t *source = conn->in_packet.source; */
1268 	isns_tlv_t *key = conn->in_packet.key;
1269 	uint16_t key_len = conn->in_packet.key_len;
1270 	isns_tlv_t *op = conn->in_packet.op;
1271 	uint16_t op_len = conn->in_packet.op_len;
1272 
1273 	/* uchar_t *src; */
1274 	uchar_t *node_name;
1275 	uint32_t nlen;
1276 	uint32_t scn;
1277 
1278 	isnslog(LOG_DEBUG, "scn_reg", "entered");
1279 
1280 	/* src = (uchar_t *)&source->attr_value[0]; */
1281 
1282 	if (op == NULL ||
1283 	    op->attr_id != ISNS_ISCSI_SCN_BITMAP_ATTR_ID ||
1284 	    op_len != 12 ||
1285 	    key == NULL ||
1286 	    key->attr_id != ISNS_ISCSI_NAME_ATTR_ID ||
1287 	    key_len != 8 + key->attr_len) {
1288 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
1289 		goto scn_reg_done;
1290 	}
1291 
1292 	node_name = (uchar_t *)&key->attr_value[0];
1293 	nlen = key->attr_len;
1294 	scn = ntohl(*(uint32_t *)&op->attr_value[0]);
1295 
1296 	ec = add_scn_entry(node_name, nlen, scn);
1297 
1298 scn_reg_done:
1299 	conn->ec = ec;
1300 
1301 	if (ec != 0) {
1302 		isnslog(LOG_DEBUG, "scn_reg", "error code: %d", ec);
1303 	}
1304 
1305 	return (0);
1306 }
1307 
1308 /*
1309  * ****************************************************************************
1310  *
1311  * scn_dereg:
1312  *	function which handles the isnsp SCN_DEREG message.
1313  *
1314  * conn	- the argument of the connection.
1315  * return - 0: the message requires response.
1316  *
1317  * ****************************************************************************
1318  */
1319 static int
1320 scn_dereg(
1321 	conn_arg_t *conn
1322 )
1323 {
1324 	int ec = 0;
1325 
1326 	isns_tlv_t *key = conn->in_packet.key;
1327 	uint16_t key_len = conn->in_packet.key_len;
1328 
1329 	uchar_t *node_name;
1330 
1331 	isnslog(LOG_DEBUG, "scn_dereg", "entered");
1332 
1333 	if (key != NULL &&
1334 	    key->attr_len != 0 &&
1335 	    key_len == 8 + key->attr_len &&
1336 	    key->attr_id == ISNS_ISCSI_NAME_ATTR_ID) {
1337 		node_name = (uchar_t *)&key->attr_value[0];
1338 		ec = remove_scn_entry(node_name);
1339 	} else {
1340 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
1341 	}
1342 
1343 	conn->ec = ec;
1344 
1345 	if (ec != 0) {
1346 		isnslog(LOG_DEBUG, "scn_dereg", "error code: %d", ec);
1347 	}
1348 
1349 	return (0);
1350 }
1351 
1352 /*
1353  * ****************************************************************************
1354  *
1355  * setup_ddid_lcp:
1356  *	setup the lookup control data for looking up the DD object
1357  *	by using the dd_id attribute.
1358  *
1359  * lcp	- pointer to the lookup control data.
1360  * dd_id- the unique ID of the DD object.
1361  * return - the pointer to the lcp.
1362  *
1363  * ****************************************************************************
1364  */
1365 #ifndef DEBUG
1366 static
1367 #endif
1368 lookup_ctrl_t *
1369 setup_ddid_lcp(
1370 	lookup_ctrl_t *lcp,
1371 	uint32_t dd_id
1372 )
1373 {
1374 	lcp->curr_uid = 0;
1375 	lcp->type = OBJ_DD;
1376 	lcp->id[0] = ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID);
1377 	lcp->op[0] = OP_INTEGER;
1378 	lcp->data[0].ui = dd_id;
1379 	lcp->op[1] = 0;
1380 
1381 	return (lcp);
1382 }
1383 
1384 /*
1385  * ****************************************************************************
1386  *
1387  * setup_ddsid_lcp:
1388  *	setup the lookup control data for looking up the DD-set object
1389  *	by using the dds_id attribute.
1390  *
1391  * lcp	- pointer to the lookup control data.
1392  * dds_id - the unique ID of the DD-set object.
1393  * return - the pointer to the lcp.
1394  *
1395  * ****************************************************************************
1396  */
1397 #ifndef DEBUG
1398 static
1399 #endif
1400 lookup_ctrl_t *
1401 setup_ddsid_lcp(
1402 	lookup_ctrl_t *lcp,
1403 	uint32_t dds_id
1404 )
1405 {
1406 	lcp->curr_uid = 0;
1407 	lcp->type = OBJ_DDS;
1408 	lcp->id[0] = ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID);
1409 	lcp->op[0] = OP_INTEGER;
1410 	lcp->data[0].ui = dds_id;
1411 	lcp->op[1] = 0;
1412 
1413 	return (lcp);
1414 }
1415 
1416 /*
1417  * ****************************************************************************
1418  *
1419  * dd_reg:
1420  *	function which handles the isnsp DD_REG message.
1421  *
1422  * conn	- the argument of the connection.
1423  * return - 0: the message requires response.
1424  *
1425  * ****************************************************************************
1426  */
1427 static int
1428 dd_reg(
1429 	conn_arg_t *conn
1430 )
1431 {
1432 	int ec = 0;
1433 
1434 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1435 	isns_tlv_t *source = conn->in_packet.source;
1436 	isns_tlv_t *key = conn->in_packet.key;
1437 	uint16_t key_len = conn->in_packet.key_len;
1438 	isns_tlv_t *op = conn->in_packet.op;
1439 	uint16_t op_len = conn->in_packet.op_len;
1440 
1441 	uint32_t dd_id = 0;
1442 	uint8_t *value;
1443 
1444 	isns_obj_t *dd = NULL;
1445 
1446 	uchar_t *iscsi_name;
1447 
1448 	lookup_ctrl_t lc;
1449 	isns_assoc_iscsi_t aiscsi;
1450 	isns_obj_t *assoc;
1451 	isns_attr_t *attr;
1452 
1453 	uint32_t features;
1454 
1455 	isnslog(LOG_DEBUG, "dd_reg", "entered");
1456 
1457 	iscsi_name = (uchar_t *)&source->attr_value[0];
1458 	if (is_control_node(iscsi_name) == 0) {
1459 		ec = ISNS_RSP_SRC_UNAUTHORIZED;
1460 		goto dd_reg_done;
1461 	}
1462 
1463 	ec = pdu_reset_rsp(&conn->out_packet.pdu,
1464 	    &conn->out_packet.pl,
1465 	    &conn->out_packet.sz);
1466 	if (ec != 0) {
1467 		goto dd_reg_done;
1468 	}
1469 
1470 	if (op == NULL ||
1471 	    (key != NULL &&
1472 	    (key_len != 12 ||
1473 	    key->attr_id != ISNS_DD_ID_ATTR_ID ||
1474 	    key->attr_len != 4 ||
1475 	    (dd_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0 ||
1476 	    is_obj_there(setup_ddid_lcp(&lc, dd_id)) == 0))) {
1477 		ec = ISNS_RSP_INVALID_REGIS;
1478 		goto dd_reg_done;
1479 	}
1480 
1481 	/* message key */
1482 	if (key != NULL &&
1483 	    (ec = rsp_add_tlv(conn, ISNS_DD_ID_ATTR_ID, 4,
1484 	    (void *)dd_id, 0)) != 0) {
1485 		goto dd_reg_done;
1486 	}
1487 
1488 	/* delimiter */
1489 	if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0,
1490 	    NULL, 0)) != 0) {
1491 		goto dd_reg_done;
1492 	}
1493 
1494 	/* A DDReg message with no Message Key SHALL result in the */
1495 	/* attempted creation of a new Discovery Domain (DD). */
1496 	if (dd_id == 0) {
1497 		ec = create_dd_object(op, op_len, &dd);
1498 		if (ec == 0) {
1499 			ec = register_object(dd, &dd_id, NULL);
1500 			if (ec == ERR_NAME_IN_USE) {
1501 				ec = ISNS_RSP_INVALID_REGIS;
1502 			}
1503 			if (ec != 0) {
1504 				free_object(dd);
1505 				goto dd_reg_done;
1506 			}
1507 		} else {
1508 			goto dd_reg_done;
1509 		}
1510 	}
1511 
1512 	/* add the newly created dd to the response */
1513 	if (dd != NULL) {
1514 		ec = rsp_add_op(conn, dd);
1515 	}
1516 
1517 	aiscsi.type = OBJ_ASSOC_ISCSI;
1518 	aiscsi.puid = dd_id;
1519 
1520 	while (op_len > 8 && ec == 0) {
1521 		value = &op->attr_value[0];
1522 		switch (op->attr_id) {
1523 		case ISNS_DD_ID_ATTR_ID:
1524 			/* if the DD_ID is included in both the Message Key */
1525 			/* and Operating Attributes, then the DD_ID value */
1526 			/* in the Message Key MUST be the same as the DD_ID */
1527 			/* value in the Operating Attributes. */
1528 			if (dd == NULL) {
1529 				if (op->attr_len != 4 ||
1530 				    dd_id != ntohl(*(uint32_t *)value)) {
1531 					ec = ISNS_RSP_INVALID_REGIS;
1532 				} else {
1533 					ec = rsp_add_tlv(conn,
1534 					    ISNS_DD_ID_ATTR_ID, 4,
1535 					    (void *)dd_id, 0);
1536 				}
1537 			}
1538 			break;
1539 		case ISNS_DD_NAME_ATTR_ID:
1540 			/* It is going to modify the DD Symbolic Name. */
1541 			if (dd == NULL) {
1542 				if (op->attr_len > 0 && op->attr_len <= 256) {
1543 					ec = update_dd_name(
1544 					    dd_id,
1545 					    op->attr_len,
1546 					    (uchar_t *)value);
1547 					if (ec == ERR_NAME_IN_USE) {
1548 						ec = ISNS_RSP_INVALID_REGIS;
1549 					}
1550 				} else {
1551 					ec = ISNS_RSP_INVALID_REGIS;
1552 				}
1553 				if (ec == 0) {
1554 					ec = rsp_add_tlv(conn,
1555 					    ISNS_DD_NAME_ATTR_ID,
1556 					    op->attr_len, (void *)value, 1);
1557 				}
1558 			}
1559 			break;
1560 		case ISNS_DD_ISCSI_INDEX_ATTR_ID:
1561 			if (op->attr_len == 4) {
1562 				/* zero the association object */
1563 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1564 				    ISNS_DD_ISCSI_INDEX_ATTR_ID)];
1565 				attr->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
1566 				attr->len = 4;
1567 				attr->value.ui = ntohl(*(uint32_t *)value);
1568 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1569 				    ISNS_DD_ISCSI_NAME_ATTR_ID)];
1570 				attr->tag = 0; /* clear it */
1571 				attr->value.ptr = NULL; /* clear it */
1572 				assoc = (isns_obj_t *)&aiscsi;
1573 				if ((ec = add_dd_member(assoc)) ==
1574 				    ERR_ALREADY_ASSOCIATED) {
1575 					ec = 0;
1576 				}
1577 				if (attr->value.ptr != NULL) {
1578 					free(attr->value.ptr);
1579 				}
1580 			} else {
1581 				ec = ISNS_RSP_INVALID_REGIS;
1582 			}
1583 			if (ec == 0) {
1584 				ec = rsp_add_tlv(conn,
1585 				    ISNS_DD_ISCSI_INDEX_ATTR_ID,
1586 				    4, (void *)attr->value.ui, 0);
1587 			}
1588 			break;
1589 		case ISNS_DD_ISCSI_NAME_ATTR_ID:
1590 			if (op->attr_len > 0 && op->attr_len <= 224) {
1591 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1592 				    ISNS_DD_ISCSI_NAME_ATTR_ID)];
1593 				attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
1594 				attr->len = op->attr_len;
1595 				attr->value.ptr = (uchar_t *)value;
1596 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1597 				    ISNS_DD_ISCSI_INDEX_ATTR_ID)];
1598 				attr->tag = 0; /* clear it */
1599 				assoc = (isns_obj_t *)&aiscsi;
1600 				if ((ec = add_dd_member(assoc)) ==
1601 				    ERR_ALREADY_ASSOCIATED) {
1602 					ec = 0;
1603 				}
1604 			} else {
1605 				ec = ISNS_RSP_INVALID_REGIS;
1606 			}
1607 			if (ec == 0) {
1608 				ec = rsp_add_tlv(conn,
1609 				    ISNS_DD_ISCSI_NAME_ATTR_ID,
1610 				    op->attr_len, (void *)value, 1);
1611 			}
1612 			break;
1613 		case ISNS_DD_FC_PORT_NAME_ATTR_ID:
1614 		case ISNS_DD_PORTAL_INDEX_ATTR_ID:
1615 		case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
1616 		case ISNS_DD_PORTAL_PORT_ATTR_ID:
1617 			ec = ISNS_RSP_REGIS_NOT_SUPPORTED;
1618 			break;
1619 		case ISNS_DD_FEATURES_ATTR_ID:
1620 			/* It is going to modify the DD Symbolic Name. */
1621 			if (dd == NULL) {
1622 				if (op->attr_len == 4) {
1623 					features = ntohl(*(uint32_t *)value);
1624 					ec = update_dd_features(
1625 					    dd_id, features);
1626 				} else {
1627 					ec = ISNS_RSP_INVALID_REGIS;
1628 				}
1629 				if (ec == 0) {
1630 					ec = rsp_add_tlv(conn,
1631 					    ISNS_DD_FEATURES_ATTR_ID,
1632 					    4, (void *)features, 0);
1633 				}
1634 			}
1635 			break;
1636 		default:
1637 			ec = ISNS_RSP_INVALID_REGIS;
1638 			break;
1639 		}
1640 
1641 		NEXT_TLV(op, op_len);
1642 	}
1643 
1644 dd_reg_done:
1645 	conn->ec = ec;
1646 
1647 	if (ec != 0) {
1648 		isnslog(LOG_DEBUG, "dd_reg", "error code: %d", ec);
1649 	}
1650 
1651 	return (0);
1652 }
1653 
1654 /*
1655  * ****************************************************************************
1656  *
1657  * dds_reg:
1658  *	function which handles the isnsp DDS_REG message.
1659  *
1660  * conn	- the argument of the connection.
1661  * return - 0: the message requires response.
1662  *
1663  * ****************************************************************************
1664  */
1665 static int
1666 dds_reg(
1667 	conn_arg_t *conn
1668 )
1669 {
1670 	int ec = 0;
1671 
1672 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1673 	isns_tlv_t *source = conn->in_packet.source;
1674 	isns_tlv_t *key = conn->in_packet.key;
1675 	uint16_t key_len = conn->in_packet.key_len;
1676 	isns_tlv_t *op = conn->in_packet.op;
1677 	uint16_t op_len = conn->in_packet.op_len;
1678 
1679 	uint32_t dds_id = 0;
1680 	uint8_t *value;
1681 
1682 	isns_obj_t *dds = NULL;
1683 
1684 	uchar_t *iscsi_name;
1685 
1686 	lookup_ctrl_t lc;
1687 	isns_assoc_dd_t add;
1688 	isns_obj_t *assoc;
1689 	isns_attr_t *attr;
1690 
1691 	uint32_t code;
1692 
1693 	isnslog(LOG_DEBUG, "dds_reg", "entered");
1694 
1695 	iscsi_name = (uchar_t *)&source->attr_value[0];
1696 	if (is_control_node(iscsi_name) == 0) {
1697 		ec = ISNS_RSP_SRC_UNAUTHORIZED;
1698 		goto dds_reg_done;
1699 	}
1700 
1701 	ec = pdu_reset_rsp(&conn->out_packet.pdu,
1702 	    &conn->out_packet.pl,
1703 	    &conn->out_packet.sz);
1704 	if (ec != 0) {
1705 		goto dds_reg_done;
1706 	}
1707 
1708 	if (op == NULL ||
1709 	    (key != NULL &&
1710 	    (key_len != 12 ||
1711 	    key->attr_id != ISNS_DD_SET_ID_ATTR_ID ||
1712 	    key->attr_len != 4 ||
1713 	    (dds_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0 ||
1714 	    is_obj_there(setup_ddsid_lcp(&lc, dds_id)) == 0))) {
1715 		ec = ISNS_RSP_INVALID_REGIS;
1716 		goto dds_reg_done;
1717 	}
1718 
1719 	/* message key */
1720 	if (key != NULL &&
1721 	    (ec = rsp_add_tlv(conn, ISNS_DD_SET_ID_ATTR_ID, 4,
1722 	    (void *)dds_id, 0)) != 0) {
1723 		goto dds_reg_done;
1724 	}
1725 
1726 	/* delimiter */
1727 	if ((ec = rsp_add_tlv(conn, ISNS_DELIMITER_ATTR_ID, 0,
1728 	    NULL, 0)) != 0) {
1729 		goto dds_reg_done;
1730 	}
1731 
1732 	/* A DDSReg message with no Message Key SHALL result in the */
1733 	/* attempted creation of a new Discovery Domain (DD). */
1734 	if (dds_id == 0) {
1735 		ec = create_dds_object(op, op_len, &dds);
1736 		if (ec == 0) {
1737 			ec = register_object(dds, &dds_id, NULL);
1738 			if (ec == ERR_NAME_IN_USE) {
1739 				ec = ISNS_RSP_INVALID_REGIS;
1740 			}
1741 			if (ec != 0) {
1742 				free_object(dds);
1743 				goto dds_reg_done;
1744 			}
1745 		} else {
1746 			goto dds_reg_done;
1747 		}
1748 	}
1749 
1750 	/* add the newly created dd to the response */
1751 	if (dds != NULL) {
1752 		ec = rsp_add_op(conn, dds);
1753 	}
1754 
1755 	add.type = OBJ_ASSOC_DD;
1756 	add.puid = dds_id;
1757 
1758 	while (op_len > 8 && ec == 0) {
1759 		value = &op->attr_value[0];
1760 		switch (op->attr_id) {
1761 		case ISNS_DD_SET_ID_ATTR_ID:
1762 			/* if the DDS_ID is included in both the Message Key */
1763 			/* and Operating Attributes, then the DDS_ID value */
1764 			/* in the Message Key MUST be the same as the DDS_ID */
1765 			/* value in the Operating Attributes. */
1766 			if (dds == NULL) {
1767 				if (op->attr_len != 4 ||
1768 				    dds_id != ntohl(*(uint32_t *)value)) {
1769 					ec = ISNS_RSP_INVALID_REGIS;
1770 				} else {
1771 					ec = rsp_add_tlv(conn,
1772 					    ISNS_DD_SET_ID_ATTR_ID,
1773 					    4, (void *)dds_id, 0);
1774 				}
1775 			}
1776 			break;
1777 		case ISNS_DD_SET_NAME_ATTR_ID:
1778 			/* It is going to modify the DD Symbolic Name. */
1779 			if (dds == NULL) {
1780 				if (op->attr_len > 0 && op->attr_len <= 256) {
1781 					ec = update_dds_name(
1782 					    dds_id,
1783 					    op->attr_len,
1784 					    (uchar_t *)value);
1785 					if (ec == ERR_NAME_IN_USE) {
1786 						ec = ISNS_RSP_INVALID_REGIS;
1787 					}
1788 				} else {
1789 					ec = ISNS_RSP_INVALID_REGIS;
1790 				}
1791 				if (ec == 0) {
1792 					ec = rsp_add_tlv(conn,
1793 					    ISNS_DD_SET_NAME_ATTR_ID,
1794 					    op->attr_len, (void *)value, 1);
1795 				}
1796 			}
1797 			break;
1798 		case ISNS_DD_SET_STATUS_ATTR_ID:
1799 			/* It is going to modify the DD Symbolic Name. */
1800 			if (dds == NULL) {
1801 				if (op->attr_len == 4) {
1802 					code = ntohl(*(uint32_t *)value);
1803 					ec = update_dds_status(
1804 					    dds_id, code);
1805 				} else {
1806 					ec = ISNS_RSP_INVALID_REGIS;
1807 				}
1808 				if (ec == 0) {
1809 					ec = rsp_add_tlv(conn,
1810 					    ISNS_DD_SET_STATUS_ATTR_ID,
1811 					    4, (void *)code, 0);
1812 				}
1813 			}
1814 			break;
1815 		case ISNS_DD_ID_ATTR_ID:
1816 			if (op->attr_len == 4) {
1817 				/* zero the association object */
1818 				attr = &add.attrs[ATTR_INDEX_ASSOC_DD(
1819 				    ISNS_DD_ID_ATTR_ID)];
1820 				attr->tag = ISNS_DD_ID_ATTR_ID;
1821 				attr->len = 4;
1822 				attr->value.ui = ntohl(*(uint32_t *)value);
1823 				assoc = (isns_obj_t *)&add;
1824 				if ((ec = add_dds_member(assoc)) ==
1825 				    ERR_ALREADY_ASSOCIATED) {
1826 					ec = 0;
1827 				}
1828 			} else {
1829 				ec = ISNS_RSP_INVALID_REGIS;
1830 			}
1831 			if (ec == 0) {
1832 				ec = rsp_add_tlv(conn,
1833 				    ISNS_DD_ID_ATTR_ID, 4,
1834 				    (void *)attr->value.ui, 0);
1835 			}
1836 			break;
1837 		default:
1838 			ec = ISNS_RSP_INVALID_REGIS;
1839 			break;
1840 		}
1841 
1842 		NEXT_TLV(op, op_len);
1843 	}
1844 
1845 dds_reg_done:
1846 	conn->ec = ec;
1847 
1848 	if (ec != 0) {
1849 		isnslog(LOG_DEBUG, "dds_reg", "error code: %d", ec);
1850 	}
1851 
1852 	return (0);
1853 }
1854 
1855 /*
1856  * ****************************************************************************
1857  *
1858  * dd_dereg:
1859  *	function which handles the isnsp DD_DEREG message.
1860  *
1861  * conn	- the argument of the connection.
1862  * return - 0: the message requires response.
1863  *
1864  * ****************************************************************************
1865  */
1866 static int
1867 dd_dereg(
1868 	conn_arg_t *conn
1869 )
1870 {
1871 	int ec = 0;
1872 
1873 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1874 	isns_tlv_t *source = conn->in_packet.source;
1875 	isns_tlv_t *key = conn->in_packet.key;
1876 	uint16_t key_len = conn->in_packet.key_len;
1877 	isns_tlv_t *op = conn->in_packet.op;
1878 	uint16_t op_len = conn->in_packet.op_len;
1879 
1880 	uint32_t dd_id;
1881 	uint8_t *value;
1882 
1883 	uchar_t *iscsi_name;
1884 
1885 	isns_assoc_iscsi_t aiscsi;
1886 	isns_obj_t *assoc;
1887 	isns_attr_t *attr;
1888 
1889 	isnslog(LOG_DEBUG, "dd_dereg", "entered");
1890 
1891 	iscsi_name = (uchar_t *)&source->attr_value[0];
1892 	if (is_control_node(iscsi_name) == 0) {
1893 		ec = ISNS_RSP_SRC_UNAUTHORIZED;
1894 		goto dd_dereg_done;
1895 	}
1896 
1897 	if (key == NULL ||
1898 	    key_len != 12 ||
1899 	    key->attr_id != ISNS_DD_ID_ATTR_ID ||
1900 	    (dd_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0) {
1901 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
1902 		goto dd_dereg_done;
1903 	}
1904 
1905 	if (op == NULL) {
1906 		ec = remove_dd_object(dd_id);
1907 	} else {
1908 		aiscsi.type = OBJ_ASSOC_ISCSI;
1909 		aiscsi.puid = dd_id;
1910 
1911 		while (op_len > 8 && ec == 0) {
1912 			value = &op->attr_value[0];
1913 			switch (op->attr_id) {
1914 			case ISNS_DD_ISCSI_INDEX_ATTR_ID:
1915 				/* zero the association object */
1916 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1917 				    ISNS_DD_ISCSI_INDEX_ATTR_ID)];
1918 				attr->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID;
1919 				attr->len = 4;
1920 				attr->value.ui = ntohl(*(uint32_t *)value);
1921 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1922 				    ISNS_DD_ISCSI_NAME_ATTR_ID)];
1923 				attr->tag = 0; /* clear it */
1924 				attr->value.ptr = NULL; /* clear it */
1925 				assoc = (isns_obj_t *)&aiscsi;
1926 				if ((ec = remove_dd_member(assoc)) ==
1927 				    ERR_NO_SUCH_ASSOCIATION) {
1928 					ec = 0;
1929 				}
1930 				if (attr->value.ptr != NULL) {
1931 					free(attr->value.ptr);
1932 				}
1933 				break;
1934 			case ISNS_DD_ISCSI_NAME_ATTR_ID:
1935 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1936 				    ISNS_DD_ISCSI_NAME_ATTR_ID)];
1937 				attr->tag = ISNS_DD_ISCSI_NAME_ATTR_ID;
1938 				attr->len = op->attr_len;
1939 				attr->value.ptr = (uchar_t *)value;
1940 				attr = &aiscsi.attrs[ATTR_INDEX_ASSOC_ISCSI(
1941 				    ISNS_DD_ISCSI_INDEX_ATTR_ID)];
1942 				attr->tag = 0; /* clear it */
1943 				assoc = (isns_obj_t *)&aiscsi;
1944 				if ((ec = remove_dd_member(assoc)) ==
1945 				    ERR_NO_SUCH_ASSOCIATION) {
1946 					ec = 0;
1947 				}
1948 				break;
1949 			case ISNS_DD_FC_PORT_NAME_ATTR_ID:
1950 			case ISNS_DD_PORTAL_INDEX_ATTR_ID:
1951 			case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID:
1952 			case ISNS_DD_PORTAL_PORT_ATTR_ID:
1953 				ec = ISNS_RSP_REGIS_NOT_SUPPORTED;
1954 				break;
1955 			default:
1956 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
1957 				break;
1958 			}
1959 
1960 			NEXT_TLV(op, op_len);
1961 		}
1962 	}
1963 
1964 dd_dereg_done:
1965 	conn->ec = ec;
1966 
1967 	if (ec != 0) {
1968 		isnslog(LOG_DEBUG, "dd_dereg", "error code: %d", ec);
1969 	}
1970 
1971 	return (0);
1972 }
1973 
1974 /*
1975  * ****************************************************************************
1976  *
1977  * dds_dereg:
1978  *	function which handles the isnsp DDS_DEREG message.
1979  *
1980  * conn	- the argument of the connection.
1981  * return - 0: the message requires response.
1982  *
1983  * ****************************************************************************
1984  */
1985 static int
1986 dds_dereg(
1987 	conn_arg_t *conn
1988 )
1989 {
1990 	int ec = 0;
1991 
1992 	/* isns_pdu_t *pdu = conn->in_packet.pdu; */
1993 	isns_tlv_t *source = conn->in_packet.source;
1994 	isns_tlv_t *key = conn->in_packet.key;
1995 	uint16_t key_len = conn->in_packet.key_len;
1996 	isns_tlv_t *op = conn->in_packet.op;
1997 	uint16_t op_len = conn->in_packet.op_len;
1998 
1999 	uint32_t dds_id;
2000 	uint32_t uid;
2001 	uint8_t *value;
2002 
2003 	uchar_t *iscsi_name;
2004 
2005 	isnslog(LOG_DEBUG, "dds_dereg", "entered");
2006 
2007 	iscsi_name = (uchar_t *)&source->attr_value[0];
2008 	if (is_control_node(iscsi_name) == 0) {
2009 		ec = ISNS_RSP_SRC_UNAUTHORIZED;
2010 		goto dds_dereg_done;
2011 	}
2012 
2013 	if (key == NULL ||
2014 	    key_len != 12 ||
2015 	    key->attr_id != ISNS_DD_SET_ID_ATTR_ID ||
2016 	    (dds_id = ntohl(*(uint32_t *)&key->attr_value[0])) == 0) {
2017 		ec = ISNS_RSP_MSG_FORMAT_ERROR;
2018 		goto dds_dereg_done;
2019 	}
2020 
2021 	if (op == NULL) {
2022 		ec = remove_dds_object(dds_id);
2023 	} else {
2024 		while (op_len > 8 && ec == 0) {
2025 			value = &op->attr_value[0];
2026 			if (op->attr_id == ISNS_DD_ID_ATTR_ID) {
2027 				uid = ntohl(*(uint32_t *)value);
2028 				if ((ec = remove_dds_member(dds_id, uid)) ==
2029 				    ERR_NO_SUCH_ASSOCIATION) {
2030 					ec = 0;
2031 				}
2032 			} else {
2033 				ec = ISNS_RSP_MSG_FORMAT_ERROR;
2034 			}
2035 
2036 			NEXT_TLV(op, op_len);
2037 		}
2038 	}
2039 
2040 dds_dereg_done:
2041 	conn->ec = ec;
2042 
2043 	if (ec != 0) {
2044 		isnslog(LOG_DEBUG, "dds_dereg", "error code: %d", ec);
2045 	}
2046 
2047 	return (0);
2048 }
2049 
2050 /*
2051  * ****************************************************************************
2052  *
2053  * msg_error:
2054  *	function which handles any unknown isnsp messages or the
2055  *	messages which are not supported.
2056  *
2057  * conn	- the argument of the connection.
2058  * return - 0: the message requires response.
2059  *
2060  * ****************************************************************************
2061  */
2062 static int
2063 msg_error(
2064 	/* LINTED E_FUNC_ARG_UNUSED */
2065 	conn_arg_t *conn
2066 )
2067 {
2068 	return (0);
2069 }
2070 
2071 /*
2072  * ****************************************************************************
2073  *
2074  * isns_response_ec:
2075  *	send the response message to the client with error code.
2076  *
2077  * so	- the socket descriptor.
2078  * pdu	- the received pdu.
2079  * ec	- the error code which is being responsed.
2080  * return - status of the sending operation.
2081  *
2082  * ****************************************************************************
2083  */
2084 static int
2085 isns_response_ec(
2086 	int so,
2087 	isns_pdu_t *pdu,
2088 	int ec
2089 )
2090 {
2091 	int status;
2092 
2093 	uint8_t buff[sizeof (isns_pdu_t) + 8];
2094 
2095 	isns_pdu_t *rsp = (isns_pdu_t *)&buff;
2096 	isns_resp_t *resp = (isns_resp_t *)rsp->payload;
2097 	size_t pl = 4;
2098 
2099 	rsp->version = htons((uint16_t)ISNSP_VERSION);
2100 	rsp->func_id = htons(pdu->func_id | ISNS_RSP_MASK);
2101 	rsp->xid = htons(pdu->xid);
2102 	resp->status = htonl(ec);
2103 
2104 	status = isns_send_pdu(so, rsp, pl);
2105 
2106 	return (status);
2107 }
2108 
2109 /*
2110  * ****************************************************************************
2111  *
2112  * isns_response:
2113  *	send the response message to the client.
2114  *
2115  * conn	- the argument of the connection.
2116  * return - status of the sending operation.
2117  *
2118  * ****************************************************************************
2119  */
2120 int
2121 isns_response(
2122 	conn_arg_t *conn
2123 )
2124 {
2125 	int status;
2126 
2127 	int so = conn->so;
2128 	int ec = conn->ec;
2129 	isns_pdu_t *pdu = conn->in_packet.pdu;
2130 	isns_pdu_t *rsp = conn->out_packet.pdu;
2131 	size_t pl = conn->out_packet.pl;
2132 
2133 	if (rsp != NULL) {
2134 		rsp->version = htons((uint16_t)ISNSP_VERSION);
2135 		rsp->func_id = htons(pdu->func_id | ISNS_RSP_MASK);
2136 		rsp->xid = htons(pdu->xid);
2137 		(void) pdu_update_code(rsp, &pl, ec);
2138 		status = isns_send_pdu(so, rsp, pl);
2139 	} else {
2140 		status = isns_response_ec(so, pdu, ec);
2141 	}
2142 
2143 	return (status);
2144 }
2145