1/*	$NetBSD: iscsid_discover.c,v 1.3 2011/11/20 01:23:57 agc Exp $	*/
2
3/*-
4 * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifndef ISCSI_MINIMAL
33
34#include "iscsid_globals.h"
35#include "isns.h"
36#include "isns_defs.h"
37
38#include <sys/socket.h>
39#include <netinet/in.h>
40#include <netinet/tcp.h>
41#include <netdb.h>
42
43#define MY_FLAGS  ISNS_FLAG_REPLACE_REG
44
45
46/**********************************************************************
47**********************************************************************/
48
49uint32_t isns_id = 0;			/* isns ID counter */
50
51ISNS_HANDLE isns_handle = ISNS_INVALID_HANDLE;
52
53/**********************************************************************
54**********************************************************************/
55
56/*
57 * xlate_ip
58 *  Support routine to translate binary IP into string form for storage in
59 *  target object. Handles IPv6 and IPv4 formats.
60 *
61 * Parameters:
62 *       dest  the destination string
63 *       data  the source (from iSNS address field)
64 *
65 * Returns:     status
66 */
67
68static void
69xlate_ip(uint8_t *dest, size_t size, void *data)
70{
71	uint16_t *wdt = (uint16_t *) data;
72	size_t	cc;
73	int i;
74	char *dst = (char *)dest;
75	char *dt = data;
76
77	for (i = 0; i < 5 && !wdt[i]; i++) {
78	}
79	if (i == 5 && wdt[5] == 0xffff) {
80		snprintf(dst, size, "%d.%d.%d.%d",
81			dt[12], dt[13], dt[14], dt[15]);
82	} else {
83		for (cc = 0, i = 0; i < 7; i++) {
84			cc += snprintf(&dst[cc], size - cc, "%x:", wdt[i]);
85		}
86		snprintf(&dst[cc], size - cc, "%x", wdt[7]);
87	}
88}
89
90
91/*
92 * get_isns_target_info
93 *  Support routine to query the server for the attributes of the given target.
94 *
95 * Parameters:
96 *       TargetName  The target name to query.
97 *
98 * Returns:     status
99 */
100
101static uint32_t
102get_isns_target_info(isns_t * isns, uint8_t * TargetName)
103{
104	int retval;
105	ISNS_TRANS t;
106	uint32_t tag;
107	uint32_t data_len;
108	void *data_p;
109	uint32_t u32;
110	struct timespec tout = { 5, 0 };
111	uint32_t status;
112	target_t *targ;
113	char name[ISCSI_STRING_LENGTH];
114	char alias[ISCSI_STRING_LENGTH];
115	iscsi_portal_address_t addr;
116
117	t = isns_new_trans(isns_handle, isnsp_DevAttrQry, MY_FLAGS);
118	if (ISNS_INVALID_TRANS == t) {
119		DEBOUT(("%s: get_targets iscsi_new_trans failed\n", __func__));
120		return ISCSID_STATUS_NO_RESOURCES;
121	}
122	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
123	isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
124
125	isns_add_tlv(t, isnst_Delimiter, 0, NULL);
126
127	isns_add_tlv(t, isnst_iSCSIName, 0, NULL);	/* 32: name */
128	isns_add_tlv(t, isnst_iSCSINodeType, 0, NULL);	/* 33: node type */
129	isns_add_tlv(t, isnst_iSCSIAlias, 0, NULL);	/* 34: alias */
130	/* ToDo: get security attributes... */
131	/* isns_add_tlv (t, isnst_PortalSecBmap, 0, NULL); */
132	/*tag=27: security bitmap */
133
134	retval = isns_send_trans(t, &tout, &status);
135	DEB(9, ("isns_send_trans called, returns %d, status %d\n", retval, status));
136	if (retval) {
137		DEBOUT(("iSNS Attribute Query failed, rc = %d\n", retval));
138		isns_free_trans(t);
139		return ISCSID_STATUS_ISNS_SERVER_ERROR;
140	}
141	/* First is target name (the one we put in), ignore */
142	if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
143		DEBOUT(("iSNS Attribute Query returned nothing\n"));
144		isns_free_trans(t);
145		return ISCSID_STATUS_ISNS_SERVER_ERROR;
146	}
147	if (tag != isnst_iSCSIName) {
148		DEBOUT(("iSNS Query returned bad type (tag = %d, length = %d)\n",
149				tag, data_len));
150		isns_free_trans(t);
151		return ISCSID_STATUS_ISNS_SERVER_ERROR;
152	}
153
154	isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
155	if (tag != isnst_Delimiter) {
156		DEBOUT(("Attr Query Missing Delimiter (tag = %d, length = %d)\n",
157				tag, data_len));
158		isns_free_trans(t);
159		return ISCSID_STATUS_ISNS_SERVER_ERROR;
160	}
161
162	isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
163	if (tag != isnst_iSCSIName || !data_len || data_len >= ISCSI_STRING_LENGTH) {
164		DEBOUT(("iSNS Query returned no or invalid name (tag = %d, "
165				"length = %d)\n", tag, data_len));
166		isns_free_trans(t);
167		return ISCSID_STATUS_ISNS_SERVER_ERROR;
168	}
169	strlcpy(name, (char *) data_p, sizeof(name));
170
171	isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
172	if (tag != isnst_iSCSINodeType || data_len != 4) {
173		DEBOUT(("iSNS Query returned no or invalid node type (tag = %d, "
174				"length = %d)\n", tag, data_len));
175		isns_free_trans(t);
176		return ISCSID_STATUS_ISNS_SERVER_ERROR;
177	}
178	u32 = ntohl(*((uint32_t *) data_p));
179	if (!(u32 & 1)) {
180		DEBOUT(("iSNS Query returned bad type (type=%x, should be 1)\n", u32));
181		isns_free_trans(t);
182		return ISCSID_STATUS_ISNS_SERVER_ERROR;
183	}
184
185	isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
186	if (tag == isnst_iSCSIAlias) {
187		if (data_len >= ISCSI_STRING_LENGTH) {
188			DEBOUT(("iSNS Query returned invalid alias (tag=%d, length=%d)\n",
189					tag, data_len));
190			isns_free_trans(t);
191			return ISCSID_STATUS_ISNS_SERVER_ERROR;
192		}
193		strlcpy(alias, (char *) data_p, sizeof(alias));
194		isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
195	} else
196		alias[0] = 0;
197
198	isns_free_trans(t);
199
200	if (ISNS_INVALID_TRANS ==
201		(t = isns_new_trans(isns_handle, isnsp_DevAttrQry, MY_FLAGS))) {
202		DEBOUT(("get_targets iscsi_new_trans failed\n"));
203		return ISCSID_STATUS_NO_RESOURCES;
204	}
205	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
206	isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
207
208	isns_add_tlv(t, isnst_Delimiter, 0, NULL);
209
210	isns_add_tlv(t, isnst_PGiSCSIName, 0, NULL);	/* 48: portal name */
211	isns_add_tlv(t, isnst_PGPortIPAddr, 0, NULL);	/* 49: portal IP */
212	isns_add_tlv(t, isnst_PGPortIPPort, 0, NULL);	/* 50: portal port */
213	isns_add_tlv(t, isnst_PGTag, 0, NULL);	/* 51: group tag */
214
215	retval = isns_send_trans(t, &tout, &status);
216	DEB(9, ("isns_send_trans called, returns %d, status %d\n", retval, status));
217	if (retval) {
218		DEBOUT(("iSNS Attribute Query failed, rc = %d\n", retval));
219		isns_free_trans(t);
220		return ISCSID_STATUS_ISNS_SERVER_ERROR;
221	}
222	/* First is target name (the one we put in), ignore */
223	if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
224		DEBOUT(("iSNS Attribute Query returned nothing\n"));
225		isns_free_trans(t);
226		return ISCSID_STATUS_ISNS_SERVER_ERROR;
227	}
228	if (tag != isnst_iSCSIName) {
229		DEBOUT(("iSNS Query2 returned bad name (tag = %d, length = %d)\n",
230				tag, data_len));
231		isns_free_trans(t);
232		return ISCSID_STATUS_ISNS_SERVER_ERROR;
233	}
234
235	isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
236	if (tag != isnst_Delimiter) {
237		DEBOUT(("Attr Query2 Missing Delimiter (tag = %d, length = %d)\n",
238				tag, data_len));
239		isns_free_trans(t);
240		return ISCSID_STATUS_ISNS_SERVER_ERROR;
241	}
242
243	while (!isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p)) {
244		if (tag != isnst_PGiSCSIName || !data_len ||
245			data_len >= ISCSI_STRING_LENGTH) {
246			DEBOUT(("iSNS Query2 returned no or invalid name (tag=%d, "
247					"length=%d)\n", tag, data_len));
248			isns_free_trans(t);
249			return ISCSID_STATUS_ISNS_SERVER_ERROR;
250		}
251		strlcpy(name, (char *) data_p, sizeof(name));
252
253		isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
254		if (tag != isnst_PGPortIPAddr || data_len != 16) {
255			DEBOUT(("iSNS Query returned no or invalid address (tag=%d, "
256					"length=%d)\n", tag, data_len));
257			isns_free_trans(t);
258			return ISCSID_STATUS_ISNS_SERVER_ERROR;
259		}
260		xlate_ip(addr.address, sizeof(addr.address), (uint8_t *) data_p);
261
262		/* Now comes the port */
263		isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
264		if (tag != isnst_PGPortIPPort || data_len != 4) {
265			DEBOUT(("iSNS Query returned no or invalid port (tag=%d, "
266					"length=%d)\n", tag, data_len));
267			isns_free_trans(t);
268			return ISCSID_STATUS_ISNS_SERVER_ERROR;
269		}
270		u32 = ntohl(*((uint32_t *) data_p));
271		if (u32 & 0xffff0000) {
272			DEBOUT(("iSNS Query returned invalid port (flags=%x, "
273					"should be 0)\n", u32 >> 16));
274			isns_free_trans(t);
275			return ISCSID_STATUS_ISNS_SERVER_ERROR;
276		}
277		addr.port = (uint16_t) u32;
278
279		/* And each target must have a group tag */
280		isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
281		if (tag != isnst_PGTag || (data_len && data_len != 4)) {
282			DEBOUT(("iSNS Query returned no or invalid group tag (tag=%d, "
283					"length=%d)\n", tag, data_len));
284			isns_free_trans(t);
285			return ISCSID_STATUS_ISNS_SERVER_ERROR;
286		}
287		if (data_len) {
288			u32 = ntohl(*((uint32_t *) data_p));
289			addr.group_tag = (uint16_t) u32;
290		} else
291			addr.group_tag = 0;
292
293		/* we have everything necessary to describe the target, add it. */
294
295		DEB(1, ("Adding <%s>, IP <%s>, Port %d, Tag %d\n",
296				name, addr.address, addr.port, addr.group_tag));
297
298		if ((targ = add_discovered_target((unsigned char *)name, &addr, PORTAL_TYPE_ISNS,
299				isns->entry.sid.id)) == NULL) {
300			isns_free_trans(t);
301			return ISCSID_STATUS_NO_RESOURCES;
302		}
303
304		if (alias[0]) {
305			strlcpy((char *)targ->TargetAlias, alias,
306				sizeof(targ->TargetAlias));
307		}
308	}
309	isns_free_trans(t);
310
311	return ISCSID_STATUS_SUCCESS;
312}
313
314
315/*
316 * deregister_isns_server
317 *  Support routine to deregister the initiator from the iSNS server
318 *
319 * Parameters:  The server descriptor
320 *
321 * Returns:     status
322 */
323
324static uint32_t
325deregister_isns_server(isns_t * isns)
326{
327	int retval;
328	ISNS_TRANS t;
329	struct timespec tout = { 5, 0 };
330	uint32_t status;
331
332	/*
333	 * Create transaction for deregistering with iSNS server
334	 */
335
336	if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle, isnsp_DevDereg,
337												  MY_FLAGS))) {
338		DEBOUT(("dereg_isns_server iscsi_new_trans failed\n"));
339		return ISCSID_STATUS_NO_RESOURCES;
340	}
341
342	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
343	isns_add_tlv(t, isnst_Delimiter, 0, NULL);
344	isns_add_string(t, isnst_EID, (char *)isns->reg_entity_id);
345	isns_add_tlv(t, isnst_PortalIPAddr, (uint32_t)sizeof(isns->reg_ip_addr),
346				 isns->reg_ip_addr);
347	isns_add_tlv(t, isnst_PortalPort, (uint32_t)sizeof(isns->reg_ip_port),
348				 &isns->reg_ip_port);
349	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
350
351	retval = isns_send_trans(t, &tout, &status);
352	DEB(9, ("DevAttrReg request returns %d, status %d\n", retval, status));
353
354	isns_free_trans(t);
355	return ISCSID_STATUS_SUCCESS;
356}
357
358/*
359 * register_isns_server
360 *
361 * Parameters:  The server descriptor
362 *
363 * Returns:     status
364 */
365
366
367static uint32_t
368register_isns_server(isns_t * isns)
369{
370	int retval;
371	ISNS_TRANS t;
372	uint32_t u32;
373	struct timespec tout = { 5, 0 };
374	uint32_t status;
375
376	if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle, isnsp_DevAttrReg,
377												  MY_FLAGS))) {
378		DEBOUT(("iscsi_new_trans failed\n"));
379		return ISCSID_STATUS_NO_RESOURCES;
380	}
381
382	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);	/*tag=32 */
383	isns_add_tlv(t, isnst_Delimiter, 0, NULL);
384	isns_add_string(t, isnst_EID, (char *)isns->reg_entity_id);
385	u32 = htonl(2);
386	isns_add_tlv(t, isnst_EntProtocol, (uint32_t)sizeof(u32), &u32);
387	isns_add_tlv(t, isnst_PortalIPAddr, (uint32_t)sizeof(isns->reg_ip_addr),
388				 isns->reg_ip_addr);
389	isns_add_tlv(t, isnst_PortalPort, (uint32_t)sizeof(isns->reg_ip_port),
390				 &isns->reg_ip_port);
391	isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);	/*tag=32 */
392	u32 = htonl(2);
393	isns_add_tlv(t, isnst_iSCSINodeType, (uint32_t)sizeof(u32), &u32);
394		/*tag=33 (node type = intiator) */
395
396	retval = isns_send_trans(t, &tout, &status);
397	DEB(9, ("DevAttrReg request returns %d, status %d\n", retval, status));
398	isns_free_trans(t);
399
400	if (retval || status)
401		return ISCSID_STATUS_ISNS_ERROR;
402
403	return ISCSID_STATUS_SUCCESS;
404}
405
406
407/*
408 * get_registration_info
409 *
410 * Parameters:  The server descriptor
411 *
412 * Returns:     status
413 */
414
415
416static uint32_t
417get_registration_info(isns_t * isns)
418{
419	struct sockaddr_storage sa;
420	unsigned n;
421
422	strlcpy((char *)isns->reg_iscsi_name, (char *)node_name.InitiatorName,
423			sizeof(isns->reg_iscsi_name));
424	strlcpy((char *)isns->reg_entity_id, (char *)node_name.InitiatorAlias,
425			sizeof(isns->reg_entity_id));
426
427	/*Get our source IP and port numbers */
428	n = sizeof(sa);
429	if (getsockname(isns->sock, (struct sockaddr *)(void *)&sa, &n)) {
430		DEBOUT(("Getsockname returned error %d\n", errno));
431		return ISCSID_STATUS_GENERAL_ERROR;
432	}
433	switch (sa.ss_family) {
434	case AF_INET:
435		{
436			struct sockaddr_in *si =
437			    (struct sockaddr_in *)(void *)&sa;
438			uint32_t *u32 = (uint32_t *)(void *)isns->reg_ip_addr;
439
440			u32[0] = u32[1] = 0;
441			u32[2] = htonl(0xffff);
442			u32[3] = htonl(si->sin_addr.s_addr);
443			isns->reg_ip_port = htons(si->sin_port);
444		}
445		break;
446
447	case AF_INET6:
448		{
449			struct sockaddr_in6 *si =
450			    (struct sockaddr_in6 *)(void *) &sa;
451
452			memcpy(isns->reg_ip_addr, &si->sin6_addr,
453					sizeof(isns->reg_ip_addr));
454			isns->reg_ip_port = htons(si->sin6_port);
455		}
456		break;
457
458	default:
459		DEBOUT(("Getsockname returned unknown address family: %d\n",
460				sa.ss_family));
461		return ISCSID_STATUS_GENERAL_ERROR;
462	}
463	return ISCSID_STATUS_SUCCESS;
464}
465
466
467/*
468 * iscsi_isns_serverconn - given a set of server address, try connecting
469 *
470 * Parameters:  The descriptor for the iSNS server to query
471 *
472 * Returns:     status
473 */
474
475static uint32_t
476iscsi_isns_serverconn(isns_t * isns)
477{
478	int sock = -1;
479	char port[16];
480	struct addrinfo hints;
481	struct addrinfo *ai, *addr;
482	int retval;
483
484	/*
485	 * Initialize the iSNS library if it needs it
486	 */
487
488	if (isns_handle == ISNS_INVALID_HANDLE) {
489		if ((retval = isns_init(&isns_handle, 0)) != 0) {
490			/*Couldn't initialize the iSNS library */
491			DEBOUT(("isns_init failed with code %d\n", retval));
492			isns_handle = ISNS_INVALID_HANDLE;
493			return ISCSID_STATUS_GENERAL_ERROR;
494		}
495	}
496
497	/*
498	 * Find the server address from the iSNS server list entry,
499	 * and try to connect to the iSNS server
500	 */
501
502	snprintf(port, sizeof(port), "%d", (isns->port) ? isns->port : ISCSI_DEFAULT_ISNS_PORT);
503	memset(&hints, 0, sizeof(hints));
504	hints.ai_family = PF_UNSPEC;
505	hints.ai_socktype = SOCK_STREAM;
506	hints.ai_protocol = IPPROTO_TCP;
507
508	retval = getaddrinfo((char *)isns->address, port, &hints, &ai);
509	if (retval) {
510		DEBOUT(("getaddrinfo failed with code %d (%s)\n",
511				retval, gai_strerror(retval)));
512		return ISCSID_STATUS_GENERAL_ERROR;
513	}
514
515	for (addr = ai; addr != NULL; addr = addr->ai_next) {
516		sock = socket(addr->ai_family, addr->ai_socktype,
517		    addr->ai_protocol);
518
519		if (sock == -1) {
520			DEBOUT(("%s: socket call FAILED!\n", __func__));
521			freeaddrinfo(ai);
522			return (uint32_t)-1;
523		}
524
525		if (connect(sock, addr->ai_addr, addr->ai_addrlen) != -1)
526			break;
527
528		DEB(1, ("%s: connect call FAILED!\n", __func__));
529		close(sock);
530		sock = -1;
531	}
532
533	if (addr == NULL) {
534		DEBOUT(("%s: couldn't connect!\n", __func__));
535		freeaddrinfo(ai);
536		return ISCSID_STATUS_GENERAL_ERROR;
537	}
538
539	if (isns_add_servercon(isns_handle, sock, addr)) {
540		DEBOUT(("%s: FAILED!\n", __func__));
541		close(sock);
542		freeaddrinfo(ai);
543		return ISCSID_STATUS_GENERAL_ERROR;
544	}
545
546	freeaddrinfo(ai);
547	isns->sock = sock;
548
549	if ((retval = get_registration_info(isns)) != 0) {
550		return retval;
551	}
552
553	deregister_isns_server(isns);
554
555	return register_isns_server(isns);
556}
557
558
559/*
560 * update_isns_server_info
561 *  Support routine to query the specified iSNS server for all targets
562 *  Called from add_isns_server and refresh_isns_server
563 *
564 * Parameters:  The descriptor for the iSNS server to query
565 *
566 * Returns:     status
567 */
568
569
570static uint32_t
571update_isns_server_info(isns_t * isns)
572{
573	int retval;
574	ISNS_TRANS t;
575	uint32_t tag;
576	uint32_t data_len;
577	void *data_p;
578	uint32_t u32;
579	struct timespec tout = { 5, 0 };
580	uint32_t status;
581	uint8_t TargetName[ISCSI_STRING_LENGTH];
582
583
584	DEB(9, ("update_isns_server_info for iSNS %s\n", isns->address));
585
586	if (isns->sock < 0) {
587		if ((status = iscsi_isns_serverconn(isns)) != 0) {
588			/*We couldn't connect to the iSNS server */
589			DEB(9, ("update_isns_server_info iscsi_isns_serverconn failed\n"));
590			return status;
591		}
592	}
593
594	for (TargetName[0] = 0;;) {
595		if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle,
596												isnsp_DevGetNext, MY_FLAGS))) {
597			DEBOUT(("update_isns_server_info iscsi_new_trans failed\n"));
598			return ISCSID_STATUS_NO_RESOURCES;
599		}
600
601		isns_add_string(t, isnst_iSCSIName, (char *)node_name.InitiatorName);
602
603		if (TargetName[0])
604			isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
605		else
606			isns_add_tlv(t, isnst_iSCSIName, 0, NULL);
607
608		isns_add_tlv(t, isnst_Delimiter, 0, NULL);
609		isns_add_tlv(t, isnst_iSCSINodeType, 0, NULL);
610
611		if ((retval = isns_send_trans(t, &tout, &status)) != 0) {
612			DEBOUT(("isns_send_trans returns rc %d, status %d\n",
613					retval, status));
614			isns_free_trans(t);
615			break;
616		}
617		if (status) {
618			DEB(9, ("DevGetNext Status = %d\n", status));
619			break;
620		}
621
622		if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
623			DEBOUT(("No TLV in DevGetNext response!\n"));
624			isns_free_trans(t);
625			break;
626		}
627		/* We need the name, or there's nothing left to do */
628
629		if (tag != isnst_iSCSIName || !data_len ||
630			data_len >= ISCSI_STRING_LENGTH) {
631			DEBOUT(("iSNS GetNextDev returned no or invalid name (tag=%d, "
632					"length=%d)\n", tag, data_len));
633			isns_free_trans(t);
634			break;
635		}
636		strlcpy((char *)TargetName, (char *) data_p, sizeof(TargetName));
637
638		/* We must get at least the node type, and it must be a target */
639		if (isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p)) {
640			DEBOUT(("iSNS GetDevNext did not return node type\n"));
641			isns_free_trans(t);
642			break;
643		}
644		if (tag == isnst_Delimiter && isns_get_tlv(t, ISNS_TLV_NEXT, &tag,
645													&data_len, &data_p)) {
646			DEBOUT(("iSNS GetDevNext did not return node type (past delim)\n"));
647			isns_free_trans(t);
648			break;
649		}
650		if (tag != isnst_iSCSINodeType || data_len != 4) {
651			DEBOUT(("iSNS Query returned no or invalid node type (tag=%d, "
652					"length=%d)\n", tag, data_len));
653			isns_free_trans(t);
654			break;
655		}
656		u32 = ntohl(*((uint32_t *) data_p));
657		isns_free_trans(t);
658
659		if (u32 & 1)
660			get_isns_target_info(isns, TargetName);
661	}
662
663	DEB(9, ("update_isns_server_info returning SUCCESS!\n"));
664	return ISCSID_STATUS_SUCCESS;
665}
666
667
668/**********************************************************************
669**********************************************************************/
670
671/*
672 * create_isns:
673 *    Create an isns structure and initialize it.
674 *
675 *    Parameter:
676 *          name        The iSNS server name
677 *
678 *    Returns:    Pointer to isns structure, NULL if allocation failed.
679 */
680
681static isns_t *
682create_isns(iscsid_add_isns_server_req_t * req)
683{
684	isns_t *isns;
685
686	DEB(9, ("Create iSNS %s\n", req->address));
687
688	if ((isns = calloc(1, sizeof(*isns))) == NULL)
689		return NULL;
690
691	for (isns_id++; !isns_id || find_isns_id(isns_id) != NULL;)
692		isns_id++;
693
694	isns->entry.sid.id = isns_id;
695	strlcpy((char *)isns->entry.sid.name, (char *)req->name, sizeof(isns->entry.sid.name));
696	strlcpy((char *)isns->address, (char *)req->address, sizeof(isns->address));
697	isns->port = req->port;
698	isns->sock = -1;
699
700	return isns;
701}
702
703
704/*
705 * add_isns_server
706 *    Adds an iSNS server to the server list.
707 *    This command will add the address of an iSNS server to the list
708 *      of iSNS servers that the discovery daemon queries to discover targets.
709 *      The daemon will then register itself with the iSNS server,
710 *      and query the iSNS server for the list of targets.
711 *      The discovered targets will be added to the list of target portals.
712 *      The response contains the ID of the iSNS server.
713 *
714 * Parameter:  The parameter contains the address of the server.
715 *
716 * Returns:    Nothing
717 *             The response parameter is an iscsid_add_isns_server_rsp_t
718 *             containing:
719 *                  server_id = Unique ID for the iSNS server
720 */
721
722void
723add_isns_server(iscsid_add_isns_server_req_t * req, iscsid_response_t ** prsp,
724				int *prsp_temp)
725{
726	iscsid_response_t *rsp = *prsp;
727	iscsid_add_isns_server_rsp_t *res;
728	isns_t *isns;
729
730	DEB(9, ("IN add_isns_server\n"));
731
732	/*
733	 * Make a response
734	 */
735
736	rsp = make_rsp(sizeof(iscsid_add_isns_server_rsp_t), prsp, prsp_temp);
737	if (rsp == NULL) {
738		DEB(9, ("OUT add_isns_server: make_rsp FAILED\n"));
739		return;
740	}
741
742	res = (iscsid_add_isns_server_rsp_t *)(void *)rsp->parameter;
743
744	/*
745	 * First, allocate the isns server structure to put on the list
746	 */
747
748	isns = create_isns(req);
749	if (isns == NULL) {
750		rsp->status = ISCSID_STATUS_NO_RESOURCES;
751		DEB(9, ("OUT add_isns_server: create_isns FAILED!\n"));
752		return;
753	}
754
755	TAILQ_INSERT_TAIL(&list[ISNS_LIST].list, &isns->entry, link);
756	list[ISNS_LIST].num_entries++;
757	res->server_id = isns->entry.sid.id;
758
759	DEB(9, ("OUT add_isns_server: server_id = %d, name = %s\n",
760			isns->entry.sid.id, isns->address));
761
762	/*
763	 * Now try to connect to the iSNS server...
764	 */
765
766	update_isns_server_info(isns);
767}
768
769
770/*
771 * get_isns_server
772 *    Returns the address of the iSNS server with the specified ID
773 *
774 * Parameters:  The unique ID of the server
775 *
776 * Returns:     The status returned by the driver
777 *              The response parameter contains the iSNS server address as a
778 *              zero-terminated UTF-8 string
779 */
780
781void
782get_isns_server(iscsid_sym_id_t * preq, iscsid_response_t ** prsp,
783				int *prsp_temp)
784{
785	iscsid_response_t *rsp = *prsp;
786	iscsid_get_isns_server_rsp_t *res;
787	isns_t *isns;
788
789	DEB(9, ("IN get_isns_server\n"));
790	isns = find_isns(preq);
791	if (isns == NULL) {
792		rsp->status = ISCSID_STATUS_INVALID_ISNS_ID;
793		DEB(9, ("OUT get_isns_server: find_isns FAILED!\n"));
794		return;
795	}
796
797	rsp = make_rsp(sizeof(iscsid_get_isns_server_rsp_t), prsp, prsp_temp);
798	if (rsp == NULL) {
799		DEB(9, ("OUT get_isns_server: make_rsp FAILED!\n"));
800		return;
801	}
802	res = (iscsid_get_isns_server_rsp_t *)(void *)rsp->parameter;
803
804	strlcpy((char *)res->address, (char *)isns->address,
805	    sizeof(res->address));
806	res->port = isns->port;
807	res->server_id = isns->entry.sid;
808	DEB(9, ("OUT get_isns_server: id = %d, address = %s\n",
809			res->server_id.id, res->address));
810}
811
812
813/*
814 * slp_find_isns_servers
815 */
816
817/* More Here Later... */
818
819
820/*
821 * refresh_isns_server
822 *    Query the specified iSNS servers for the list of targets.
823 *
824 *    Parameters:
825 *          id    Server ID
826 *
827 *    Returns:     Status
828 */
829
830uint32_t
831refresh_isns_server(uint32_t id)
832{
833	uint32_t rc;
834	isns_t *isns;
835	generic_entry_t *curr;
836	generic_entry_t *next;
837
838	isns = find_isns_id(id);
839	if (isns == NULL)
840		return ISCSID_STATUS_INVALID_ISNS_ID;
841
842	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
843		portal_t *p = (portal_t *)(void *)curr;
844		if (p->portaltype == PORTAL_TYPE_ISNS && p->discoveryid == id)
845			p->portaltype = PORTAL_TYPE_REFRESHING;
846	}
847
848	rc = update_isns_server_info(isns);
849
850	/*
851	 * Go through our list of portals and look for ones
852	 * that are still marked for refreshing.
853	 * These are ones that are no longer there and should be removed.
854	 */
855
856	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
857		 curr = next) {
858		portal_t *p = (portal_t *)(void *)curr;
859		next = TAILQ_NEXT(curr, link);
860		if (p->portaltype == PORTAL_TYPE_REFRESHING)
861			delete_portal(p, TRUE);
862	}
863
864	return rc;
865}
866
867
868/*
869 * remove_isns_server
870 *    Removed an iSNS server.
871 *    This does not remove the discovered targets from the list.
872 *
873 * Parameters:  The iscid_remove_isns_req_t structure containing:
874 *                  server_id = unique ID of server to remove
875 *
876 * Returns:     The status returned.
877 */
878
879uint32_t
880remove_isns_server(iscsid_sym_id_t * preq)
881{
882	generic_entry_t *curr;
883	isns_t *isns;
884	uint32_t id;
885
886	isns = find_isns(preq);
887	if (isns == NULL)
888		return ISCSID_STATUS_INVALID_ISNS_ID;
889
890	/*Deregister with the iSNS server. */
891	/*Ignore any errors during deregistration... */
892	if (isns->sock >= 0) {
893		deregister_isns_server(isns);
894		close(isns->sock);
895	}
896
897	TAILQ_REMOVE(&list[ISNS_LIST].list, &isns->entry, link);
898	list[ISNS_LIST].num_entries--;
899
900	id = isns->entry.sid.id;
901	free(isns);
902
903	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
904		portal_t *p = (portal_t *)(void *)curr;
905		if (p->portaltype == PORTAL_TYPE_ISNS && p->discoveryid == id)
906			p->discoveryid = 0; /* mark deleted */
907	}
908
909	return ISCSID_STATUS_SUCCESS;
910}
911
912
913/*
914   Deregister all isns servers on daemon termination
915*/
916
917void
918dereg_all_isns_servers(void)
919{
920	generic_list_t *plist;
921	generic_entry_t *curr;
922
923	plist = &list[ISNS_LIST].list;
924	TAILQ_FOREACH(curr, plist, link)
925		deregister_isns_server((isns_t *)(void *)curr);
926}
927
928#endif
929
930