xref: /freebsd/usr.sbin/iscsid/discovery.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
1009ea47eSEdward Tomasz Napierala /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4009ea47eSEdward Tomasz Napierala  * Copyright (c) 2012 The FreeBSD Foundation
5009ea47eSEdward Tomasz Napierala  *
6009ea47eSEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
7009ea47eSEdward Tomasz Napierala  * from the FreeBSD Foundation.
8009ea47eSEdward Tomasz Napierala  *
9009ea47eSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
10009ea47eSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
11009ea47eSEdward Tomasz Napierala  * are met:
12009ea47eSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
13009ea47eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
14009ea47eSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
15009ea47eSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
16009ea47eSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
17009ea47eSEdward Tomasz Napierala  *
18009ea47eSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19009ea47eSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20009ea47eSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21009ea47eSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22009ea47eSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23009ea47eSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24009ea47eSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25009ea47eSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26009ea47eSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27009ea47eSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28009ea47eSEdward Tomasz Napierala  * SUCH DAMAGE.
29009ea47eSEdward Tomasz Napierala  *
30009ea47eSEdward Tomasz Napierala  */
31009ea47eSEdward Tomasz Napierala 
32009ea47eSEdward Tomasz Napierala #include <sys/types.h>
33009ea47eSEdward Tomasz Napierala #include <sys/ioctl.h>
34009ea47eSEdward Tomasz Napierala #include <stdbool.h>
35009ea47eSEdward Tomasz Napierala #include <string.h>
36009ea47eSEdward Tomasz Napierala #include <netinet/in.h>
37009ea47eSEdward Tomasz Napierala 
38009ea47eSEdward Tomasz Napierala #include "iscsid.h"
39009ea47eSEdward Tomasz Napierala #include "iscsi_proto.h"
40009ea47eSEdward Tomasz Napierala 
41009ea47eSEdward Tomasz Napierala static struct pdu *
logout_receive(struct connection * conn)42009ea47eSEdward Tomasz Napierala logout_receive(struct connection *conn)
43009ea47eSEdward Tomasz Napierala {
44009ea47eSEdward Tomasz Napierala 	struct pdu *response;
45009ea47eSEdward Tomasz Napierala 	struct iscsi_bhs_logout_response *bhslr;
46009ea47eSEdward Tomasz Napierala 
47009ea47eSEdward Tomasz Napierala 	response = pdu_new(conn);
48009ea47eSEdward Tomasz Napierala 	pdu_receive(response);
49009ea47eSEdward Tomasz Napierala 	if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGOUT_RESPONSE)
50009ea47eSEdward Tomasz Napierala 		log_errx(1, "protocol error: received invalid opcode 0x%x",
51009ea47eSEdward Tomasz Napierala 		    response->pdu_bhs->bhs_opcode);
52009ea47eSEdward Tomasz Napierala 	bhslr = (struct iscsi_bhs_logout_response *)response->pdu_bhs;
53009ea47eSEdward Tomasz Napierala 	if (ntohs(bhslr->bhslr_response) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY)
54009ea47eSEdward Tomasz Napierala 		log_warnx("received Logout Response with reason %d",
55009ea47eSEdward Tomasz Napierala 		    ntohs(bhslr->bhslr_response));
56009ea47eSEdward Tomasz Napierala 	if (ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) {
57009ea47eSEdward Tomasz Napierala 		log_errx(1, "received Logout PDU with wrong StatSN: "
582124e3b0SAlexander Motin 		    "is %u, should be %u", ntohl(bhslr->bhslr_statsn),
59009ea47eSEdward Tomasz Napierala 		    conn->conn_statsn + 1);
60009ea47eSEdward Tomasz Napierala 	}
61009ea47eSEdward Tomasz Napierala 	conn->conn_statsn = ntohl(bhslr->bhslr_statsn);
62009ea47eSEdward Tomasz Napierala 
63009ea47eSEdward Tomasz Napierala 	return (response);
64009ea47eSEdward Tomasz Napierala }
65009ea47eSEdward Tomasz Napierala 
66009ea47eSEdward Tomasz Napierala static struct pdu *
logout_new_request(struct connection * conn)67009ea47eSEdward Tomasz Napierala logout_new_request(struct connection *conn)
68009ea47eSEdward Tomasz Napierala {
69009ea47eSEdward Tomasz Napierala 	struct pdu *request;
70009ea47eSEdward Tomasz Napierala 	struct iscsi_bhs_logout_request *bhslr;
71009ea47eSEdward Tomasz Napierala 
72009ea47eSEdward Tomasz Napierala 	request = pdu_new(conn);
73009ea47eSEdward Tomasz Napierala 	bhslr = (struct iscsi_bhs_logout_request *)request->pdu_bhs;
74009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST |
75009ea47eSEdward Tomasz Napierala 	    ISCSI_BHS_OPCODE_IMMEDIATE;
76009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION;
77009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_reason |= 0x80;
78009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_initiator_task_tag = 0; /* XXX */
79009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_cmdsn = 0; /* XXX */
80009ea47eSEdward Tomasz Napierala 	bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1);
81009ea47eSEdward Tomasz Napierala 
82009ea47eSEdward Tomasz Napierala 	return (request);
83009ea47eSEdward Tomasz Napierala }
84009ea47eSEdward Tomasz Napierala 
85009ea47eSEdward Tomasz Napierala static void
kernel_add(const struct iscsid_connection * conn,const char * target)8663783933SJohn Baldwin kernel_add(const struct iscsid_connection *conn, const char *target)
87009ea47eSEdward Tomasz Napierala {
88009ea47eSEdward Tomasz Napierala 	struct iscsi_session_add isa;
89009ea47eSEdward Tomasz Napierala 	int error;
90009ea47eSEdward Tomasz Napierala 
91009ea47eSEdward Tomasz Napierala 	memset(&isa, 0, sizeof(isa));
929e55679bSEdward Tomasz Napierala 	memcpy(&isa.isa_conf, &conn->conn_conf, sizeof(isa.isa_conf));
93009ea47eSEdward Tomasz Napierala 	strlcpy(isa.isa_conf.isc_target, target,
94009ea47eSEdward Tomasz Napierala 	    sizeof(isa.isa_conf.isc_target));
95009ea47eSEdward Tomasz Napierala 	isa.isa_conf.isc_discovery = 0;
96009ea47eSEdward Tomasz Napierala 	error = ioctl(conn->conn_iscsi_fd, ISCSISADD, &isa);
97009ea47eSEdward Tomasz Napierala 	if (error != 0)
98009ea47eSEdward Tomasz Napierala 		log_warn("failed to add %s: ISCSISADD", target);
99009ea47eSEdward Tomasz Napierala }
100009ea47eSEdward Tomasz Napierala 
101009ea47eSEdward Tomasz Napierala static void
kernel_remove(const struct iscsid_connection * conn)10263783933SJohn Baldwin kernel_remove(const struct iscsid_connection *conn)
103009ea47eSEdward Tomasz Napierala {
104009ea47eSEdward Tomasz Napierala 	struct iscsi_session_remove isr;
105009ea47eSEdward Tomasz Napierala 	int error;
106009ea47eSEdward Tomasz Napierala 
107009ea47eSEdward Tomasz Napierala 	memset(&isr, 0, sizeof(isr));
108009ea47eSEdward Tomasz Napierala 	isr.isr_session_id = conn->conn_session_id;
109009ea47eSEdward Tomasz Napierala 	error = ioctl(conn->conn_iscsi_fd, ISCSISREMOVE, &isr);
110009ea47eSEdward Tomasz Napierala 	if (error != 0)
111009ea47eSEdward Tomasz Napierala 		log_warn("ISCSISREMOVE");
112009ea47eSEdward Tomasz Napierala }
113009ea47eSEdward Tomasz Napierala 
114009ea47eSEdward Tomasz Napierala void
discovery(struct iscsid_connection * conn)11563783933SJohn Baldwin discovery(struct iscsid_connection *conn)
116009ea47eSEdward Tomasz Napierala {
117009ea47eSEdward Tomasz Napierala 	struct pdu *request, *response;
118009ea47eSEdward Tomasz Napierala 	struct keys *request_keys, *response_keys;
119009ea47eSEdward Tomasz Napierala 	int i;
120009ea47eSEdward Tomasz Napierala 
121009ea47eSEdward Tomasz Napierala 	log_debugx("beginning discovery session");
122009ea47eSEdward Tomasz Napierala 	request_keys = keys_new();
123009ea47eSEdward Tomasz Napierala 	keys_add(request_keys, "SendTargets", "All");
124b4068979SJohn Baldwin 	text_send_request(&conn->conn, request_keys);
125009ea47eSEdward Tomasz Napierala 	keys_delete(request_keys);
126009ea47eSEdward Tomasz Napierala 	request_keys = NULL;
127009ea47eSEdward Tomasz Napierala 
128009ea47eSEdward Tomasz Napierala 	log_debugx("waiting for Text Response");
129b4068979SJohn Baldwin 	response_keys = text_read_response(&conn->conn);
130009ea47eSEdward Tomasz Napierala 	for (i = 0; i < KEYS_MAX; i++) {
131009ea47eSEdward Tomasz Napierala 		if (response_keys->keys_names[i] == NULL)
132009ea47eSEdward Tomasz Napierala 			break;
133009ea47eSEdward Tomasz Napierala 
134009ea47eSEdward Tomasz Napierala 		if (strcmp(response_keys->keys_names[i], "TargetName") != 0)
135009ea47eSEdward Tomasz Napierala 			continue;
136009ea47eSEdward Tomasz Napierala 
137009ea47eSEdward Tomasz Napierala 		log_debugx("adding target %s", response_keys->keys_values[i]);
138009ea47eSEdward Tomasz Napierala 		/*
139009ea47eSEdward Tomasz Napierala 		 * XXX: Validate the target name?
140009ea47eSEdward Tomasz Napierala 		 */
141009ea47eSEdward Tomasz Napierala 		kernel_add(conn, response_keys->keys_values[i]);
142009ea47eSEdward Tomasz Napierala 	}
143009ea47eSEdward Tomasz Napierala 	keys_delete(response_keys);
144009ea47eSEdward Tomasz Napierala 
145009ea47eSEdward Tomasz Napierala 	log_debugx("removing temporary discovery session");
146009ea47eSEdward Tomasz Napierala 	kernel_remove(conn);
147009ea47eSEdward Tomasz Napierala 
148b7af91d0SEdward Tomasz Napierala #ifdef ICL_KERNEL_PROXY
149b7af91d0SEdward Tomasz Napierala 	if (conn->conn_conf.isc_iser == 1) {
150b7af91d0SEdward Tomasz Napierala 		/*
151b7af91d0SEdward Tomasz Napierala 		 * If we're going through the proxy, the kernel already
152b7af91d0SEdward Tomasz Napierala 		 * sent Logout PDU for us and destroyed the session,
153b7af91d0SEdward Tomasz Napierala 		 * so we can't send anything anymore.
154b7af91d0SEdward Tomasz Napierala 		 */
155b7af91d0SEdward Tomasz Napierala 		log_debugx("discovery session done");
156b7af91d0SEdward Tomasz Napierala 		return;
157b7af91d0SEdward Tomasz Napierala 	}
158b7af91d0SEdward Tomasz Napierala #endif
159b7af91d0SEdward Tomasz Napierala 
160009ea47eSEdward Tomasz Napierala 	log_debugx("discovery done; logging out");
16163783933SJohn Baldwin 	request = logout_new_request(&conn->conn);
162009ea47eSEdward Tomasz Napierala 	pdu_send(request);
1630b50e359SEdward Tomasz Napierala 	pdu_delete(request);
164009ea47eSEdward Tomasz Napierala 	request = NULL;
165009ea47eSEdward Tomasz Napierala 
166009ea47eSEdward Tomasz Napierala 	log_debugx("waiting for Logout Response");
16763783933SJohn Baldwin 	response = logout_receive(&conn->conn);
168009ea47eSEdward Tomasz Napierala 	pdu_delete(response);
169009ea47eSEdward Tomasz Napierala 
170009ea47eSEdward Tomasz Napierala 	log_debugx("discovery session done");
171009ea47eSEdward Tomasz Napierala }
172