Home | History | Annotate | Download | only in iscsitgtd
      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 2010 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdio.h>
     28 #include <unistd.h>
     29 #include <stdlib.h>
     30 #include <strings.h>
     31 #include <syslog.h>
     32 #include <netdb.h>
     33 #include <pthread.h>
     34 #include <signal.h>
     35 #include <errno.h>
     36 #include <netinet/in.h>
     37 #include <sys/types.h>
     38 #include <sys/socket.h>
     39 #include <arpa/inet.h>
     40 
     41 #include <iscsitgt_impl.h>
     42 
     43 #include "isns_protocol.h"
     44 #include "isns_client.h"
     45 #include "target.h"
     46 #include "queue.h"
     47 
     48 
     49 typedef struct {
     50 	uint32_t	pf_family;
     51 	uint32_t	ip_len;
     52 	uint32_t	ai_addrlen;
     53 	union {
     54 		in_addr_t	in;
     55 		in6_addr_t	in6;
     56 	} ip_adr;
     57 } ip_t;
     58 
     59 #define	ISNS_TGT_LOGOUT		54321
     60 
     61 extern target_queue_t	*mgmtq;
     62 
     63 /*
     64  * Global
     65  * Parameters for ESI/SCN processing.
     66  * scn_port: ESI/SCN port to receive ISNS_ESI & ISNS_SCN messages
     67  * isns_args:
     68  * eid_ip: Entity IP info
     69  */
     70 static	int scn_port = 0;
     71 static	esi_scn_arg_t	isns_args = {{0}, {0}, 0};
     72 static	ip_t	eid_ip;
     73 static	int	num_reg = 0;
     74 static	pthread_t	scn_tid = 0;
     75 static	pthread_t	isns_tid = 0;
     76 static	Boolean_t	isns_shutdown = True;
     77 static	Boolean_t	connection_thr_bail_out = False;
     78 static int ISNS_SLEEP_SECS = 20;
     79 Boolean_t	isns_server_connection_thr_running = False;
     80 target_queue_t	*mgmtq = NULL;
     81 
     82 static	int	get_ip_addr(char *node, ip_t *sa);
     83 static	int	isns_op_all(uint16_t);
     84 static	int	append_tpgt(tgt_node_t *, isns_pdu_t *);
     85 static	void	process_esi(int, isns_pdu_t *);
     86 static	void	process_scn(int, isns_pdu_t *);
     87 static	void	*esi_scn_thr(void *);
     88 static	int	process_rsp(isns_pdu_t *, isns_rsp_t *);
     89 static	int	isns_dev_attr_reg(int, tgt_node_t *, char *, char *);
     90 static	int	isns_dev_attr_dereg(int, char *);
     91 static	int	isns_scn_reg(int, char *);
     92 static	int	isns_scn_dereg(int so, char *node);
     93 static	tgt_node_t	*find_tgt_by_name(char *, char **);
     94 static	tgt_node_t	*find_next_tgt(tgt_node_t *, char **);
     95 static int isns_populate_and_update_server_info(Boolean_t state);
     96 static int get_addr_family(char *node);
     97 
     98 /*
     99  * find_tgt_by_name searches DB by iscsi name or local name, if found
    100  * returns tgt_node_t.  iname needs to be free by caller.
    101  */
    102 static tgt_node_t *
    103 find_tgt_by_name(char *targ, char **iname)
    104 {
    105 	tgt_node_t	*tgt = NULL;
    106 
    107 	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    108 	    tgt)) != NULL) {
    109 		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname)
    110 		    == FALSE) {
    111 			syslog(LOG_ALERT, "ISNS: Missing iscsi name\n");
    112 			break;
    113 		}
    114 		/* match either iscsi name or local name */
    115 		if (strcmp(targ, tgt->x_value) == 0 ||
    116 		    strcmp(targ, *iname) == 0) {
    117 			return (tgt);
    118 		}
    119 		free(*iname);
    120 	}
    121 	return (NULL);
    122 }
    123 
    124 static tgt_node_t *
    125 find_next_tgt(tgt_node_t *tgt, char **iname)
    126 {
    127 	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    128 	    tgt)) != NULL) {
    129 		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname)
    130 		    == FALSE) {
    131 			continue;
    132 		}
    133 		return (tgt);
    134 	}
    135 	return (NULL);
    136 }
    137 
    138 /*
    139  * Find ip-addr associated with TPGT, don't send if no ip-addr is
    140  * found for a TPGT
    141  */
    142 static int
    143 append_tpgt(tgt_node_t *tgt, isns_pdu_t *cmd)
    144 {
    145 	tgt_node_t	*t, *x;
    146 	tgt_node_t	*pgt	= NULL;
    147 	tgt_node_t	*iplist	= NULL;
    148 	tgt_node_t	*tpgt	= NULL;
    149 	ip_t		eid;
    150 
    151 	/* Always add the default TPGT (1) */
    152 	(void) isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL,
    153 	    1);
    154 	if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
    155 	    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
    156 	    eid_ip.ip_len) != 0) {
    157 		return (-1);
    158 	}
    159 	if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID,
    160 	    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
    161 		return (-1);
    162 	}
    163 
    164 	/* Get the remainning TPGT-LIST */
    165 	if ((t = tgt_node_next(tgt, XML_ELEMENT_TPGTLIST, NULL))
    166 	    != NULL) {
    167 		/* find tgpt from tpgt-list */
    168 		while ((pgt = tgt_node_next(t, XML_ELEMENT_TPGT, pgt))
    169 		    != NULL) {
    170 			/* update isns only if TPGT contains ip_addr */
    171 			while ((tpgt = tgt_node_next_child(main_config,
    172 			    XML_ELEMENT_TPGT, tpgt)) != NULL) {
    173 				if (strcmp(pgt->x_value, tpgt->x_value) != 0)
    174 					continue;
    175 				if ((iplist = tgt_node_next(tpgt,
    176 				    XML_ELEMENT_IPADDRLIST, NULL)) != NULL)
    177 					break;
    178 			}
    179 			if (tpgt == NULL || iplist == NULL)
    180 				continue;
    181 			if (isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID,
    182 			    ISNS_PG_TAG_SZ, NULL,
    183 			    strtol(pgt->x_value, NULL, 0)) != 0) {
    184 				return (-1);
    185 			}
    186 
    187 			/* get ip-addr & port */
    188 			for (x = iplist->x_child; x; x = x->x_sibling) {
    189 				if (get_ip_addr(x->x_value, &eid) < 0)
    190 					continue;
    191 				if (isns_append_attr(cmd,
    192 				    ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
    193 				    eid.ai_addrlen, (void *)&eid.ip_adr,
    194 				    eid.ip_len) != 0) {
    195 					return (-1);
    196 				}
    197 				if (isns_append_attr(cmd,
    198 				    ISNS_PG_PORTAL_PORT_ATTR_ID,
    199 				    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
    200 					return (-1);
    201 				}
    202 			}
    203 		}
    204 	}
    205 
    206 	return (0);
    207 }
    208 
    209 /*
    210  * process_scn()
    211  *	-Added/Updated object: nop, initiator is verified during connect
    212  *
    213  *	-Removed object: logout_targ if still connected
    214  *
    215  * RFC 4171 section 5.6.5.9
    216  * destination attribute is always the 1st attribute in the SCN message,
    217  * then follows by SCN_BITMAP(35) & Source_Attribute(32)
    218  */
    219 static void
    220 process_scn(int so, isns_pdu_t *scn)
    221 {
    222 	uint8_t		*ptr = scn->payload;
    223 	isns_tlv_t	*tlv;
    224 	uint16_t	cnt = 0;
    225 	uint32_t	got_dest = 0;
    226 	uint32_t	got_source = 0;
    227 	uint32_t	bitmap = 0;
    228 	uint32_t	got_bitmap = 0;
    229 	char		dest[MAXNAMELEN];
    230 	char		source[MAXNAMELEN];
    231 
    232 	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u\n",
    233 	    scn->payload_len);
    234 
    235 	if (scn->payload_len < TAG_LEN_SZ) {
    236 		syslog(LOG_ALERT, "ISNS SCN message error\n");
    237 		return;
    238 	}
    239 
    240 	while (cnt < scn->payload_len) {
    241 		/* LINTED */
    242 		tlv = (isns_tlv_t *)ptr;
    243 		tlv->attr_id = ntohl(tlv->attr_id);
    244 		tlv->attr_len = ntohl(tlv->attr_len);
    245 		queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u %u\n",
    246 		    tlv->attr_id, tlv->attr_len);
    247 		/*
    248 		 * devAttrQry the source attribute, process if node_type
    249 		 * is initiator
    250 		 */
    251 		switch (tlv->attr_id) {
    252 			case ISNS_ISCSI_NAME_ATTR_ID:
    253 				if (got_dest == 0) {
    254 					bcopy(tlv->attr_value, dest,
    255 					    tlv->attr_len);
    256 					queue_prt(mgmtq, Q_ISNS_DBG,
    257 					    "PROCESS_SCN dest %s\n", dest);
    258 					got_dest = 1;
    259 				} else {
    260 					bcopy(tlv->attr_value, source,
    261 					    tlv->attr_len);
    262 					queue_prt(mgmtq, Q_ISNS_DBG,
    263 					    "PROCESS_SCN source %s\n", source);
    264 					got_source = 1;
    265 				}
    266 				break;
    267 			case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
    268 				bcopy(tlv->attr_value, &bitmap, tlv->attr_len);
    269 				bitmap = ntohl(bitmap);
    270 				queue_prt(mgmtq, Q_ISNS_DBG,
    271 				    "PROCESS_SCN bitmap %u\n", bitmap);
    272 				got_bitmap = 1;
    273 				break;
    274 			default:
    275 				queue_prt(mgmtq, Q_ISNS_DBG,
    276 				    "PROCESS_SCN DEFAULT\n");
    277 				break;
    278 		}
    279 
    280 		if (got_source && !got_bitmap) {
    281 			queue_prt(mgmtq, Q_ISNS_DBG,
    282 			    "process_scn: message out-of-order\n");
    283 			return;
    284 		}
    285 
    286 		if (got_source && got_bitmap) {
    287 			switch (bitmap) {
    288 				case ISNS_OBJ_ADDED:
    289 				case ISNS_OBJ_UPDATED:
    290 					queue_prt(mgmtq, Q_ISNS_DBG,
    291 					    "PROCESS_SCN OBJ ADDED");
    292 					(void) isns_update();
    293 					break;
    294 				case ISNS_OBJ_REMOVED:
    295 					queue_prt(mgmtq, Q_ISNS_DBG,
    296 					    "PROCESS_SCN OBJ REMOVED");
    297 					/* logout target */
    298 					if (got_dest == 0) {
    299 						syslog(LOG_ALERT,
    300 						    "ISNS protocol error\n");
    301 						continue;
    302 					}
    303 					logout_targ(dest);
    304 					break;
    305 				default:
    306 					break;
    307 			}
    308 
    309 			/* clear got_xxx */
    310 			got_source = 0;
    311 			got_bitmap = 1;
    312 		}
    313 
    314 		/* next attribute */
    315 		cnt += ISNS_ATTR_SZ(tlv->attr_len);
    316 		ptr += ISNS_ATTR_SZ(tlv->attr_len);
    317 	}
    318 	queue_prt(mgmtq, Q_ISNS_DBG, "DONE PROCESS_SCN\n");
    319 }
    320 
    321 /*
    322  * Process ESI requires a success response only
    323  */
    324 static void
    325 process_esi(int so, isns_pdu_t *esi)
    326 {
    327 	isns_rsp_t	*cmd;
    328 	int		pl_len;
    329 
    330 	if (isns_create_pdu(ISNS_ESI_RSP, 0, (isns_pdu_t **)&cmd) != 0) {
    331 		return;
    332 	}
    333 
    334 	pl_len = esi->payload_len + ISNS_STATUS_SZ;
    335 	if (pl_len > MAX_PDU_PAYLOAD_SZ) {
    336 		syslog(LOG_ALERT, "process_esi: payload size exceeded");
    337 		isns_free_pdu(cmd);
    338 		return;
    339 	}
    340 
    341 	/* change the xid to the request xid */
    342 	cmd->xid = htons(esi->xid);
    343 	cmd->status = htonl(ISNS_RSP_SUCCESSFUL);
    344 
    345 	/* copy original data */
    346 	bcopy(esi->payload, cmd->data, esi->payload_len);
    347 	cmd->pdu_len = htons(pl_len);
    348 
    349 	if (isns_send(so, (isns_pdu_t *)cmd) < 0) {
    350 		syslog(LOG_ALERT, "process_esi failed to isns_send");
    351 	}
    352 
    353 	isns_free_pdu(cmd);
    354 }
    355 
    356 static int
    357 is_isns_server_up(char *server) {
    358 	int			so;
    359 	socklen_t		len;
    360 	struct sockaddr		sa;
    361 
    362 	/* no server specified */
    363 	if (server == NULL) {
    364 		return (-1);
    365 	}
    366 	/*
    367 	 * open isns server connect and determine which PF_INET to use
    368 	 */
    369 	if ((so = isns_open(server)) < 0) {
    370 		syslog(LOG_ERR,
    371 		    "isns server %s not found",
    372 			server);
    373 		return (-1);
    374 	}
    375 	len = sizeof (sa);
    376 	if (getsockname(so, &sa, &len) < 0) {
    377 		isns_close(so);
    378 		syslog(LOG_ALERT,
    379 			"isns getsockname failed");
    380 		return (-1);
    381 	}
    382 	isns_close(so);
    383 
    384 	if (sa.sa_family != PF_INET &&
    385 		sa.sa_family != PF_INET6) {
    386 		syslog(LOG_ERR,
    387 			"isns unknown domain type");
    388 		return (-1);
    389 	}
    390 	return (0);
    391 }
    392 
    393 /*
    394  * This thread sit's in a loop and ensures that it keeps checking for
    395  * connection to isns_server. Once the connection works it registers
    396  * with the isns and bails out.
    397  * We expect the isns server to be fault taulerant and has persistence
    398  * for the registered entries.
    399  */
    400 static void *
    401 isns_server_connection_thr(void *arg)
    402 {
    403 	Boolean_t registered_targets = False;
    404 	char server[MAXHOSTNAMELEN + 1] = {0};
    405 
    406 	while (isns_shutdown == False &&
    407 	    connection_thr_bail_out == False) {
    408 		/* current server */
    409 		(void) strcpy(server, isns_args.server);
    410 
    411 		if (is_isns_server_up(server) == 0) {
    412 			if (registered_targets == False) {
    413 				/*
    414 				 * register all targets, what happens if
    415 				 * no targets are created yet? this should
    416 				 * not be a failure, when new target gets
    417 				 * created, update gets call. what if SCN
    418 				 * register fails?
    419 				 */
    420 				if (isns_reg_all() == 0) {
    421 					/* scn register all targets */
    422 					if (isns_op_all(ISNS_SCN_REG) != 0) {
    423 						syslog(LOG_ERR,
    424 						    "SCN registrations"
    425 						    " failed\n");
    426 						(void) isns_op_all(
    427 						    ISNS_DEV_DEREG);
    428 						registered_targets = False;
    429 					} else {
    430 						registered_targets = True;
    431 						break;
    432 					}
    433 				}
    434 			}
    435 		} else {
    436 			syslog(LOG_INFO,
    437 			    "isns server %s is not reachable",
    438 			    server);
    439 			registered_targets = False;
    440 		}
    441 		(void) sleep(ISNS_SLEEP_SECS);
    442 		/* If isns was disabled, deregister and close the thread */
    443 		if (isns_enabled() == False) {
    444 			syslog(LOG_INFO,
    445 			    "isns server is disabled, dergister target");
    446 			isns_fini();
    447 			break;
    448 		}
    449 
    450 	}
    451 	queue_message_set(mgmtq, 0, msg_pthread_join,
    452 	    (void *)(uintptr_t)pthread_self());
    453 
    454 	return (NULL);
    455 }
    456 
    457 /*
    458  * esi_scn_thr() is the thread creates an end point to receive and process
    459  * ESI & SCN messages.  This thread is created when isns_access is enabled
    460  * and for the duration of the iscsi daemon
    461  */
    462 static void *
    463 esi_scn_thr(void *arg)
    464 {
    465 	struct sockaddr		sa, *ai;
    466 	struct sockaddr_in	sin;
    467 	struct sockaddr_in6	sin6;
    468 	int			so, fd, pf;
    469 	socklen_t		len;
    470 	char			strport[NI_MAXSERV];
    471 	isns_pdu_t		*scn = NULL;
    472 	struct timeval timeout;
    473 	fd_set fdset;
    474 	int socket_ready = 0;
    475 
    476 	pf = get_addr_family(isns_args.entity);
    477 	if (pf == PF_INET) {
    478 		bzero(&sin, sizeof (sin));
    479 		sin.sin_family = PF_INET;
    480 		sin.sin_port = htons(0);
    481 		sin.sin_addr.s_addr = INADDR_ANY;
    482 		ai = (struct sockaddr *)&sin;
    483 		len = sizeof (sin);
    484 	} else if (pf == PF_INET6) {
    485 		bzero(&sin6, sizeof (sin6));
    486 		sin6.sin6_family = PF_INET6;
    487 		sin6.sin6_port = htons(0);
    488 		sin6.sin6_addr = in6addr_any;
    489 		ai = (struct sockaddr *)&sin6;
    490 		len = sizeof (sin6);
    491 	} else {
    492 		syslog(LOG_ERR, "Bad address family. Exit esi_scn_thr");
    493 		return (NULL);
    494 	}
    495 
    496 	/*
    497 	 * create and bind SCN socket
    498 	 * save the scn port info
    499 	 */
    500 	if ((so = socket(pf, SOCK_STREAM, 0)) == -1) {
    501 		syslog(LOG_ALERT, "create isns socket failed");
    502 		return (NULL);
    503 	}
    504 
    505 	(void) setsockopt(so, SOL_SOCKET, SO_REUSEADDR, 0, 0);
    506 
    507 	if (bind(so, ai, len) < 0) {
    508 		syslog(LOG_ALERT, "esi_scn_thr: bind failed");
    509 		(void) close(so);
    510 		return (NULL);
    511 	}
    512 
    513 	/* get scn port info */
    514 	len = sizeof (sa);
    515 	if (getsockname(so, &sa, &len) < 0) {
    516 		syslog(LOG_ALERT, "isns getsockname failed");
    517 		(void) close(so);
    518 		return (NULL);
    519 	}
    520 	if (getnameinfo(&sa, len, NULL, 0, strport, NI_MAXSERV,
    521 	    NI_NUMERICSERV) != 0) {
    522 		syslog(LOG_ALERT, "isns getnameinfo failed");
    523 		(void) close(so);
    524 		return (NULL);
    525 	}
    526 	scn_port = atoi(strport);
    527 
    528 
    529 	if (listen(so, 5) < 0) {
    530 		syslog(LOG_ALERT, "esi_scn_thr: failed listen");
    531 		(void) close(so);
    532 		return (NULL);
    533 	}
    534 
    535 	/* listen for esi or scn messages */
    536 	while (isns_shutdown == False) {
    537 		/* ISNS_ESI_INTERVAL_ATTR_ID is set to 10s */
    538 		timeout.tv_sec = 10;
    539 		timeout.tv_usec = 0;
    540 		FD_ZERO(&fdset);
    541 		FD_SET(so, &fdset);
    542 
    543 		socket_ready = select(so + 1, &fdset, NULL, NULL, &timeout);
    544 
    545 		/* If disabled bail out, dont care about packets */
    546 		if (isns_enabled() == False) {
    547 			syslog(LOG_INFO,
    548 			    "isns server is disabled, dergister target");
    549 			isns_fini();
    550 			(void) close(so);
    551 			return (NULL);
    552 		}
    553 
    554 		if (socket_ready < 0) {
    555 			syslog(LOG_ERR,
    556 			    "esi_scn_thr: select failed, retrying.");
    557 			continue;
    558 		} else if (socket_ready == 0) { /* timeout */
    559 			continue;
    560 		} else {
    561 			/* Socket is ready */
    562 			if ((fd = accept(so, &sa, &len)) < 0) {
    563 				syslog(LOG_ALERT, "esi_scn_thr: failed accept");
    564 				continue;
    565 			}
    566 		}
    567 		if (isns_recv(fd, (isns_rsp_t **)&scn) == 0) {
    568 			/* Just return success for ESI */
    569 			switch (scn->func_id) {
    570 				case ISNS_ESI:
    571 					process_esi(fd, scn);
    572 					break;
    573 				case ISNS_SCN:
    574 					/* call the SCN process function */
    575 					process_scn(fd, scn);
    576 					break;
    577 				default:
    578 					syslog(LOG_ERR,
    579 					    "esi_scn_thr: Invalid funcid %d\n",
    580 					    scn->func_id);
    581 					break;
    582 			}
    583 			/* free response resource */
    584 			isns_free_pdu(scn);
    585 		} else {
    586 			syslog(LOG_ALERT, "esi_scn_thr fails isns_recv ");
    587 		}
    588 
    589 		(void) close(fd);
    590 	}
    591 	(void) close(so);
    592 	return (NULL);
    593 }
    594 
    595 /*
    596  * Perform operation on all targets
    597  */
    598 static int
    599 isns_op_all(uint16_t op)
    600 {
    601 	int		so;
    602 	tgt_node_t	*tgt = NULL;
    603 	char		*iname;
    604 
    605 	if (isns_server_connection_thr_running == False) {
    606 		syslog(LOG_ERR,
    607 		    "isns_op_all: iSNS discovery is not running."
    608 		    " Check the previous iSNS initialization error.");
    609 		return (-1);
    610 	}
    611 
    612 	if ((so = isns_open(isns_args.server)) == -1) {
    613 		syslog(LOG_ERR, "isns_op_all: failed to open isns server %s",
    614 		    isns_args.server);
    615 		return (-1);
    616 	}
    617 
    618 	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    619 	    tgt)) != NULL) {
    620 		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &iname)
    621 		    == FALSE) {
    622 			continue;
    623 		}
    624 
    625 		switch (op) {
    626 			case ISNS_DEV_DEREG:
    627 				if (isns_dev_attr_dereg(so, iname) == -1) {
    628 					syslog(LOG_ERR,
    629 					    "ISNS de-register failed\n");
    630 				}
    631 				num_reg = 0;
    632 				break;
    633 			case ISNS_SCN_DEREG:
    634 				if (isns_scn_dereg(so, iname) == -1) {
    635 					syslog(LOG_ERR,
    636 					    "ISNS SCN de-register failed\n");
    637 				}
    638 				break;
    639 			case ISNS_SCN_REG:
    640 				if (isns_scn_reg(so, iname) == -1) {
    641 					syslog(LOG_ERR,
    642 					    "ISNS SCN register failed\n");
    643 				}
    644 				break;
    645 			case ISNS_TGT_LOGOUT:
    646 				logout_targ(iname);
    647 				break;
    648 			default:
    649 				break;
    650 		}
    651 
    652 		free(iname);
    653 	}
    654 	isns_close(so);
    655 	return (0);
    656 }
    657 
    658 static int
    659 isns_populate_and_update_server_info(Boolean_t update) {
    660 	char		*isns_srv, *isns_port;
    661 	int retcode = 0;
    662 
    663 	/* get isns server info */
    664 	(void) tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV,
    665 	    &isns_srv);
    666 	if (isns_srv == NULL) {
    667 		syslog(LOG_INFO,
    668 		    "The server has not been setup, "
    669 		    "but enabling the isns access");
    670 		retcode = -1;
    671 		return (retcode);
    672 	}
    673 	isns_port = strchr(isns_srv, ':');
    674 	if (isns_port == NULL) {
    675 		isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT;
    676 	} else {
    677 		isns_args.isns_port = strtoul(isns_port + 1, NULL, 0);
    678 		if (isns_args.isns_port == 0) {
    679 			isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT;
    680 		}
    681 		*isns_port = '\0';
    682 	}
    683 
    684 	if (update == True) {
    685 		/* isns_server changed */
    686 		if (strcmp(isns_srv, isns_args.server) != 0) {
    687 			/* de-reg from old iSNS server if it is setup */
    688 			syslog(LOG_INFO,
    689 			    "Detected a new isns server, deregistering"
    690 			    " %s", isns_args.server);
    691 			(void) isns_dereg_all();
    692 			(void) strcpy(isns_args.server, isns_srv);
    693 			/* Register with the new server */
    694 			if (isns_reg_all() == 0) {
    695 				/* scn register all targets */
    696 				if (isns_op_all(ISNS_SCN_REG) != 0) {
    697 					syslog(LOG_ERR,
    698 					    "SCN registrations failed\n");
    699 					(void) isns_op_all(ISNS_DEV_DEREG);
    700 					retcode = -1;
    701 				}
    702 			}
    703 		}
    704 	} else {
    705 		(void) strcpy(isns_args.server, isns_srv);
    706 	}
    707 	free(isns_srv);
    708 	return (retcode);
    709 }
    710 
    711 /*
    712  * isns_init() needs to be call before all ISNS operations.
    713  * Save the isns_server & entity name.
    714  * Start esi_scn_thr to receive ESI & SCN messages
    715  */
    716 int
    717 isns_init(target_queue_t *q)
    718 {
    719 	if (q != NULL)
    720 		mgmtq = q;
    721 
    722 	if (isns_enabled() == False)
    723 		return (0);
    724 
    725 	/* get local hostname for entity usage */
    726 	if ((gethostname(isns_args.entity, MAXHOSTNAMELEN) < 0) ||
    727 	    (get_ip_addr(isns_args.entity, &eid_ip) < 0)) {
    728 		syslog(LOG_ERR, "isns_init: failed to get host name or host ip"
    729 		    " address for ENTITY properties");
    730 		return (-1);
    731 	}
    732 
    733 	isns_shutdown = False;
    734 
    735 	(void) isns_populate_and_update_server_info(False);
    736 	if (pthread_create(&scn_tid, NULL,
    737 	    esi_scn_thr, (void *)&isns_args) !=
    738 	    0) {
    739 		syslog(LOG_ALERT, "isns_init failed to pthread_create");
    740 		(void) pthread_kill(isns_tid, SIGKILL);
    741 		return (-1);
    742 	}
    743 
    744 	if (pthread_create(&isns_tid, NULL, isns_server_connection_thr,
    745 	    (void *)NULL) != 0) {
    746 		syslog(LOG_ALERT,
    747 		    "isns_init failed to create the "
    748 		    "isns connection thr");
    749 		return (-1);
    750 	}
    751 
    752 	isns_server_connection_thr_running = True;
    753 	return (0);
    754 }
    755 
    756 /*
    757  * isns_update gets call on modify_admin, this is changes to
    758  * isns access and/or isns server
    759  */
    760 int
    761 isns_update()
    762 {
    763 	Boolean_t is_isns_enabled = isns_enabled();
    764 	/*
    765 	 * If the isns thread was not started before and we are going
    766 	 * enabled from disabled start the threads.
    767 	 */
    768 	if (isns_server_connection_thr_running == False) {
    769 		if (is_isns_enabled == True) {
    770 			if (isns_init(NULL) != 0) {
    771 				return (-1);
    772 			} else {
    773 				return (0);
    774 			}
    775 		} else {
    776 			syslog(LOG_INFO,
    777 			    "isns_update: isns is disabled");
    778 		}
    779 	} else {
    780 		/*
    781 		 * isns is disabled after enabled,
    782 		 * log off all targets and fini isns service
    783 		 */
    784 		if (is_isns_enabled == False) {
    785 			isns_shutdown = True;
    786 			/* pthread_join for the isns thread */
    787 			(void) pthread_join(isns_tid, NULL);
    788 			(void) pthread_join(scn_tid, NULL);
    789 			isns_server_connection_thr_running = False;
    790 		} else {
    791 			/*
    792 			 * Incase the original thread is still running
    793 			 * we should reap it
    794 			 */
    795 			connection_thr_bail_out = True;
    796 			(void) pthread_join(isns_tid, NULL);
    797 			connection_thr_bail_out = False;
    798 
    799 			/*
    800 			 * Read the configuration file incase the server
    801 			 * has changed.
    802 			 */
    803 			if (isns_populate_and_update_server_info(True) == -1) {
    804 				return (-1);
    805 			}
    806 		}
    807 	}
    808 	return (0);
    809 }
    810 
    811 /*
    812  * isns_fini is called when isns access is disabled
    813  */
    814 void
    815 isns_fini()
    816 {
    817 	/*
    818 	 * de-register all targets 1st, this prevents initiator from
    819 	 * logging back in
    820 	 */
    821 	(void) isns_op_all(ISNS_SCN_DEREG);
    822 	(void) isns_op_all(ISNS_DEV_DEREG);
    823 
    824 	/* log off all targets */
    825 	(void) isns_op_all(ISNS_TGT_LOGOUT);
    826 }
    827 
    828 static int
    829 get_addr_family(char *node) {
    830 	struct addrinfo		*ai = NULL;
    831 	int ret;
    832 
    833 	if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) {
    834 		syslog(LOG_ALERT, "get_addr_family: server %s not found : %s",
    835 		    node, gai_strerror(ret));
    836 		return (-1);
    837 	}
    838 	ret = ai->ai_family;
    839 	freeaddrinfo(ai);
    840 	return (ret);
    841 }
    842 
    843 static int
    844 get_ip_addr(char *node, ip_t *sa)
    845 {
    846 	struct addrinfo		*ai = NULL, *aip;
    847 	struct sockaddr_in	*sin;
    848 	struct sockaddr_in6	*sin6;
    849 	int	ret;
    850 
    851 	if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) {
    852 		syslog(LOG_ALERT, "get_ip_addr: %s not found : %s",
    853 		    node, gai_strerror(ret));
    854 		return (-1);
    855 	}
    856 
    857 	bzero(sa, sizeof (ip_t));
    858 	aip = ai;
    859 	do {
    860 		sa->ai_addrlen = aip->ai_addrlen;
    861 		sa->pf_family = aip->ai_family;
    862 		switch (aip->ai_family) {
    863 			case PF_INET:
    864 				/* LINTED */
    865 				sin = (struct sockaddr_in *)aip->ai_addr;
    866 				sa->ip_len = sizeof (in_addr_t);
    867 				bcopy(&sin->sin_addr, (void *)&sa->ip_adr.in,
    868 				    sa->ip_len);
    869 				freeaddrinfo(ai);
    870 				return (0);
    871 			case PF_INET6:
    872 				/* LINTED */
    873 				sin6 = (struct sockaddr_in6 *)aip->ai_addr;
    874 				sa->ip_len = sizeof (in6_addr_t);
    875 				bcopy(&sin6->sin6_addr, &sa->ip_adr.in6,
    876 				    sa->ip_len);
    877 				freeaddrinfo(ai);
    878 				return (0);
    879 			default:
    880 				continue;
    881 		}
    882 	} while ((aip = aip->ai_next) != NULL);
    883 
    884 	freeaddrinfo(ai);
    885 	return (-1);
    886 }
    887 
    888 /*
    889  * Process isns response, need to verify same transaction id, func_id
    890  * as the isns command, the isns command is in network byte order,
    891  * the isns response is in host byte order
    892  */
    893 static int
    894 process_rsp(isns_pdu_t *cmd, isns_rsp_t *rsp)
    895 {
    896 	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_RSP");
    897 	/*
    898 	 * Process responses:
    899 	 *	-verify sucessful response
    900 	 *	-verify match xid
    901 	 *	-process operating attributes
    902 	 * For DevAttrReg & DevAttrQry and most isns command,
    903 	 * the response func_id is  command_func_id | 0x8000.
    904 	 */
    905 	rsp->status = ntohl(rsp->status);
    906 	if (rsp->status != ISNS_RSP_SUCCESSFUL ||
    907 	    rsp->xid != ntohs(cmd->xid) ||
    908 	    rsp->func_id != (ntohs(cmd->func_id) | 0x8000)) {
    909 		queue_prt(mgmtq, Q_ISNS_DBG,
    910 		    "cmd failed with: status= %d xid= %d %d "\
    911 		    "response attribute %x\n", rsp->status, rsp->xid,\
    912 		    ntohs(cmd->xid), rsp->func_id);
    913 		return (-1);
    914 	}
    915 
    916 	return (0);
    917 }
    918 
    919 /*
    920  * DevAttrDereg
    921  */
    922 static int
    923 isns_dev_attr_dereg(int so, char *node)
    924 {
    925 	isns_pdu_t	*cmd = NULL;
    926 	isns_rsp_t	*rsp = NULL;
    927 	uint32_t	flags = 0;
    928 	int		ret = -1;
    929 
    930 	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_DEREG");
    931 
    932 	if (isns_create_pdu(ISNS_DEV_DEREG, flags, &cmd) != 0) {
    933 		return (-1);
    934 	}
    935 
    936 	/* add source attribute */
    937 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
    938 	    STRLEN(node), node, 0) != 0) {
    939 		goto error;
    940 	}
    941 
    942 	/* add delimiter */
    943 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
    944 		goto error;
    945 	}
    946 
    947 	/* add operation attributes */
    948 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
    949 	    STRLEN(node), node, 0) != 0) {
    950 		goto error;
    951 	}
    952 
    953 	/* send pdu */
    954 	if (isns_send(so, cmd) == -1) {
    955 		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_send");
    956 		goto error;
    957 	}
    958 
    959 	/* get isns response */
    960 	if (isns_recv(so, &rsp) == -1) {
    961 		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_recv ");
    962 		goto error;
    963 	}
    964 
    965 	/* process response */
    966 	if (process_rsp(cmd, rsp) == 0) {
    967 		/*
    968 		 * Keep the num_reg to a non-negative number.
    969 		 * num_reg is used to keep track of whether there was
    970 		 * any registration occurred or not. Deregstration should
    971 		 * be followed by registration but in case dereg occurs
    972 		 * and somehow it is succeeded keeping num_reg to 0 prevent
    973 		 * any negative effect on subsequent registration.
    974 		 */
    975 		if (num_reg > 0) num_reg--;
    976 		ret = 0;
    977 	}
    978 
    979 error:
    980 	/* Free all resouces here */
    981 	if (cmd)
    982 		isns_free_pdu(cmd);
    983 	if (rsp)
    984 		isns_free_pdu(rsp);
    985 	return (ret);
    986 }
    987 
    988 /*
    989  * Register a new node, need to find another node that is already registered
    990  * DevAttrReg
    991  * RFC 4171 Section 5.6.5.5 indicated SCN-port-tag (23) needed to be
    992  * included in the registration
    993  * Also need to register ESI-port-tag (20) see Section 6.3.5
    994  */
    995 static int
    996 isns_dev_attr_reg(int so, tgt_node_t *tgt, char *node, char *alias)
    997 {
    998 	isns_pdu_t	*cmd = NULL;
    999 	isns_rsp_t	*rsp = NULL;
   1000 	uint32_t	flags = 0;
   1001 	int		ret = 0;
   1002 	Boolean_t	found = False;
   1003 	tgt_node_t	*src = NULL;
   1004 	char		*src_nm = NULL;
   1005 
   1006 	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_REG");
   1007 
   1008 	if ((so = isns_open(isns_args.server)) == -1) {
   1009 		return (-1);
   1010 	}
   1011 
   1012 	if (num_reg == 0) {
   1013 		flags |= ISNS_FLAG_REPLACE_REG;
   1014 	}
   1015 
   1016 	if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) {
   1017 		return (-1);
   1018 	}
   1019 
   1020 	if (num_reg == 0) {
   1021 		/* add new node to source attribute */
   1022 		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1023 		    STRLEN(node), node, 0) != 0) {
   1024 			goto error;
   1025 		}
   1026 	} else {
   1027 		/* find a registered node to use */
   1028 		do {
   1029 			src = find_next_tgt(src, &src_nm);
   1030 			if (src == NULL) {
   1031 				syslog(LOG_ALERT, "ISNS out of sync\n");
   1032 				goto error;
   1033 			}
   1034 			if (tgt == src) {
   1035 				free(src_nm);
   1036 				src_nm = NULL;
   1037 				continue;
   1038 			} else {
   1039 				found = True;
   1040 			}
   1041 		} while (found == False);
   1042 
   1043 		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1044 		    STRLEN(src_nm), src_nm, 0) != 0) {
   1045 			goto error;
   1046 		}
   1047 	}
   1048 
   1049 	/* add message key attribute */
   1050 	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
   1051 	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
   1052 		goto error;
   1053 	}
   1054 
   1055 	/* add delimiter */
   1056 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
   1057 		goto error;
   1058 	}
   1059 
   1060 	/* add operation attributes */
   1061 
   1062 	/* entity id */
   1063 	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
   1064 	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
   1065 		goto error;
   1066 	}
   1067 
   1068 	/* entity type */
   1069 	if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID,
   1070 	    ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
   1071 		goto error;
   1072 	}
   1073 
   1074 	/*
   1075 	 * Register entity portal properties the 1st time
   1076 	 */
   1077 	if (num_reg == 0) {
   1078 		/* portal ip-addr */
   1079 		if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID,
   1080 		    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
   1081 		    eid_ip.ip_len) != 0) {
   1082 			goto error;
   1083 		}
   1084 
   1085 		/* portal port */
   1086 		if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID,
   1087 		    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
   1088 			goto error;
   1089 		}
   1090 
   1091 		/* ESI interval */
   1092 		if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID,
   1093 		    ISNS_ESI_TICK_SZ, NULL, 10) != 0) {
   1094 			goto error;
   1095 		}
   1096 
   1097 		/* scn port */
   1098 		if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID,
   1099 		    ISNS_PORT_SZ, NULL, scn_port) != 0) {
   1100 			goto error;
   1101 		}
   1102 
   1103 		/* esi port */
   1104 		if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID,
   1105 		    ISNS_PORT_SZ, NULL, scn_port) != 0) {
   1106 			goto error;
   1107 		}
   1108 	}
   1109 
   1110 	/* iscsi node name */
   1111 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1112 	    STRLEN(node), node, 0) != 0) {
   1113 		goto error;
   1114 	}
   1115 
   1116 	/* iscsi node type */
   1117 	if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
   1118 	    ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE) != 0) {
   1119 		goto error;
   1120 	}
   1121 
   1122 	/* iscsi node alias */
   1123 	if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
   1124 	    STRLEN(alias), alias, 0) != 0) {
   1125 		goto error;
   1126 	}
   1127 
   1128 	/* PGT */
   1129 	if (append_tpgt(tgt, cmd) != 0) {
   1130 		goto error;
   1131 	}
   1132 
   1133 	/* send pdu */
   1134 	if (isns_send(so, cmd) == -1) {
   1135 		goto error;
   1136 	}
   1137 
   1138 	/* get isns response */
   1139 	if (isns_recv(so, &rsp) == -1) {
   1140 		goto error;
   1141 	}
   1142 
   1143 	/* process response */
   1144 	if ((ret = process_rsp(cmd, rsp)) == 0) {
   1145 		num_reg++;
   1146 	}
   1147 
   1148 error:
   1149 	/* Free all resouces here */
   1150 	if (cmd)
   1151 		isns_free_pdu(cmd);
   1152 	if (rsp)
   1153 		isns_free_pdu(rsp);
   1154 	if (src_nm)
   1155 		free(src_nm);
   1156 	return (ret);
   1157 }
   1158 
   1159 /*
   1160  * DevAttrQry for iscsi initiator
   1161  * See RFC 4171 Sect. 5.6.5.2 for query detail
   1162  */
   1163 static int
   1164 isns_dev_attr_qry(int so, char *target, char *initiator)
   1165 {
   1166 	isns_pdu_t	*cmd;
   1167 	isns_rsp_t	*rsp;
   1168 	uint32_t	flags = 0;
   1169 	int		ret = -1;
   1170 	size_t		remain;
   1171 	isns_tlv_t	*tlv;
   1172 	uint8_t		*ptr;
   1173 
   1174 	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_QRY");
   1175 
   1176 	if (isns_create_pdu(ISNS_DEV_ATTR_QRY, flags, &cmd) != 0) {
   1177 		return (-1);
   1178 	}
   1179 
   1180 	/* source attribute */
   1181 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1182 	    STRLEN(target), target, 0) == -1) {
   1183 		goto error;
   1184 	}
   1185 
   1186 	/* message key attribute */
   1187 	/* iscsi initiator node type */
   1188 	if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
   1189 	    ISNS_NODE_TYP_SZ, NULL, ISNS_INITIATOR_NODE_TYPE) == -1) {
   1190 		goto error;
   1191 	}
   1192 
   1193 	/* delimiter */
   1194 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
   1195 		goto error;
   1196 	}
   1197 
   1198 	/*
   1199 	 * operating attributes
   1200 	 * Query Iscsi initiator with zero length TLV operating
   1201 	 * attribute
   1202 	 */
   1203 
   1204 	/* iscsi name */
   1205 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1206 	    0, NULL, 0) != 0) {
   1207 		goto error;
   1208 	}
   1209 
   1210 	if (isns_send(so, cmd) == -1) {
   1211 		syslog(LOG_ERR, "isns_dev_attr_qry fails isns_send");
   1212 		goto error;
   1213 	}
   1214 
   1215 	/* recv response */
   1216 	if (isns_recv(so, &rsp) == -1) {
   1217 		syslog(LOG_ERR, "isns_dev_attr_qry fails isns_recv ");
   1218 		goto error;
   1219 	}
   1220 
   1221 	/* process response */
   1222 	if ((ret = process_rsp(cmd, rsp)) == 0) {
   1223 		/* compare initiator name to the response, success if found */
   1224 		/* subtract out status word */
   1225 		remain = rsp->pdu_len - ISNS_STATUS_SZ;
   1226 		ptr = rsp->data;
   1227 
   1228 		while (remain > 0) {
   1229 			/* LINTED */
   1230 			tlv = (isns_tlv_t *)ptr;
   1231 
   1232 			/* debug only */
   1233 			print_ntoh_tlv(tlv);
   1234 
   1235 			/* process tag-len-value */
   1236 			ntoh_tlv(tlv);
   1237 			/*
   1238 			 * let's process the data, only interested
   1239 			 * in iscsi name, skip everything else for
   1240 			 * now.
   1241 			 */
   1242 			if (tlv->attr_id == ISNS_ISCSI_NAME_ATTR_ID) {
   1243 				if (strncmp((char *)tlv->attr_value, initiator,
   1244 				    tlv->attr_len) == 0) {
   1245 					break;
   1246 				}
   1247 			}
   1248 			/* next tlv */
   1249 			remain -= ISNS_ATTR_SZ(tlv->attr_len);
   1250 			ptr += ISNS_ATTR_SZ(tlv->attr_len);
   1251 		}
   1252 		ret = (remain > 0) ? 1 : 0;
   1253 	}
   1254 
   1255 error:
   1256 	if (cmd)
   1257 		isns_free_pdu(cmd);
   1258 	if (rsp)
   1259 		isns_free_pdu(rsp);
   1260 	return (ret);
   1261 }
   1262 
   1263 /*
   1264  * SCNReg
   1265  * See RFC 4171 Section 5.6.5.5
   1266  */
   1267 static int
   1268 isns_scn_reg(int so, char *node)
   1269 {
   1270 	isns_pdu_t	*cmd;
   1271 	isns_rsp_t	*rsp;
   1272 	uint32_t	flags = 0;
   1273 	uint32_t	bitmap = 0;
   1274 	int		ret = -1;
   1275 
   1276 	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_REG");
   1277 
   1278 	if (isns_create_pdu(ISNS_SCN_REG, flags, &cmd) != 0) {
   1279 		return (-1);
   1280 	}
   1281 
   1282 	/* source attribute */
   1283 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1284 	    STRLEN(node), node, 0) == -1) {
   1285 		goto error;
   1286 	}
   1287 
   1288 	/* message key attribute */
   1289 	/* iscsi initiator node name */
   1290 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1291 	    STRLEN(node), node, 0) != 0) {
   1292 		goto error;
   1293 	}
   1294 
   1295 	/* delimiter */
   1296 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
   1297 		goto error;
   1298 	}
   1299 
   1300 	/* SCN bitmap */
   1301 	bitmap = ISNS_INIT_SELF_INFO_ONLY | ISNS_OBJ_REMOVED |
   1302 	    ISNS_OBJ_ADDED | ISNS_OBJ_UPDATED;
   1303 	if (isns_append_attr(cmd, ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
   1304 	    ISNS_SCN_BITMAP_SZ, NULL, bitmap) == -1) {
   1305 		goto error;
   1306 	}
   1307 
   1308 	if (isns_send(so, cmd) == -1) {
   1309 		syslog(LOG_ERR, "isns_scn_reg fails isns_send");
   1310 		goto error;
   1311 	}
   1312 
   1313 	if (isns_recv(so, &rsp) == -1) {
   1314 		syslog(LOG_ERR, "isns_scn_reg fails isns_recv ");
   1315 		goto error;
   1316 	}
   1317 
   1318 	/* process response */
   1319 	if (process_rsp(cmd, rsp) == 0) {
   1320 		ret = 0;
   1321 	}
   1322 
   1323 error:
   1324 	if (cmd)
   1325 		isns_free_pdu(cmd);
   1326 	if (rsp)
   1327 		isns_free_pdu(rsp);
   1328 	return (ret);
   1329 }
   1330 
   1331 
   1332 /*
   1333  * SCNDereg
   1334  */
   1335 static int
   1336 isns_scn_dereg(int so, char *node)
   1337 {
   1338 	isns_pdu_t	*cmd = NULL;
   1339 	isns_rsp_t	*rsp = NULL;
   1340 	uint32_t	flags = 0;
   1341 	int		ret = -1;
   1342 
   1343 	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_DEREG");
   1344 
   1345 	if (isns_create_pdu(ISNS_SCN_DEREG, flags, &cmd) != 0) {
   1346 		return (-1);
   1347 	}
   1348 
   1349 	/* source attribute */
   1350 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1351 	    STRLEN(node), node, 0) == -1) {
   1352 		goto error;
   1353 	}
   1354 
   1355 	/* message key attribute */
   1356 	/* iscsi initiator node name */
   1357 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1358 	    STRLEN(node), node, 0) != 0) {
   1359 		goto error;
   1360 	}
   1361 
   1362 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) {
   1363 		goto error;
   1364 	}
   1365 
   1366 	if (isns_send(so, cmd) == -1) {
   1367 		syslog(LOG_ERR, "isns_scn_reg fails isns_send");
   1368 		goto error;
   1369 	}
   1370 
   1371 	if (isns_recv(so, &rsp) == -1) {
   1372 		syslog(LOG_ERR, "isns_scn_reg fails isns_recv ");
   1373 		goto error;
   1374 	}
   1375 
   1376 	/* process response */
   1377 	if (process_rsp(cmd, rsp) == 0) {
   1378 		ret = 0;
   1379 	}
   1380 
   1381 error:
   1382 	if (cmd)
   1383 		isns_free_pdu(cmd);
   1384 	if (rsp)
   1385 		isns_free_pdu(rsp);
   1386 	return (ret);
   1387 }
   1388 
   1389 /*
   1390  * isns_reg is called to register new target
   1391  */
   1392 int
   1393 isns_reg(char *targ)
   1394 {
   1395 	int		so;
   1396 	tgt_node_t	*tgt;
   1397 	char		*iqn = NULL;
   1398 
   1399 	if (isns_server_connection_thr_running == False) {
   1400 		syslog(LOG_ERR,
   1401 		    "isns_reg: iSNS discovery is not running."
   1402 		    " Check the previous iSNS initialization error.");
   1403 		return (-1);
   1404 	}
   1405 
   1406 	if ((so = isns_open(isns_args.server)) == -1) {
   1407 		syslog(LOG_ERR, "isns_reg failed with server: %s",
   1408 		    isns_args.server);
   1409 		return (-1);
   1410 	}
   1411 
   1412 	/*
   1413 	 * Open targets_config and devAttrReg all nodes
   1414 	 */
   1415 	if ((tgt = find_tgt_by_name(targ, &iqn)) != NULL) {
   1416 		if (isns_dev_attr_reg(so, tgt, iqn, tgt->x_value) != 0) {
   1417 			syslog(LOG_ALERT, "ISNS registration failed %s\n",
   1418 			    tgt->x_value);
   1419 			goto error;
   1420 		}
   1421 		if (isns_scn_reg(so, iqn) == -1) {
   1422 			syslog(LOG_ERR, "ISNS SCN register failed\n");
   1423 		}
   1424 	}
   1425 
   1426 error:
   1427 	if (iqn)
   1428 		free(iqn);
   1429 	isns_close(so);
   1430 	return (0);
   1431 }
   1432 
   1433 
   1434 /*
   1435  * Register all iscsi target nodes from the XML database
   1436  * Alway use the ISNS_FLAG_REPLACE_REG flag
   1437  */
   1438 int
   1439 isns_reg_all()
   1440 {
   1441 	int so;
   1442 	uint32_t	flags = ISNS_FLAG_REPLACE_REG;
   1443 	isns_pdu_t	*cmd = NULL;
   1444 	isns_rsp_t	*rsp = NULL;
   1445 	char		*n = NULL;
   1446 	char		*a = NULL;
   1447 	char		alias[MAXNAMELEN];
   1448 	char		iname[MAXNAMELEN];
   1449 	tgt_node_t	*tgt = NULL;
   1450 	int		ret = -1;
   1451 	int		tgt_cnt = 0;
   1452 
   1453 	if (isns_server_connection_thr_running == False) {
   1454 		syslog(LOG_ERR,
   1455 		    "isns_reg_all: iSNS discovery is not running."
   1456 		    " Check the previous iSNS initialization error.");
   1457 		return (-1);
   1458 	}
   1459 
   1460 	/*
   1461 	 * get the 1st target and use it for the source attribute
   1462 	 */
   1463 	if ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt))
   1464 	    == NULL) {
   1465 		return (0);
   1466 	}
   1467 	if (tgt->x_value == NULL) {
   1468 		syslog(LOG_ALERT, "ISNS: target with NULL local name\n");
   1469 		return (-1);
   1470 	}
   1471 	if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
   1472 	    == FALSE) {
   1473 		syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n");
   1474 		return (-1);
   1475 	}
   1476 	(void) strcpy(iname, n);
   1477 	free(n);
   1478 	if ((so = isns_open(isns_args.server)) == -1) {
   1479 		syslog(LOG_ALERT, "ISNS: fails to connect to %s\n",
   1480 		    isns_args.server);
   1481 		return (-1);
   1482 	}
   1483 
   1484 	if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) {
   1485 		goto error;
   1486 	}
   1487 
   1488 	/* source attribute */
   1489 	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1490 	    STRLEN(iname), iname, 0) != 0) {
   1491 		goto error;
   1492 	}
   1493 
   1494 	/* add message key attribute */
   1495 	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
   1496 	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
   1497 		goto error;
   1498 	}
   1499 
   1500 	/* add delimiter */
   1501 	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
   1502 		goto error;
   1503 	}
   1504 
   1505 	/* entity id */
   1506 	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
   1507 	    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
   1508 		goto error;
   1509 	}
   1510 
   1511 	/* entity type */
   1512 	if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID,
   1513 	    ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
   1514 		goto error;
   1515 	}
   1516 
   1517 	/* portal ip-addr */
   1518 	if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID,
   1519 	    eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr,
   1520 	    eid_ip.ip_len) != 0) {
   1521 		goto error;
   1522 	}
   1523 
   1524 	/* portal port */
   1525 	if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID,
   1526 	    ISNS_PORT_SZ, NULL, iscsi_port) != 0) {
   1527 		goto error;
   1528 	}
   1529 
   1530 	/* ESI interval */
   1531 	if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID,
   1532 	    ISNS_ESI_TICK_SZ, NULL, 10) != 0) {
   1533 		goto error;
   1534 	}
   1535 
   1536 
   1537 	/* scn port */
   1538 	if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID,
   1539 	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
   1540 		goto error;
   1541 	}
   1542 
   1543 	/* esi port */
   1544 	if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID,
   1545 	    ISNS_PORT_SZ, NULL, scn_port) != 0) {
   1546 		goto error;
   1547 	}
   1548 
   1549 	/*
   1550 	 * Open targets_config and devAttrReg all nodes
   1551 	 */
   1552 	tgt = NULL;
   1553 	while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
   1554 	    tgt)) != NULL) {
   1555 		if (tgt->x_value == NULL) {
   1556 			syslog(LOG_ALERT, "ISNS: target with NULL name\n");
   1557 			continue;
   1558 		}
   1559 		/* use this value as alias if alias is not set */
   1560 		(void) strcpy(alias, tgt->x_value);
   1561 
   1562 		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
   1563 		    == FALSE) {
   1564 			continue;
   1565 		}
   1566 		(void) strcpy(iname, n);
   1567 		free(n);
   1568 
   1569 		/* find alias */
   1570 		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a)
   1571 		    == TRUE) {
   1572 			(void) strcpy(alias, a);
   1573 			free(a);
   1574 		}
   1575 
   1576 		tgt_cnt++;		/* increment target count */
   1577 
   1578 		/* operation attributes */
   1579 		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1580 		    STRLEN(iname), iname, 0) != 0) {
   1581 			goto error;
   1582 		}
   1583 		if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
   1584 		    4, NULL, ISNS_TARGET_NODE_TYPE) != 0) {
   1585 			goto error;
   1586 		}
   1587 		if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
   1588 		    STRLEN(alias), alias, 0) != 0) {
   1589 			goto error;
   1590 		}
   1591 
   1592 		if (append_tpgt(tgt, cmd) != 0) {
   1593 			goto error;
   1594 		}
   1595 
   1596 	}
   1597 
   1598 	/* send pdu */
   1599 	if (isns_send(so, cmd) == -1) {
   1600 		goto error;
   1601 	}
   1602 
   1603 	/* get isns response */
   1604 	if (isns_recv(so, &rsp) == -1) {
   1605 		goto error;
   1606 	}
   1607 
   1608 	/* process response */
   1609 	if (process_rsp(cmd, rsp) == 0) {
   1610 		ret = 0;
   1611 		num_reg = tgt_cnt;
   1612 		queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful");
   1613 	} else {
   1614 		syslog(LOG_ALERT, "DevAttrReg failed");
   1615 	}
   1616 
   1617 error:
   1618 	if (cmd)
   1619 		isns_free_pdu(cmd);
   1620 	if (rsp)
   1621 		isns_free_pdu(rsp);
   1622 	isns_close(so);
   1623 	return (ret);
   1624 }
   1625 
   1626 /*
   1627  * Deregister an iscsi target node
   1628  */
   1629 int
   1630 isns_dereg(char *name)
   1631 {
   1632 	int so;
   1633 	int ret;
   1634 
   1635 	if (isns_server_connection_thr_running == False) {
   1636 		syslog(LOG_ERR,
   1637 		    "isns_dereg: iSNS discovery is not running."
   1638 		    " Check the previous iSNS initialization error.");
   1639 		return (-1);
   1640 	}
   1641 
   1642 	if ((so = isns_open(isns_args.server)) == -1) {
   1643 		return (-1);
   1644 	}
   1645 
   1646 	ret = isns_dev_attr_dereg(so, name);
   1647 
   1648 	isns_close(so);
   1649 	return (ret);
   1650 }
   1651 
   1652 /*
   1653  * Update an existing iscsi target property
   1654  */
   1655 int
   1656 isns_dev_update(char *targ, uint32_t mods)
   1657 {
   1658 	int		so;
   1659 	int		flags = 0;	/* update only */
   1660 	char		*iname = NULL;
   1661 	char		*dummy = NULL;
   1662 	char		alias[MAXNAMELEN];
   1663 	tgt_node_t	*tgt = NULL;
   1664 	isns_pdu_t	*cmd;
   1665 	isns_rsp_t	*rsp;
   1666 	int		ret = -1;
   1667 
   1668 	if (mods == 0)
   1669 		return (0);
   1670 
   1671 	if (isns_server_connection_thr_running == False) {
   1672 		syslog(LOG_ERR,
   1673 		    "isns_dev_update: iSNS discovery is not running."
   1674 		    " Check the previous iSNS initialization error.");
   1675 		return (-1);
   1676 	}
   1677 
   1678 	if ((tgt = find_tgt_by_name(targ, &iname)) != NULL) {
   1679 		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &dummy) ==
   1680 		    True) {
   1681 			(void) strcpy(alias, dummy);
   1682 			free(dummy);
   1683 		} else
   1684 			(void) strcpy(alias, tgt->x_value);
   1685 
   1686 		if ((so = isns_open(isns_args.server)) < 0) {
   1687 			goto error;
   1688 		}
   1689 
   1690 		if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd)) {
   1691 			goto error;
   1692 		}
   1693 		/* source attr, msg key, delimiter */
   1694 		if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1695 		    STRLEN(iname), iname, 0) != 0) {
   1696 			goto error;
   1697 		}
   1698 		if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
   1699 		    STRLEN(isns_args.entity), isns_args.entity, 0) != 0) {
   1700 			goto error;
   1701 		}
   1702 		if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0)
   1703 		    != 0) {
   1704 			goto error;
   1705 		}
   1706 
   1707 		/*
   1708 		 * get current operating attributes, alias & portal group
   1709 		 * objects, these should be the only things that get change
   1710 		 */
   1711 		(void) isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
   1712 		    STRLEN(iname), iname, 0);
   1713 		(void) isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
   1714 		    ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE);
   1715 
   1716 		if (mods & ISNS_MOD_ALIAS)
   1717 		if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID,
   1718 		    STRLEN(alias), alias, 0) != 0) {
   1719 			goto error;
   1720 		}
   1721 
   1722 		if (mods & ISNS_MOD_TPGT)
   1723 			if (append_tpgt(tgt, cmd) != 0) {
   1724 				goto error;
   1725 			}
   1726 
   1727 		if (isns_send(so, (isns_pdu_t *)cmd) < 0) {
   1728 			goto error;
   1729 		}
   1730 
   1731 		if (isns_recv(so, &rsp) == -1) {
   1732 			goto error;
   1733 		}
   1734 
   1735 		/* process response, if failed do a isns_reg_all */
   1736 		if ((ret = process_rsp(cmd, rsp)) == -1) {
   1737 			if (isns_reg_all() != 0 || isns_scn_reg_all() != 0) {
   1738 				syslog(LOG_ALERT, "ISNS register failed\n");
   1739 				goto error;
   1740 			}
   1741 			ret = 0;
   1742 		} else {
   1743 			if (isns_scn_reg(so, iname) == -1) {
   1744 				syslog(LOG_ERR, "ISNS SCN register failed\n");
   1745 				goto error;
   1746 			}
   1747 			ret = 0;
   1748 		}
   1749 	} else {
   1750 		syslog(LOG_ERR, "ISNS: fails to update target %s\n", alias);
   1751 	}
   1752 
   1753 error:
   1754 	if (cmd)
   1755 		isns_free_pdu(cmd);
   1756 	if (rsp)
   1757 		isns_free_pdu(rsp);
   1758 	if (iname)
   1759 		free(iname);
   1760 	isns_close(so);
   1761 	return (ret);
   1762 }
   1763 
   1764 
   1765 /*
   1766  * Deregister all iscsi target nodes from the XML database
   1767  */
   1768 int
   1769 isns_dereg_all()
   1770 {
   1771 	return (isns_op_all(ISNS_DEV_DEREG));
   1772 }
   1773 
   1774 int
   1775 isns_scn_reg_all()
   1776 {
   1777 	return (isns_op_all(ISNS_SCN_REG));
   1778 }
   1779 
   1780 int
   1781 isns_scn_dereg_all()
   1782 {
   1783 	return (isns_op_all(ISNS_SCN_DEREG));
   1784 }
   1785 
   1786 /*
   1787  * Query an iscsi initiator node
   1788  */
   1789 Boolean_t
   1790 isns_qry_initiator(char *target, char *initiator)
   1791 {
   1792 	int so;
   1793 	int ret;
   1794 
   1795 	if (isns_server_connection_thr_running == False) {
   1796 		syslog(LOG_ERR,
   1797 		    "isns_qry_initiator: iSNS discovery is not running"
   1798 		    " Check the previous iSNS initialization error.");
   1799 		return (-1);
   1800 	}
   1801 
   1802 	if ((so = isns_open(isns_args.server)) == -1) {
   1803 		syslog(LOG_ERR, "isns_qry failed");
   1804 		return (-1);
   1805 	}
   1806 
   1807 	ret = isns_dev_attr_qry(so, target, initiator);
   1808 
   1809 	isns_close(so);
   1810 	return (ret == 1 ? True : False);
   1811 }
   1812 
   1813 Boolean_t
   1814 isns_enabled()
   1815 {
   1816 	Boolean_t	isns_access = False;
   1817 	char		*isns_srv = NULL;
   1818 
   1819 	(void) tgt_find_value_boolean(main_config, XML_ELEMENT_ISNS_ACCESS,
   1820 	    &isns_access);
   1821 	/* get isns server info */
   1822 	if (isns_access == True) {
   1823 		if (tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV,
   1824 		    &isns_srv) == True) {
   1825 			free(isns_srv);
   1826 			return (True);
   1827 		}
   1828 	}
   1829 	return (False);
   1830 }
   1831