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