Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e48354ce NB |
2 | /******************************************************************************* |
3 | * This file contains main functions related to iSCSI Parameter negotiation. | |
4 | * | |
4c76251e | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
e48354ce NB |
6 | * |
7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | |
8 | * | |
e48354ce NB |
9 | ******************************************************************************/ |
10 | ||
11 | #include <linux/ctype.h> | |
e5419865 | 12 | #include <linux/kthread.h> |
8dcf07be | 13 | #include <linux/slab.h> |
3f07c014 | 14 | #include <linux/sched/signal.h> |
8dcf07be | 15 | #include <net/sock.h> |
e48354ce NB |
16 | #include <scsi/iscsi_proto.h> |
17 | #include <target/target_core_base.h> | |
c4795fb2 | 18 | #include <target/target_core_fabric.h> |
baa4d64b | 19 | #include <target/iscsi/iscsi_transport.h> |
e48354ce | 20 | |
67f091f2 | 21 | #include <target/iscsi/iscsi_target_core.h> |
e48354ce NB |
22 | #include "iscsi_target_parameters.h" |
23 | #include "iscsi_target_login.h" | |
24 | #include "iscsi_target_nego.h" | |
25 | #include "iscsi_target_tpg.h" | |
26 | #include "iscsi_target_util.h" | |
27 | #include "iscsi_target.h" | |
28 | #include "iscsi_target_auth.h" | |
29 | ||
30 | #define MAX_LOGIN_PDUS 7 | |
31 | #define TEXT_LEN 4096 | |
32 | ||
33 | void convert_null_to_semi(char *buf, int len) | |
34 | { | |
35 | int i; | |
36 | ||
37 | for (i = 0; i < len; i++) | |
38 | if (buf[i] == '\0') | |
39 | buf[i] = ';'; | |
40 | } | |
41 | ||
fceb5bc7 | 42 | static int strlen_semi(char *buf) |
e48354ce NB |
43 | { |
44 | int i = 0; | |
45 | ||
46 | while (buf[i] != '\0') { | |
47 | if (buf[i] == ';') | |
48 | return i; | |
49 | i++; | |
50 | } | |
51 | ||
52 | return -1; | |
53 | } | |
54 | ||
55 | int extract_param( | |
56 | const char *in_buf, | |
57 | const char *pattern, | |
58 | unsigned int max_length, | |
59 | char *out_buf, | |
60 | unsigned char *type) | |
61 | { | |
62 | char *ptr; | |
63 | int len; | |
64 | ||
65 | if (!in_buf || !pattern || !out_buf || !type) | |
66 | return -1; | |
67 | ||
68 | ptr = strstr(in_buf, pattern); | |
69 | if (!ptr) | |
70 | return -1; | |
71 | ||
72 | ptr = strstr(ptr, "="); | |
73 | if (!ptr) | |
74 | return -1; | |
75 | ||
76 | ptr += 1; | |
77 | if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) { | |
78 | ptr += 2; /* skip 0x */ | |
79 | *type = HEX; | |
80 | } else | |
81 | *type = DECIMAL; | |
82 | ||
83 | len = strlen_semi(ptr); | |
84 | if (len < 0) | |
85 | return -1; | |
86 | ||
369653e4 | 87 | if (len >= max_length) { |
5e58b029 | 88 | pr_err("Length of input: %d exceeds max_length:" |
e48354ce NB |
89 | " %d\n", len, max_length); |
90 | return -1; | |
91 | } | |
92 | memcpy(out_buf, ptr, len); | |
93 | out_buf[len] = '\0'; | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | static u32 iscsi_handle_authentication( | |
99 | struct iscsi_conn *conn, | |
100 | char *in_buf, | |
101 | char *out_buf, | |
102 | int in_length, | |
103 | int *out_length, | |
104 | unsigned char *authtype) | |
105 | { | |
106 | struct iscsi_session *sess = conn->sess; | |
107 | struct iscsi_node_auth *auth; | |
108 | struct iscsi_node_acl *iscsi_nacl; | |
c3e51442 | 109 | struct iscsi_portal_group *iscsi_tpg; |
e48354ce NB |
110 | struct se_node_acl *se_nacl; |
111 | ||
112 | if (!sess->sess_ops->SessionType) { | |
113 | /* | |
114 | * For SessionType=Normal | |
115 | */ | |
116 | se_nacl = conn->sess->se_sess->se_node_acl; | |
117 | if (!se_nacl) { | |
118 | pr_err("Unable to locate struct se_node_acl for" | |
119 | " CHAP auth\n"); | |
120 | return -1; | |
121 | } | |
122 | iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, | |
123 | se_node_acl); | |
124 | if (!iscsi_nacl) { | |
125 | pr_err("Unable to locate struct iscsi_node_acl for" | |
126 | " CHAP auth\n"); | |
127 | return -1; | |
128 | } | |
129 | ||
c3e51442 NB |
130 | if (se_nacl->dynamic_node_acl) { |
131 | iscsi_tpg = container_of(se_nacl->se_tpg, | |
132 | struct iscsi_portal_group, tpg_se_tpg); | |
133 | ||
134 | auth = &iscsi_tpg->tpg_demo_auth; | |
135 | } else { | |
136 | iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, | |
137 | se_node_acl); | |
138 | ||
b7eec2cd | 139 | auth = &iscsi_nacl->node_auth; |
c3e51442 | 140 | } |
e48354ce NB |
141 | } else { |
142 | /* | |
143 | * For SessionType=Discovery | |
144 | */ | |
145 | auth = &iscsit_global->discovery_acl.node_auth; | |
146 | } | |
147 | ||
148 | if (strstr("CHAP", authtype)) | |
149 | strcpy(conn->sess->auth_type, "CHAP"); | |
150 | else | |
151 | strcpy(conn->sess->auth_type, NONE); | |
152 | ||
153 | if (strstr("None", authtype)) | |
154 | return 1; | |
155 | #ifdef CANSRP | |
156 | else if (strstr("SRP", authtype)) | |
157 | return srp_main_loop(conn, auth, in_buf, out_buf, | |
158 | &in_length, out_length); | |
159 | #endif | |
160 | else if (strstr("CHAP", authtype)) | |
161 | return chap_main_loop(conn, auth, in_buf, out_buf, | |
162 | &in_length, out_length); | |
163 | else if (strstr("SPKM1", authtype)) | |
164 | return 2; | |
165 | else if (strstr("SPKM2", authtype)) | |
166 | return 2; | |
167 | else if (strstr("KRB5", authtype)) | |
168 | return 2; | |
169 | else | |
170 | return 2; | |
171 | } | |
172 | ||
173 | static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) | |
174 | { | |
175 | kfree(conn->auth_protocol); | |
176 | } | |
177 | ||
baa4d64b | 178 | int iscsi_target_check_login_request( |
e48354ce NB |
179 | struct iscsi_conn *conn, |
180 | struct iscsi_login *login) | |
181 | { | |
28168905 | 182 | int req_csg, req_nsg; |
e48354ce NB |
183 | u32 payload_length; |
184 | struct iscsi_login_req *login_req; | |
e48354ce NB |
185 | |
186 | login_req = (struct iscsi_login_req *) login->req; | |
e48354ce NB |
187 | payload_length = ntoh24(login_req->dlength); |
188 | ||
189 | switch (login_req->opcode & ISCSI_OPCODE_MASK) { | |
190 | case ISCSI_OP_LOGIN: | |
191 | break; | |
192 | default: | |
193 | pr_err("Received unknown opcode 0x%02x.\n", | |
194 | login_req->opcode & ISCSI_OPCODE_MASK); | |
195 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
196 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
197 | return -1; | |
198 | } | |
199 | ||
200 | if ((login_req->flags & ISCSI_FLAG_LOGIN_CONTINUE) && | |
201 | (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { | |
202 | pr_err("Login request has both ISCSI_FLAG_LOGIN_CONTINUE" | |
203 | " and ISCSI_FLAG_LOGIN_TRANSIT set, protocol error.\n"); | |
204 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
205 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
206 | return -1; | |
207 | } | |
208 | ||
5d358065 AG |
209 | req_csg = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags); |
210 | req_nsg = ISCSI_LOGIN_NEXT_STAGE(login_req->flags); | |
e48354ce NB |
211 | |
212 | if (req_csg != login->current_stage) { | |
213 | pr_err("Initiator unexpectedly changed login stage" | |
214 | " from %d to %d, login failed.\n", login->current_stage, | |
215 | req_csg); | |
216 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
217 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
218 | return -1; | |
219 | } | |
220 | ||
221 | if ((req_nsg == 2) || (req_csg >= 2) || | |
222 | ((login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT) && | |
223 | (req_nsg <= req_csg))) { | |
224 | pr_err("Illegal login_req->flags Combination, CSG: %d," | |
225 | " NSG: %d, ISCSI_FLAG_LOGIN_TRANSIT: %d.\n", req_csg, | |
226 | req_nsg, (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)); | |
227 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
228 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
229 | return -1; | |
230 | } | |
231 | ||
232 | if ((login_req->max_version != login->version_max) || | |
233 | (login_req->min_version != login->version_min)) { | |
234 | pr_err("Login request changed Version Max/Nin" | |
235 | " unexpectedly to 0x%02x/0x%02x, protocol error\n", | |
236 | login_req->max_version, login_req->min_version); | |
237 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
238 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
239 | return -1; | |
240 | } | |
241 | ||
242 | if (memcmp(login_req->isid, login->isid, 6) != 0) { | |
243 | pr_err("Login request changed ISID unexpectedly," | |
244 | " protocol error.\n"); | |
245 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
246 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
247 | return -1; | |
248 | } | |
249 | ||
250 | if (login_req->itt != login->init_task_tag) { | |
251 | pr_err("Login request changed ITT unexpectedly to" | |
252 | " 0x%08x, protocol error.\n", login_req->itt); | |
253 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
254 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
255 | return -1; | |
256 | } | |
257 | ||
258 | if (payload_length > MAX_KEY_VALUE_PAIRS) { | |
259 | pr_err("Login request payload exceeds default" | |
260 | " MaxRecvDataSegmentLength: %u, protocol error.\n", | |
261 | MAX_KEY_VALUE_PAIRS); | |
262 | return -1; | |
263 | } | |
264 | ||
265 | return 0; | |
266 | } | |
d2faaefb | 267 | EXPORT_SYMBOL(iscsi_target_check_login_request); |
e48354ce NB |
268 | |
269 | static int iscsi_target_check_first_request( | |
270 | struct iscsi_conn *conn, | |
271 | struct iscsi_login *login) | |
272 | { | |
273 | struct iscsi_param *param = NULL; | |
274 | struct se_node_acl *se_nacl; | |
275 | ||
276 | login->first_request = 0; | |
277 | ||
278 | list_for_each_entry(param, &conn->param_list->param_list, p_list) { | |
279 | if (!strncmp(param->name, SESSIONTYPE, 11)) { | |
280 | if (!IS_PSTATE_ACCEPTOR(param)) { | |
281 | pr_err("SessionType key not received" | |
282 | " in first login request.\n"); | |
283 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
284 | ISCSI_LOGIN_STATUS_MISSING_FIELDS); | |
285 | return -1; | |
286 | } | |
287 | if (!strncmp(param->value, DISCOVERY, 9)) | |
288 | return 0; | |
289 | } | |
290 | ||
291 | if (!strncmp(param->name, INITIATORNAME, 13)) { | |
292 | if (!IS_PSTATE_ACCEPTOR(param)) { | |
293 | if (!login->leading_connection) | |
294 | continue; | |
295 | ||
296 | pr_err("InitiatorName key not received" | |
297 | " in first login request.\n"); | |
298 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
299 | ISCSI_LOGIN_STATUS_MISSING_FIELDS); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | /* | |
304 | * For non-leading connections, double check that the | |
305 | * received InitiatorName matches the existing session's | |
306 | * struct iscsi_node_acl. | |
307 | */ | |
308 | if (!login->leading_connection) { | |
309 | se_nacl = conn->sess->se_sess->se_node_acl; | |
310 | if (!se_nacl) { | |
311 | pr_err("Unable to locate" | |
312 | " struct se_node_acl\n"); | |
313 | iscsit_tx_login_rsp(conn, | |
314 | ISCSI_STATUS_CLS_INITIATOR_ERR, | |
315 | ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); | |
316 | return -1; | |
317 | } | |
318 | ||
319 | if (strcmp(param->value, | |
320 | se_nacl->initiatorname)) { | |
321 | pr_err("Incorrect" | |
322 | " InitiatorName: %s for this" | |
323 | " iSCSI Initiator Node.\n", | |
324 | param->value); | |
325 | iscsit_tx_login_rsp(conn, | |
326 | ISCSI_STATUS_CLS_INITIATOR_ERR, | |
327 | ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); | |
328 | return -1; | |
329 | } | |
330 | } | |
331 | } | |
332 | } | |
333 | ||
334 | return 0; | |
335 | } | |
336 | ||
337 | static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) | |
338 | { | |
339 | u32 padding = 0; | |
e48354ce NB |
340 | struct iscsi_login_rsp *login_rsp; |
341 | ||
342 | login_rsp = (struct iscsi_login_rsp *) login->rsp; | |
343 | ||
344 | login_rsp->opcode = ISCSI_OP_LOGIN_RSP; | |
345 | hton24(login_rsp->dlength, login->rsp_length); | |
346 | memcpy(login_rsp->isid, login->isid, 6); | |
347 | login_rsp->tsih = cpu_to_be16(login->tsih); | |
66c7db68 | 348 | login_rsp->itt = login->init_task_tag; |
e48354ce NB |
349 | login_rsp->statsn = cpu_to_be32(conn->stat_sn++); |
350 | login_rsp->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | |
109e2381 | 351 | login_rsp->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); |
e48354ce NB |
352 | |
353 | pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x," | |
354 | " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:" | |
66c7db68 | 355 | " %u\n", login_rsp->flags, (__force u32)login_rsp->itt, |
e48354ce NB |
356 | ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn), |
357 | ntohl(login_rsp->statsn), login->rsp_length); | |
358 | ||
359 | padding = ((-login->rsp_length) & 3); | |
e5419865 NB |
360 | /* |
361 | * Before sending the last login response containing the transition | |
362 | * bit for full-feature-phase, go ahead and start up TX/RX threads | |
363 | * now to avoid potential resource allocation failures after the | |
364 | * final login response has been sent. | |
365 | */ | |
366 | if (login->login_complete) { | |
367 | int rc = iscsit_start_kthreads(conn); | |
368 | if (rc) { | |
369 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
370 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | |
371 | return -1; | |
372 | } | |
373 | } | |
e48354ce | 374 | |
baa4d64b NB |
375 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, |
376 | login->rsp_length + padding) < 0) | |
e5419865 | 377 | goto err; |
e48354ce NB |
378 | |
379 | login->rsp_length = 0; | |
e48354ce NB |
380 | |
381 | return 0; | |
e5419865 NB |
382 | |
383 | err: | |
384 | if (login->login_complete) { | |
385 | if (conn->rx_thread && conn->rx_thread_active) { | |
386 | send_sig(SIGINT, conn->rx_thread, 1); | |
ca82c2bd | 387 | complete(&conn->rx_login_comp); |
e5419865 NB |
388 | kthread_stop(conn->rx_thread); |
389 | } | |
390 | if (conn->tx_thread && conn->tx_thread_active) { | |
391 | send_sig(SIGINT, conn->tx_thread, 1); | |
392 | kthread_stop(conn->tx_thread); | |
393 | } | |
394 | spin_lock(&iscsit_global->ts_bitmap_lock); | |
395 | bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, | |
396 | get_order(1)); | |
397 | spin_unlock(&iscsit_global->ts_bitmap_lock); | |
398 | } | |
399 | return -1; | |
e48354ce NB |
400 | } |
401 | ||
676d2369 | 402 | static void iscsi_target_sk_data_ready(struct sock *sk) |
d381a801 NB |
403 | { |
404 | struct iscsi_conn *conn = sk->sk_user_data; | |
405 | bool rc; | |
406 | ||
407 | pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn); | |
408 | ||
409 | write_lock_bh(&sk->sk_callback_lock); | |
410 | if (!sk->sk_user_data) { | |
411 | write_unlock_bh(&sk->sk_callback_lock); | |
412 | return; | |
413 | } | |
414 | if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { | |
415 | write_unlock_bh(&sk->sk_callback_lock); | |
416 | pr_debug("Got LOGIN_FLAGS_READY=0, conn: %p >>>>\n", conn); | |
417 | return; | |
418 | } | |
419 | if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { | |
420 | write_unlock_bh(&sk->sk_callback_lock); | |
421 | pr_debug("Got LOGIN_FLAGS_CLOSED=1, conn: %p >>>>\n", conn); | |
422 | return; | |
423 | } | |
424 | if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { | |
425 | write_unlock_bh(&sk->sk_callback_lock); | |
426 | pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn); | |
1c130ae0 FW |
427 | if (iscsi_target_sk_data_ready == conn->orig_data_ready) |
428 | return; | |
429 | conn->orig_data_ready(sk); | |
d381a801 NB |
430 | return; |
431 | } | |
432 | ||
433 | rc = schedule_delayed_work(&conn->login_work, 0); | |
0bcc297e | 434 | if (!rc) { |
d381a801 NB |
435 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" |
436 | " got false\n"); | |
437 | } | |
438 | write_unlock_bh(&sk->sk_callback_lock); | |
439 | } | |
440 | ||
bb048357 NB |
441 | static void iscsi_target_sk_state_change(struct sock *); |
442 | ||
d381a801 NB |
443 | static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) |
444 | { | |
445 | struct sock *sk; | |
446 | ||
447 | if (!conn->sock) | |
448 | return; | |
449 | ||
450 | sk = conn->sock->sk; | |
451 | pr_debug("Entering iscsi_target_set_sock_callbacks: conn: %p\n", conn); | |
452 | ||
453 | write_lock_bh(&sk->sk_callback_lock); | |
454 | sk->sk_user_data = conn; | |
455 | conn->orig_data_ready = sk->sk_data_ready; | |
bb048357 | 456 | conn->orig_state_change = sk->sk_state_change; |
d381a801 | 457 | sk->sk_data_ready = iscsi_target_sk_data_ready; |
bb048357 | 458 | sk->sk_state_change = iscsi_target_sk_state_change; |
d381a801 | 459 | write_unlock_bh(&sk->sk_callback_lock); |
bb048357 NB |
460 | |
461 | sk->sk_sndtimeo = TA_LOGIN_TIMEOUT * HZ; | |
462 | sk->sk_rcvtimeo = TA_LOGIN_TIMEOUT * HZ; | |
d381a801 NB |
463 | } |
464 | ||
465 | static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) | |
466 | { | |
467 | struct sock *sk; | |
468 | ||
469 | if (!conn->sock) | |
470 | return; | |
471 | ||
472 | sk = conn->sock->sk; | |
473 | pr_debug("Entering iscsi_target_restore_sock_callbacks: conn: %p\n", conn); | |
474 | ||
475 | write_lock_bh(&sk->sk_callback_lock); | |
476 | if (!sk->sk_user_data) { | |
477 | write_unlock_bh(&sk->sk_callback_lock); | |
478 | return; | |
479 | } | |
480 | sk->sk_user_data = NULL; | |
481 | sk->sk_data_ready = conn->orig_data_ready; | |
bb048357 | 482 | sk->sk_state_change = conn->orig_state_change; |
d381a801 | 483 | write_unlock_bh(&sk->sk_callback_lock); |
bb048357 NB |
484 | |
485 | sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; | |
486 | sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; | |
d381a801 NB |
487 | } |
488 | ||
489 | static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); | |
490 | ||
25cdda95 | 491 | static bool __iscsi_target_sk_check_close(struct sock *sk) |
d381a801 NB |
492 | { |
493 | if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { | |
25cdda95 | 494 | pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," |
d381a801 | 495 | "returning FALSE\n"); |
25cdda95 | 496 | return true; |
d381a801 | 497 | } |
25cdda95 NB |
498 | return false; |
499 | } | |
500 | ||
501 | static bool iscsi_target_sk_check_close(struct iscsi_conn *conn) | |
502 | { | |
503 | bool state = false; | |
504 | ||
505 | if (conn->sock) { | |
506 | struct sock *sk = conn->sock->sk; | |
507 | ||
508 | read_lock_bh(&sk->sk_callback_lock); | |
509 | state = (__iscsi_target_sk_check_close(sk) || | |
510 | test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); | |
511 | read_unlock_bh(&sk->sk_callback_lock); | |
512 | } | |
513 | return state; | |
514 | } | |
515 | ||
516 | static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag) | |
517 | { | |
518 | bool state = false; | |
519 | ||
520 | if (conn->sock) { | |
521 | struct sock *sk = conn->sock->sk; | |
522 | ||
523 | read_lock_bh(&sk->sk_callback_lock); | |
524 | state = test_bit(flag, &conn->login_flags); | |
525 | read_unlock_bh(&sk->sk_callback_lock); | |
526 | } | |
527 | return state; | |
528 | } | |
529 | ||
530 | static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag) | |
531 | { | |
532 | bool state = false; | |
533 | ||
534 | if (conn->sock) { | |
535 | struct sock *sk = conn->sock->sk; | |
536 | ||
537 | write_lock_bh(&sk->sk_callback_lock); | |
538 | state = (__iscsi_target_sk_check_close(sk) || | |
539 | test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); | |
540 | if (!state) | |
541 | clear_bit(flag, &conn->login_flags); | |
542 | write_unlock_bh(&sk->sk_callback_lock); | |
543 | } | |
544 | return state; | |
d381a801 NB |
545 | } |
546 | ||
547 | static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) | |
548 | { | |
549 | struct iscsi_np *np = login->np; | |
550 | bool zero_tsih = login->zero_tsih; | |
551 | ||
552 | iscsi_remove_failed_auth_entry(conn); | |
553 | iscsi_target_nego_release(conn); | |
554 | iscsi_target_login_sess_out(conn, np, zero_tsih, true); | |
555 | } | |
556 | ||
f7c9564a KC |
557 | struct conn_timeout { |
558 | struct timer_list timer; | |
559 | struct iscsi_conn *conn; | |
560 | }; | |
561 | ||
562 | static void iscsi_target_login_timeout(struct timer_list *t) | |
d381a801 | 563 | { |
f7c9564a KC |
564 | struct conn_timeout *timeout = from_timer(timeout, t, timer); |
565 | struct iscsi_conn *conn = timeout->conn; | |
d381a801 NB |
566 | |
567 | pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); | |
568 | ||
569 | if (conn->login_kworker) { | |
570 | pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", | |
571 | conn->login_kworker->comm, conn->login_kworker->pid); | |
572 | send_sig(SIGINT, conn->login_kworker, 1); | |
573 | } | |
574 | } | |
575 | ||
576 | static void iscsi_target_do_login_rx(struct work_struct *work) | |
577 | { | |
578 | struct iscsi_conn *conn = container_of(work, | |
579 | struct iscsi_conn, login_work.work); | |
580 | struct iscsi_login *login = conn->login; | |
581 | struct iscsi_np *np = login->np; | |
582 | struct iscsi_portal_group *tpg = conn->tpg; | |
583 | struct iscsi_tpg_np *tpg_np = conn->tpg_np; | |
f7c9564a | 584 | struct conn_timeout timeout; |
d381a801 NB |
585 | int rc, zero_tsih = login->zero_tsih; |
586 | bool state; | |
587 | ||
588 | pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", | |
589 | conn, current->comm, current->pid); | |
25cdda95 NB |
590 | /* |
591 | * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready() | |
592 | * before initial PDU processing in iscsi_target_start_negotiation() | |
593 | * has completed, go ahead and retry until it's cleared. | |
594 | * | |
595 | * Otherwise if the TCP connection drops while this is occuring, | |
596 | * iscsi_target_start_negotiation() will detect the failure, call | |
597 | * cancel_delayed_work_sync(&conn->login_work), and cleanup the | |
598 | * remaining iscsi connection resources from iscsi_np process context. | |
599 | */ | |
600 | if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) { | |
601 | schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10)); | |
602 | return; | |
603 | } | |
d381a801 NB |
604 | |
605 | spin_lock(&tpg->tpg_state_lock); | |
606 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); | |
607 | spin_unlock(&tpg->tpg_state_lock); | |
608 | ||
0bcc297e | 609 | if (!state) { |
d381a801 | 610 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); |
25cdda95 | 611 | goto err; |
d381a801 NB |
612 | } |
613 | ||
25cdda95 NB |
614 | if (iscsi_target_sk_check_close(conn)) { |
615 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); | |
616 | goto err; | |
d381a801 NB |
617 | } |
618 | ||
619 | conn->login_kworker = current; | |
620 | allow_signal(SIGINT); | |
621 | ||
f7c9564a KC |
622 | timeout.conn = conn; |
623 | timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0); | |
624 | mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ); | |
625 | pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid); | |
d381a801 NB |
626 | |
627 | rc = conn->conn_transport->iscsit_get_login_rx(conn, login); | |
f7c9564a KC |
628 | del_timer_sync(&timeout.timer); |
629 | destroy_timer_on_stack(&timeout.timer); | |
d381a801 NB |
630 | flush_signals(current); |
631 | conn->login_kworker = NULL; | |
632 | ||
25cdda95 NB |
633 | if (rc < 0) |
634 | goto err; | |
d381a801 NB |
635 | |
636 | pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", | |
637 | conn, current->comm, current->pid); | |
638 | ||
639 | rc = iscsi_target_do_login(conn, login); | |
640 | if (rc < 0) { | |
25cdda95 | 641 | goto err; |
d381a801 | 642 | } else if (!rc) { |
25cdda95 NB |
643 | if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE)) |
644 | goto err; | |
d381a801 NB |
645 | } else if (rc == 1) { |
646 | iscsi_target_nego_release(conn); | |
647 | iscsi_post_login_handler(np, conn, zero_tsih); | |
648 | iscsit_deaccess_np(np, tpg, tpg_np); | |
649 | } | |
25cdda95 NB |
650 | return; |
651 | ||
652 | err: | |
653 | iscsi_target_restore_sock_callbacks(conn); | |
654 | iscsi_target_login_drop(conn, login); | |
655 | iscsit_deaccess_np(np, tpg, tpg_np); | |
d381a801 NB |
656 | } |
657 | ||
bb048357 NB |
658 | static void iscsi_target_sk_state_change(struct sock *sk) |
659 | { | |
660 | struct iscsi_conn *conn; | |
661 | void (*orig_state_change)(struct sock *); | |
662 | bool state; | |
663 | ||
664 | pr_debug("Entering iscsi_target_sk_state_change\n"); | |
665 | ||
666 | write_lock_bh(&sk->sk_callback_lock); | |
667 | conn = sk->sk_user_data; | |
668 | if (!conn) { | |
669 | write_unlock_bh(&sk->sk_callback_lock); | |
670 | return; | |
671 | } | |
672 | orig_state_change = conn->orig_state_change; | |
673 | ||
674 | if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { | |
675 | pr_debug("Got LOGIN_FLAGS_READY=0 sk_state_change conn: %p\n", | |
676 | conn); | |
677 | write_unlock_bh(&sk->sk_callback_lock); | |
678 | orig_state_change(sk); | |
679 | return; | |
680 | } | |
25cdda95 NB |
681 | state = __iscsi_target_sk_check_close(sk); |
682 | pr_debug("__iscsi_target_sk_close_change: state: %d\n", state); | |
683 | ||
bb048357 NB |
684 | if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { |
685 | pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change" | |
686 | " conn: %p\n", conn); | |
25cdda95 NB |
687 | if (state) |
688 | set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); | |
bb048357 NB |
689 | write_unlock_bh(&sk->sk_callback_lock); |
690 | orig_state_change(sk); | |
691 | return; | |
692 | } | |
25cdda95 | 693 | if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { |
bb048357 NB |
694 | pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n", |
695 | conn); | |
696 | write_unlock_bh(&sk->sk_callback_lock); | |
697 | orig_state_change(sk); | |
698 | return; | |
699 | } | |
25cdda95 NB |
700 | /* |
701 | * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED, | |
702 | * but only queue conn->login_work -> iscsi_target_do_login_rx() | |
703 | * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared. | |
704 | * | |
705 | * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close() | |
706 | * will detect the dropped TCP connection from delayed workqueue context. | |
707 | * | |
708 | * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial | |
709 | * iscsi_target_start_negotiation() is running, iscsi_target_do_login() | |
710 | * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation() | |
711 | * via iscsi_target_sk_check_and_clear() is responsible for detecting the | |
712 | * dropped TCP connection in iscsi_np process context, and cleaning up | |
713 | * the remaining iscsi connection resources. | |
714 | */ | |
715 | if (state) { | |
716 | pr_debug("iscsi_target_sk_state_change got failed state\n"); | |
717 | set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); | |
718 | state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); | |
719 | write_unlock_bh(&sk->sk_callback_lock); | |
bb048357 | 720 | |
25cdda95 | 721 | orig_state_change(sk); |
bb048357 | 722 | |
25cdda95 NB |
723 | if (!state) |
724 | schedule_delayed_work(&conn->login_work, 0); | |
bb048357 NB |
725 | return; |
726 | } | |
25cdda95 NB |
727 | write_unlock_bh(&sk->sk_callback_lock); |
728 | ||
bb048357 NB |
729 | orig_state_change(sk); |
730 | } | |
731 | ||
e48354ce NB |
732 | /* |
733 | * NOTE: We check for existing sessions or connections AFTER the initiator | |
734 | * has been successfully authenticated in order to protect against faked | |
735 | * ISID/TSIH combinations. | |
736 | */ | |
737 | static int iscsi_target_check_for_existing_instances( | |
738 | struct iscsi_conn *conn, | |
739 | struct iscsi_login *login) | |
740 | { | |
741 | if (login->checked_for_existing) | |
742 | return 0; | |
743 | ||
744 | login->checked_for_existing = 1; | |
745 | ||
746 | if (!login->tsih) | |
747 | return iscsi_check_for_session_reinstatement(conn); | |
748 | else | |
749 | return iscsi_login_post_auth_non_zero_tsih(conn, login->cid, | |
750 | login->initial_exp_statsn); | |
751 | } | |
752 | ||
753 | static int iscsi_target_do_authentication( | |
754 | struct iscsi_conn *conn, | |
755 | struct iscsi_login *login) | |
756 | { | |
757 | int authret; | |
758 | u32 payload_length; | |
759 | struct iscsi_param *param; | |
760 | struct iscsi_login_req *login_req; | |
761 | struct iscsi_login_rsp *login_rsp; | |
762 | ||
763 | login_req = (struct iscsi_login_req *) login->req; | |
764 | login_rsp = (struct iscsi_login_rsp *) login->rsp; | |
765 | payload_length = ntoh24(login_req->dlength); | |
766 | ||
767 | param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); | |
768 | if (!param) | |
769 | return -1; | |
770 | ||
771 | authret = iscsi_handle_authentication( | |
772 | conn, | |
773 | login->req_buf, | |
774 | login->rsp_buf, | |
775 | payload_length, | |
776 | &login->rsp_length, | |
777 | param->value); | |
778 | switch (authret) { | |
779 | case 0: | |
780 | pr_debug("Received OK response" | |
781 | " from LIO Authentication, continuing.\n"); | |
782 | break; | |
783 | case 1: | |
784 | pr_debug("iSCSI security negotiation" | |
bfb9035c | 785 | " completed successfully.\n"); |
e48354ce NB |
786 | login->auth_complete = 1; |
787 | if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && | |
788 | (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { | |
789 | login_rsp->flags |= (ISCSI_FLAG_LOGIN_NEXT_STAGE1 | | |
790 | ISCSI_FLAG_LOGIN_TRANSIT); | |
791 | login->current_stage = 1; | |
792 | } | |
793 | return iscsi_target_check_for_existing_instances( | |
794 | conn, login); | |
795 | case 2: | |
796 | pr_err("Security negotiation" | |
797 | " failed.\n"); | |
798 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
799 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | |
800 | return -1; | |
801 | default: | |
802 | pr_err("Received unknown error %d from LIO" | |
803 | " Authentication\n", authret); | |
804 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
805 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | |
806 | return -1; | |
807 | } | |
808 | ||
809 | return 0; | |
810 | } | |
811 | ||
812 | static int iscsi_target_handle_csg_zero( | |
813 | struct iscsi_conn *conn, | |
814 | struct iscsi_login *login) | |
815 | { | |
816 | int ret; | |
817 | u32 payload_length; | |
818 | struct iscsi_param *param; | |
819 | struct iscsi_login_req *login_req; | |
820 | struct iscsi_login_rsp *login_rsp; | |
821 | ||
822 | login_req = (struct iscsi_login_req *) login->req; | |
823 | login_rsp = (struct iscsi_login_rsp *) login->rsp; | |
824 | payload_length = ntoh24(login_req->dlength); | |
825 | ||
826 | param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); | |
827 | if (!param) | |
828 | return -1; | |
829 | ||
830 | ret = iscsi_decode_text_input( | |
831 | PHASE_SECURITY|PHASE_DECLARATIVE, | |
832 | SENDER_INITIATOR|SENDER_RECEIVER, | |
833 | login->req_buf, | |
834 | payload_length, | |
9977bb18 | 835 | conn); |
e48354ce NB |
836 | if (ret < 0) |
837 | return -1; | |
838 | ||
839 | if (ret > 0) { | |
840 | if (login->auth_complete) { | |
841 | pr_err("Initiator has already been" | |
842 | " successfully authenticated, but is still" | |
843 | " sending %s keys.\n", param->value); | |
844 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
845 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
846 | return -1; | |
847 | } | |
848 | ||
849 | goto do_auth; | |
91f0abfd NB |
850 | } else if (!payload_length) { |
851 | pr_err("Initiator sent zero length security payload," | |
852 | " login failed\n"); | |
853 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
854 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | |
855 | return -1; | |
e48354ce NB |
856 | } |
857 | ||
858 | if (login->first_request) | |
859 | if (iscsi_target_check_first_request(conn, login) < 0) | |
860 | return -1; | |
861 | ||
862 | ret = iscsi_encode_text_output( | |
863 | PHASE_SECURITY|PHASE_DECLARATIVE, | |
864 | SENDER_TARGET, | |
865 | login->rsp_buf, | |
866 | &login->rsp_length, | |
138d351e NB |
867 | conn->param_list, |
868 | conn->tpg->tpg_attrib.login_keys_workaround); | |
e48354ce NB |
869 | if (ret < 0) |
870 | return -1; | |
871 | ||
872 | if (!iscsi_check_negotiated_keys(conn->param_list)) { | |
60bfcf8e | 873 | if (conn->tpg->tpg_attrib.authentication && |
e48354ce NB |
874 | !strncmp(param->value, NONE, 4)) { |
875 | pr_err("Initiator sent AuthMethod=None but" | |
876 | " Target is enforcing iSCSI Authentication," | |
877 | " login failed.\n"); | |
878 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
879 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | |
880 | return -1; | |
881 | } | |
882 | ||
60bfcf8e | 883 | if (conn->tpg->tpg_attrib.authentication && |
e48354ce NB |
884 | !login->auth_complete) |
885 | return 0; | |
886 | ||
887 | if (strncmp(param->value, NONE, 4) && !login->auth_complete) | |
888 | return 0; | |
889 | ||
890 | if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && | |
891 | (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { | |
892 | login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE1 | | |
893 | ISCSI_FLAG_LOGIN_TRANSIT; | |
894 | login->current_stage = 1; | |
895 | } | |
896 | } | |
897 | ||
898 | return 0; | |
899 | do_auth: | |
900 | return iscsi_target_do_authentication(conn, login); | |
901 | } | |
902 | ||
903 | static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_login *login) | |
904 | { | |
905 | int ret; | |
906 | u32 payload_length; | |
907 | struct iscsi_login_req *login_req; | |
908 | struct iscsi_login_rsp *login_rsp; | |
909 | ||
910 | login_req = (struct iscsi_login_req *) login->req; | |
911 | login_rsp = (struct iscsi_login_rsp *) login->rsp; | |
912 | payload_length = ntoh24(login_req->dlength); | |
913 | ||
914 | ret = iscsi_decode_text_input( | |
915 | PHASE_OPERATIONAL|PHASE_DECLARATIVE, | |
916 | SENDER_INITIATOR|SENDER_RECEIVER, | |
917 | login->req_buf, | |
918 | payload_length, | |
9977bb18 | 919 | conn); |
1c5c12c6 RD |
920 | if (ret < 0) { |
921 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
922 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
e48354ce | 923 | return -1; |
1c5c12c6 | 924 | } |
e48354ce NB |
925 | |
926 | if (login->first_request) | |
927 | if (iscsi_target_check_first_request(conn, login) < 0) | |
928 | return -1; | |
929 | ||
930 | if (iscsi_target_check_for_existing_instances(conn, login) < 0) | |
931 | return -1; | |
932 | ||
933 | ret = iscsi_encode_text_output( | |
934 | PHASE_OPERATIONAL|PHASE_DECLARATIVE, | |
935 | SENDER_TARGET, | |
936 | login->rsp_buf, | |
937 | &login->rsp_length, | |
138d351e NB |
938 | conn->param_list, |
939 | conn->tpg->tpg_attrib.login_keys_workaround); | |
1c5c12c6 RD |
940 | if (ret < 0) { |
941 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
942 | ISCSI_LOGIN_STATUS_INIT_ERR); | |
e48354ce | 943 | return -1; |
1c5c12c6 | 944 | } |
e48354ce NB |
945 | |
946 | if (!login->auth_complete && | |
60bfcf8e | 947 | conn->tpg->tpg_attrib.authentication) { |
e48354ce NB |
948 | pr_err("Initiator is requesting CSG: 1, has not been" |
949 | " successfully authenticated, and the Target is" | |
950 | " enforcing iSCSI Authentication, login failed.\n"); | |
951 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
952 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | |
953 | return -1; | |
954 | } | |
955 | ||
956 | if (!iscsi_check_negotiated_keys(conn->param_list)) | |
957 | if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE3) && | |
958 | (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) | |
959 | login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE3 | | |
960 | ISCSI_FLAG_LOGIN_TRANSIT; | |
961 | ||
962 | return 0; | |
963 | } | |
964 | ||
965 | static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *login) | |
966 | { | |
967 | int pdu_count = 0; | |
968 | struct iscsi_login_req *login_req; | |
969 | struct iscsi_login_rsp *login_rsp; | |
970 | ||
971 | login_req = (struct iscsi_login_req *) login->req; | |
972 | login_rsp = (struct iscsi_login_rsp *) login->rsp; | |
973 | ||
974 | while (1) { | |
975 | if (++pdu_count > MAX_LOGIN_PDUS) { | |
976 | pr_err("MAX_LOGIN_PDUS count reached.\n"); | |
977 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
978 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | |
979 | return -1; | |
980 | } | |
981 | ||
5d358065 | 982 | switch (ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)) { |
e48354ce | 983 | case 0: |
5d358065 | 984 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK; |
e48354ce NB |
985 | if (iscsi_target_handle_csg_zero(conn, login) < 0) |
986 | return -1; | |
987 | break; | |
988 | case 1: | |
989 | login_rsp->flags |= ISCSI_FLAG_LOGIN_CURRENT_STAGE1; | |
990 | if (iscsi_target_handle_csg_one(conn, login) < 0) | |
991 | return -1; | |
992 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | |
25cdda95 NB |
993 | /* |
994 | * Check to make sure the TCP connection has not | |
995 | * dropped asynchronously while session reinstatement | |
996 | * was occuring in this kthread context, before | |
997 | * transitioning to full feature phase operation. | |
998 | */ | |
999 | if (iscsi_target_sk_check_close(conn)) | |
1000 | return -1; | |
1001 | ||
e48354ce | 1002 | login->tsih = conn->sess->tsih; |
baa4d64b | 1003 | login->login_complete = 1; |
d381a801 | 1004 | iscsi_target_restore_sock_callbacks(conn); |
e48354ce NB |
1005 | if (iscsi_target_do_tx_login_io(conn, |
1006 | login) < 0) | |
1007 | return -1; | |
d381a801 | 1008 | return 1; |
e48354ce NB |
1009 | } |
1010 | break; | |
1011 | default: | |
1012 | pr_err("Illegal CSG: %d received from" | |
1013 | " Initiator, protocol error.\n", | |
5d358065 | 1014 | ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)); |
e48354ce NB |
1015 | break; |
1016 | } | |
1017 | ||
ea3a179a | 1018 | if (iscsi_target_do_tx_login_io(conn, login) < 0) |
e48354ce NB |
1019 | return -1; |
1020 | ||
1021 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | |
1022 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; | |
1023 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; | |
1024 | } | |
d381a801 | 1025 | break; |
e48354ce NB |
1026 | } |
1027 | ||
1028 | return 0; | |
1029 | } | |
1030 | ||
1031 | static void iscsi_initiatorname_tolower( | |
1032 | char *param_buf) | |
1033 | { | |
1034 | char *c; | |
1035 | u32 iqn_size = strlen(param_buf), i; | |
1036 | ||
1037 | for (i = 0; i < iqn_size; i++) { | |
8359cf43 | 1038 | c = ¶m_buf[i]; |
e48354ce NB |
1039 | if (!isupper(*c)) |
1040 | continue; | |
1041 | ||
1042 | *c = tolower(*c); | |
1043 | } | |
1044 | } | |
1045 | ||
1046 | /* | |
1047 | * Processes the first Login Request.. | |
1048 | */ | |
baa4d64b | 1049 | int iscsi_target_locate_portal( |
e48354ce NB |
1050 | struct iscsi_np *np, |
1051 | struct iscsi_conn *conn, | |
1052 | struct iscsi_login *login) | |
1053 | { | |
1054 | char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL; | |
1055 | char *tmpbuf, *start = NULL, *end = NULL, *key, *value; | |
1056 | struct iscsi_session *sess = conn->sess; | |
1057 | struct iscsi_tiqn *tiqn; | |
d381a801 | 1058 | struct iscsi_tpg_np *tpg_np = NULL; |
e48354ce | 1059 | struct iscsi_login_req *login_req; |
988e3a85 NB |
1060 | struct se_node_acl *se_nacl; |
1061 | u32 payload_length, queue_depth = 0; | |
1062 | int sessiontype = 0, ret = 0, tag_num, tag_size; | |
e48354ce | 1063 | |
d381a801 NB |
1064 | INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx); |
1065 | iscsi_target_set_sock_callbacks(conn); | |
1066 | ||
1067 | login->np = np; | |
1068 | ||
e48354ce | 1069 | login_req = (struct iscsi_login_req *) login->req; |
e48354ce NB |
1070 | payload_length = ntoh24(login_req->dlength); |
1071 | ||
e48354ce NB |
1072 | tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); |
1073 | if (!tmpbuf) { | |
1074 | pr_err("Unable to allocate memory for tmpbuf.\n"); | |
1075 | return -1; | |
1076 | } | |
1077 | ||
1078 | memcpy(tmpbuf, login->req_buf, payload_length); | |
1079 | tmpbuf[payload_length] = '\0'; | |
1080 | start = tmpbuf; | |
1081 | end = (start + payload_length); | |
1082 | ||
1083 | /* | |
1084 | * Locate the initial keys expected from the Initiator node in | |
1085 | * the first login request in order to progress with the login phase. | |
1086 | */ | |
1087 | while (start < end) { | |
1088 | if (iscsi_extract_key_value(start, &key, &value) < 0) { | |
1089 | ret = -1; | |
1090 | goto out; | |
1091 | } | |
1092 | ||
1093 | if (!strncmp(key, "InitiatorName", 13)) | |
1094 | i_buf = value; | |
1095 | else if (!strncmp(key, "SessionType", 11)) | |
1096 | s_buf = value; | |
1097 | else if (!strncmp(key, "TargetName", 10)) | |
1098 | t_buf = value; | |
1099 | ||
1100 | start += strlen(key) + strlen(value) + 2; | |
1101 | } | |
e48354ce NB |
1102 | /* |
1103 | * See 5.3. Login Phase. | |
1104 | */ | |
1105 | if (!i_buf) { | |
1106 | pr_err("InitiatorName key not received" | |
1107 | " in first login request.\n"); | |
1108 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
1109 | ISCSI_LOGIN_STATUS_MISSING_FIELDS); | |
1110 | ret = -1; | |
1111 | goto out; | |
1112 | } | |
1113 | /* | |
1114 | * Convert the incoming InitiatorName to lowercase following | |
1115 | * RFC-3720 3.2.6.1. section c) that says that iSCSI IQNs | |
1116 | * are NOT case sensitive. | |
1117 | */ | |
1118 | iscsi_initiatorname_tolower(i_buf); | |
1119 | ||
1120 | if (!s_buf) { | |
1121 | if (!login->leading_connection) | |
1122 | goto get_target; | |
1123 | ||
1124 | pr_err("SessionType key not received" | |
1125 | " in first login request.\n"); | |
1126 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
1127 | ISCSI_LOGIN_STATUS_MISSING_FIELDS); | |
1128 | ret = -1; | |
1129 | goto out; | |
1130 | } | |
1131 | ||
1132 | /* | |
1133 | * Use default portal group for discovery sessions. | |
1134 | */ | |
1135 | sessiontype = strncmp(s_buf, DISCOVERY, 9); | |
1136 | if (!sessiontype) { | |
1137 | conn->tpg = iscsit_global->discovery_tpg; | |
1138 | if (!login->leading_connection) | |
1139 | goto get_target; | |
1140 | ||
1141 | sess->sess_ops->SessionType = 1; | |
1142 | /* | |
1143 | * Setup crc32c modules from libcrypto | |
1144 | */ | |
1145 | if (iscsi_login_setup_crypto(conn) < 0) { | |
1146 | pr_err("iscsi_login_setup_crypto() failed\n"); | |
1147 | ret = -1; | |
1148 | goto out; | |
1149 | } | |
1150 | /* | |
1151 | * Serialize access across the discovery struct iscsi_portal_group to | |
1152 | * process login attempt. | |
1153 | */ | |
1154 | if (iscsit_access_np(np, conn->tpg) < 0) { | |
1155 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
1156 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | |
1157 | ret = -1; | |
1158 | goto out; | |
1159 | } | |
1160 | ret = 0; | |
988e3a85 | 1161 | goto alloc_tags; |
e48354ce NB |
1162 | } |
1163 | ||
1164 | get_target: | |
1165 | if (!t_buf) { | |
1166 | pr_err("TargetName key not received" | |
1167 | " in first login request while" | |
1168 | " SessionType=Normal.\n"); | |
1169 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
1170 | ISCSI_LOGIN_STATUS_MISSING_FIELDS); | |
1171 | ret = -1; | |
1172 | goto out; | |
1173 | } | |
1174 | ||
1175 | /* | |
1176 | * Locate Target IQN from Storage Node. | |
1177 | */ | |
1178 | tiqn = iscsit_get_tiqn_for_login(t_buf); | |
1179 | if (!tiqn) { | |
1180 | pr_err("Unable to locate Target IQN: %s in" | |
1181 | " Storage Node\n", t_buf); | |
1182 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
1183 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | |
1184 | ret = -1; | |
1185 | goto out; | |
1186 | } | |
1187 | pr_debug("Located Storage Object: %s\n", tiqn->tiqn); | |
1188 | ||
1189 | /* | |
1190 | * Locate Target Portal Group from Storage Node. | |
1191 | */ | |
d381a801 | 1192 | conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np); |
e48354ce NB |
1193 | if (!conn->tpg) { |
1194 | pr_err("Unable to locate Target Portal Group" | |
1195 | " on %s\n", tiqn->tiqn); | |
1196 | iscsit_put_tiqn_for_login(tiqn); | |
1197 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
1198 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | |
1199 | ret = -1; | |
1200 | goto out; | |
1201 | } | |
d381a801 | 1202 | conn->tpg_np = tpg_np; |
e48354ce NB |
1203 | pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); |
1204 | /* | |
1205 | * Setup crc32c modules from libcrypto | |
1206 | */ | |
1207 | if (iscsi_login_setup_crypto(conn) < 0) { | |
1208 | pr_err("iscsi_login_setup_crypto() failed\n"); | |
d381a801 NB |
1209 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); |
1210 | iscsit_put_tiqn_for_login(tiqn); | |
1211 | conn->tpg = NULL; | |
e48354ce NB |
1212 | ret = -1; |
1213 | goto out; | |
1214 | } | |
1215 | /* | |
1216 | * Serialize access across the struct iscsi_portal_group to | |
1217 | * process login attempt. | |
1218 | */ | |
1219 | if (iscsit_access_np(np, conn->tpg) < 0) { | |
d381a801 | 1220 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); |
e48354ce NB |
1221 | iscsit_put_tiqn_for_login(tiqn); |
1222 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
1223 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | |
e48354ce | 1224 | conn->tpg = NULL; |
d381a801 | 1225 | ret = -1; |
e48354ce NB |
1226 | goto out; |
1227 | } | |
1228 | ||
1229 | /* | |
1230 | * conn->sess->node_acl will be set when the referenced | |
1231 | * struct iscsi_session is located from received ISID+TSIH in | |
1232 | * iscsi_login_non_zero_tsih_s2(). | |
1233 | */ | |
1234 | if (!login->leading_connection) { | |
1235 | ret = 0; | |
1236 | goto out; | |
1237 | } | |
1238 | ||
1239 | /* | |
1240 | * This value is required in iscsi_login_zero_tsih_s2() | |
1241 | */ | |
1242 | sess->sess_ops->SessionType = 0; | |
1243 | ||
1244 | /* | |
1245 | * Locate incoming Initiator IQN reference from Storage Node. | |
1246 | */ | |
1247 | sess->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( | |
1248 | &conn->tpg->tpg_se_tpg, i_buf); | |
1249 | if (!sess->se_sess->se_node_acl) { | |
1250 | pr_err("iSCSI Initiator Node: %s is not authorized to" | |
1251 | " access iSCSI target portal group: %hu.\n", | |
1252 | i_buf, conn->tpg->tpgt); | |
1253 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | |
1254 | ISCSI_LOGIN_STATUS_TGT_FORBIDDEN); | |
1255 | ret = -1; | |
1256 | goto out; | |
1257 | } | |
988e3a85 NB |
1258 | se_nacl = sess->se_sess->se_node_acl; |
1259 | queue_depth = se_nacl->queue_depth; | |
1260 | /* | |
1261 | * Setup pre-allocated tags based upon allowed per NodeACL CmdSN | |
1262 | * depth for non immediate commands, plus extra tags for immediate | |
1263 | * commands. | |
1264 | * | |
1265 | * Also enforce a ISCSIT_MIN_TAGS to prevent unnecessary contention | |
1266 | * in per-cpu-ida tag allocation logic + small queue_depth. | |
1267 | */ | |
1268 | alloc_tags: | |
1269 | tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); | |
4a4caa29 | 1270 | tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; |
988e3a85 | 1271 | tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; |
e48354ce | 1272 | |
988e3a85 NB |
1273 | ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); |
1274 | if (ret < 0) { | |
1275 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | |
1276 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | |
1277 | ret = -1; | |
1278 | } | |
e48354ce NB |
1279 | out: |
1280 | kfree(tmpbuf); | |
1281 | return ret; | |
1282 | } | |
1283 | ||
e48354ce NB |
1284 | int iscsi_target_start_negotiation( |
1285 | struct iscsi_login *login, | |
1286 | struct iscsi_conn *conn) | |
1287 | { | |
baa4d64b | 1288 | int ret; |
e48354ce | 1289 | |
1efaa949 BVA |
1290 | if (conn->sock) { |
1291 | struct sock *sk = conn->sock->sk; | |
d381a801 | 1292 | |
1efaa949 BVA |
1293 | write_lock_bh(&sk->sk_callback_lock); |
1294 | set_bit(LOGIN_FLAGS_READY, &conn->login_flags); | |
25cdda95 | 1295 | set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); |
1efaa949 BVA |
1296 | write_unlock_bh(&sk->sk_callback_lock); |
1297 | } | |
25cdda95 NB |
1298 | /* |
1299 | * If iscsi_target_do_login returns zero to signal more PDU | |
1300 | * exchanges are required to complete the login, go ahead and | |
1301 | * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection | |
1302 | * is still active. | |
1303 | * | |
1304 | * Otherwise if TCP connection dropped asynchronously, go ahead | |
1305 | * and perform connection cleanup now. | |
1306 | */ | |
1efaa949 | 1307 | ret = iscsi_target_do_login(conn, login); |
25cdda95 NB |
1308 | if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) |
1309 | ret = -1; | |
1310 | ||
1efaa949 | 1311 | if (ret < 0) { |
d381a801 NB |
1312 | cancel_delayed_work_sync(&conn->login_work); |
1313 | iscsi_target_restore_sock_callbacks(conn); | |
e48354ce | 1314 | iscsi_remove_failed_auth_entry(conn); |
d381a801 NB |
1315 | } |
1316 | if (ret != 0) | |
1317 | iscsi_target_nego_release(conn); | |
e48354ce | 1318 | |
e48354ce NB |
1319 | return ret; |
1320 | } | |
1321 | ||
baa4d64b | 1322 | void iscsi_target_nego_release(struct iscsi_conn *conn) |
e48354ce | 1323 | { |
baa4d64b NB |
1324 | struct iscsi_login *login = conn->conn_login; |
1325 | ||
1326 | if (!login) | |
1327 | return; | |
1328 | ||
e48354ce NB |
1329 | kfree(login->req_buf); |
1330 | kfree(login->rsp_buf); | |
1331 | kfree(login); | |
baa4d64b NB |
1332 | |
1333 | conn->conn_login = NULL; | |
e48354ce | 1334 | } |