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