2 * Copyright (c) 2012 The FreeBSD Foundation
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
38 #include <netinet/in.h>
41 #include "iscsi_proto.h"
44 text_receive(struct connection
*conn
)
47 struct iscsi_bhs_text_response
*bhstr
;
49 response
= pdu_new(conn
);
50 pdu_receive(response
);
51 if (response
->pdu_bhs
->bhs_opcode
!= ISCSI_BHS_OPCODE_TEXT_RESPONSE
)
52 log_errx(1, "protocol error: received invalid opcode 0x%x",
53 response
->pdu_bhs
->bhs_opcode
);
54 bhstr
= (struct iscsi_bhs_text_response
*)response
->pdu_bhs
;
56 if ((bhstr
->bhstr_flags
& BHSTR_FLAGS_FINAL
) == 0)
57 log_errx(1, "received Text PDU without the \"F\" flag");
60 * XXX: Implement the C flag some day.
62 if ((bhstr
->bhstr_flags
& BHSTR_FLAGS_CONTINUE
) != 0)
63 log_errx(1, "received Text PDU with unsupported \"C\" flag");
64 if (ntohl(bhstr
->bhstr_statsn
) != conn
->conn_statsn
+ 1) {
65 log_errx(1, "received Text PDU with wrong StatSN: "
66 "is %u, should be %u", ntohl(bhstr
->bhstr_statsn
),
67 conn
->conn_statsn
+ 1);
69 conn
->conn_statsn
= ntohl(bhstr
->bhstr_statsn
);
75 text_new_request(struct connection
*conn
)
78 struct iscsi_bhs_text_request
*bhstr
;
80 request
= pdu_new(conn
);
81 bhstr
= (struct iscsi_bhs_text_request
*)request
->pdu_bhs
;
82 bhstr
->bhstr_opcode
= ISCSI_BHS_OPCODE_TEXT_REQUEST
|
83 ISCSI_BHS_OPCODE_IMMEDIATE
;
84 bhstr
->bhstr_flags
= BHSTR_FLAGS_FINAL
;
85 bhstr
->bhstr_initiator_task_tag
= 0;
86 bhstr
->bhstr_target_transfer_tag
= 0xffffffff;
88 bhstr
->bhstr_initiator_task_tag
= 0; /* XXX */
89 bhstr
->bhstr_cmdsn
= 0; /* XXX */
90 bhstr
->bhstr_expstatsn
= htonl(conn
->conn_statsn
+ 1);
96 logout_receive(struct connection
*conn
)
99 struct iscsi_bhs_logout_response
*bhslr
;
101 response
= pdu_new(conn
);
102 pdu_receive(response
);
103 if (response
->pdu_bhs
->bhs_opcode
!= ISCSI_BHS_OPCODE_LOGOUT_RESPONSE
)
104 log_errx(1, "protocol error: received invalid opcode 0x%x",
105 response
->pdu_bhs
->bhs_opcode
);
106 bhslr
= (struct iscsi_bhs_logout_response
*)response
->pdu_bhs
;
107 if (ntohs(bhslr
->bhslr_response
) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY
)
108 log_warnx("received Logout Response with reason %d",
109 ntohs(bhslr
->bhslr_response
));
110 if (ntohl(bhslr
->bhslr_statsn
) != conn
->conn_statsn
+ 1) {
111 log_errx(1, "received Logout PDU with wrong StatSN: "
112 "is %u, should be %u", ntohl(bhslr
->bhslr_statsn
),
113 conn
->conn_statsn
+ 1);
115 conn
->conn_statsn
= ntohl(bhslr
->bhslr_statsn
);
121 logout_new_request(struct connection
*conn
)
124 struct iscsi_bhs_logout_request
*bhslr
;
126 request
= pdu_new(conn
);
127 bhslr
= (struct iscsi_bhs_logout_request
*)request
->pdu_bhs
;
128 bhslr
->bhslr_opcode
= ISCSI_BHS_OPCODE_LOGOUT_REQUEST
|
129 ISCSI_BHS_OPCODE_IMMEDIATE
;
130 bhslr
->bhslr_reason
= BHSLR_REASON_CLOSE_SESSION
;
131 bhslr
->bhslr_reason
|= 0x80;
132 bhslr
->bhslr_initiator_task_tag
= 0; /* XXX */
133 bhslr
->bhslr_cmdsn
= 0; /* XXX */
134 bhslr
->bhslr_expstatsn
= htonl(conn
->conn_statsn
+ 1);
140 kernel_add(const struct connection
*conn
, const char *target
)
142 struct iscsi_session_add isa
;
145 memset(&isa
, 0, sizeof(isa
));
146 memcpy(&isa
.isa_conf
, &conn
->conn_conf
, sizeof(isa
.isa_conf
));
147 strlcpy(isa
.isa_conf
.isc_target
, target
,
148 sizeof(isa
.isa_conf
.isc_target
));
149 isa
.isa_conf
.isc_discovery
= 0;
150 error
= ioctl(conn
->conn_iscsi_fd
, ISCSISADD
, &isa
);
152 log_warn("failed to add %s: ISCSISADD", target
);
156 kernel_remove(const struct connection
*conn
)
158 struct iscsi_session_remove isr
;
161 memset(&isr
, 0, sizeof(isr
));
162 isr
.isr_session_id
= conn
->conn_session_id
;
163 error
= ioctl(conn
->conn_iscsi_fd
, ISCSISREMOVE
, &isr
);
165 log_warn("ISCSISREMOVE");
169 discovery(struct connection
*conn
)
171 struct pdu
*request
, *response
;
172 struct keys
*request_keys
, *response_keys
;
175 log_debugx("beginning discovery session");
176 request
= text_new_request(conn
);
177 request_keys
= keys_new();
178 keys_add(request_keys
, "SendTargets", "All");
179 keys_save(request_keys
, request
);
180 keys_delete(request_keys
);
186 log_debugx("waiting for Text Response");
187 response
= text_receive(conn
);
188 response_keys
= keys_new();
189 keys_load(response_keys
, response
);
190 for (i
= 0; i
< KEYS_MAX
; i
++) {
191 if (response_keys
->keys_names
[i
] == NULL
)
194 if (strcmp(response_keys
->keys_names
[i
], "TargetName") != 0)
197 log_debugx("adding target %s", response_keys
->keys_values
[i
]);
199 * XXX: Validate the target name?
201 kernel_add(conn
, response_keys
->keys_values
[i
]);
203 keys_delete(response_keys
);
204 pdu_delete(response
);
206 log_debugx("removing temporary discovery session");
209 #ifdef ICL_KERNEL_PROXY
210 if (conn
->conn_conf
.isc_iser
== 1) {
212 * If we're going through the proxy, the kernel already
213 * sent Logout PDU for us and destroyed the session,
214 * so we can't send anything anymore.
216 log_debugx("discovery session done");
221 log_debugx("discovery done; logging out");
222 request
= logout_new_request(conn
);
227 log_debugx("waiting for Logout Response");
228 response
= logout_receive(conn
);
229 pdu_delete(response
);
231 log_debugx("discovery session done");