18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/******************************************************************************* 38c2ecf20Sopenharmony_ci * This file contains main functions related to iSCSI Parameter negotiation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) Copyright 2007-2013 Datera, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci ******************************************************************************/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/ctype.h> 128c2ecf20Sopenharmony_ci#include <linux/kthread.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 158c2ecf20Sopenharmony_ci#include <net/sock.h> 168c2ecf20Sopenharmony_ci#include <scsi/iscsi_proto.h> 178c2ecf20Sopenharmony_ci#include <target/target_core_base.h> 188c2ecf20Sopenharmony_ci#include <target/target_core_fabric.h> 198c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_transport.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <target/iscsi/iscsi_target_core.h> 228c2ecf20Sopenharmony_ci#include "iscsi_target_parameters.h" 238c2ecf20Sopenharmony_ci#include "iscsi_target_login.h" 248c2ecf20Sopenharmony_ci#include "iscsi_target_nego.h" 258c2ecf20Sopenharmony_ci#include "iscsi_target_tpg.h" 268c2ecf20Sopenharmony_ci#include "iscsi_target_util.h" 278c2ecf20Sopenharmony_ci#include "iscsi_target.h" 288c2ecf20Sopenharmony_ci#include "iscsi_target_auth.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define MAX_LOGIN_PDUS 7 318c2ecf20Sopenharmony_ci#define TEXT_LEN 4096 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_civoid convert_null_to_semi(char *buf, int len) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci int i; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 388c2ecf20Sopenharmony_ci if (buf[i] == '\0') 398c2ecf20Sopenharmony_ci buf[i] = ';'; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int strlen_semi(char *buf) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int i = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci while (buf[i] != '\0') { 478c2ecf20Sopenharmony_ci if (buf[i] == ';') 488c2ecf20Sopenharmony_ci return i; 498c2ecf20Sopenharmony_ci i++; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return -1; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciint extract_param( 568c2ecf20Sopenharmony_ci const char *in_buf, 578c2ecf20Sopenharmony_ci const char *pattern, 588c2ecf20Sopenharmony_ci unsigned int max_length, 598c2ecf20Sopenharmony_ci char *out_buf, 608c2ecf20Sopenharmony_ci unsigned char *type) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci char *ptr; 638c2ecf20Sopenharmony_ci int len; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!in_buf || !pattern || !out_buf || !type) 668c2ecf20Sopenharmony_ci return -1; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ptr = strstr(in_buf, pattern); 698c2ecf20Sopenharmony_ci if (!ptr) 708c2ecf20Sopenharmony_ci return -1; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci ptr = strstr(ptr, "="); 738c2ecf20Sopenharmony_ci if (!ptr) 748c2ecf20Sopenharmony_ci return -1; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ptr += 1; 778c2ecf20Sopenharmony_ci if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) { 788c2ecf20Sopenharmony_ci ptr += 2; /* skip 0x */ 798c2ecf20Sopenharmony_ci *type = HEX; 808c2ecf20Sopenharmony_ci } else 818c2ecf20Sopenharmony_ci *type = DECIMAL; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci len = strlen_semi(ptr); 848c2ecf20Sopenharmony_ci if (len < 0) 858c2ecf20Sopenharmony_ci return -1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (len >= max_length) { 888c2ecf20Sopenharmony_ci pr_err("Length of input: %d exceeds max_length:" 898c2ecf20Sopenharmony_ci " %d\n", len, max_length); 908c2ecf20Sopenharmony_ci return -1; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci memcpy(out_buf, ptr, len); 938c2ecf20Sopenharmony_ci out_buf[len] = '\0'; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic u32 iscsi_handle_authentication( 998c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 1008c2ecf20Sopenharmony_ci char *in_buf, 1018c2ecf20Sopenharmony_ci char *out_buf, 1028c2ecf20Sopenharmony_ci int in_length, 1038c2ecf20Sopenharmony_ci int *out_length, 1048c2ecf20Sopenharmony_ci unsigned char *authtype) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct iscsi_session *sess = conn->sess; 1078c2ecf20Sopenharmony_ci struct iscsi_node_auth *auth; 1088c2ecf20Sopenharmony_ci struct iscsi_node_acl *iscsi_nacl; 1098c2ecf20Sopenharmony_ci struct iscsi_portal_group *iscsi_tpg; 1108c2ecf20Sopenharmony_ci struct se_node_acl *se_nacl; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!sess->sess_ops->SessionType) { 1138c2ecf20Sopenharmony_ci /* 1148c2ecf20Sopenharmony_ci * For SessionType=Normal 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci se_nacl = conn->sess->se_sess->se_node_acl; 1178c2ecf20Sopenharmony_ci if (!se_nacl) { 1188c2ecf20Sopenharmony_ci pr_err("Unable to locate struct se_node_acl for" 1198c2ecf20Sopenharmony_ci " CHAP auth\n"); 1208c2ecf20Sopenharmony_ci return -1; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, 1238c2ecf20Sopenharmony_ci se_node_acl); 1248c2ecf20Sopenharmony_ci if (!iscsi_nacl) { 1258c2ecf20Sopenharmony_ci pr_err("Unable to locate struct iscsi_node_acl for" 1268c2ecf20Sopenharmony_ci " CHAP auth\n"); 1278c2ecf20Sopenharmony_ci return -1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (se_nacl->dynamic_node_acl) { 1318c2ecf20Sopenharmony_ci iscsi_tpg = container_of(se_nacl->se_tpg, 1328c2ecf20Sopenharmony_ci struct iscsi_portal_group, tpg_se_tpg); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci auth = &iscsi_tpg->tpg_demo_auth; 1358c2ecf20Sopenharmony_ci } else { 1368c2ecf20Sopenharmony_ci iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, 1378c2ecf20Sopenharmony_ci se_node_acl); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci auth = &iscsi_nacl->node_auth; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * For SessionType=Discovery 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci auth = &iscsit_global->discovery_acl.node_auth; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (strstr("CHAP", authtype)) 1498c2ecf20Sopenharmony_ci strcpy(conn->sess->auth_type, "CHAP"); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci strcpy(conn->sess->auth_type, NONE); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (strstr("None", authtype)) 1548c2ecf20Sopenharmony_ci return 1; 1558c2ecf20Sopenharmony_ci else if (strstr("CHAP", authtype)) 1568c2ecf20Sopenharmony_ci return chap_main_loop(conn, auth, in_buf, out_buf, 1578c2ecf20Sopenharmony_ci &in_length, out_length); 1588c2ecf20Sopenharmony_ci /* SRP, SPKM1, SPKM2 and KRB5 are unsupported */ 1598c2ecf20Sopenharmony_ci return 2; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci kfree(conn->auth_protocol); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint iscsi_target_check_login_request( 1688c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 1698c2ecf20Sopenharmony_ci struct iscsi_login *login) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int req_csg, req_nsg; 1728c2ecf20Sopenharmony_ci u32 payload_length; 1738c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 1768c2ecf20Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci switch (login_req->opcode & ISCSI_OPCODE_MASK) { 1798c2ecf20Sopenharmony_ci case ISCSI_OP_LOGIN: 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci default: 1828c2ecf20Sopenharmony_ci pr_err("Received unknown opcode 0x%02x.\n", 1838c2ecf20Sopenharmony_ci login_req->opcode & ISCSI_OPCODE_MASK); 1848c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 1858c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 1868c2ecf20Sopenharmony_ci return -1; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if ((login_req->flags & ISCSI_FLAG_LOGIN_CONTINUE) && 1908c2ecf20Sopenharmony_ci (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { 1918c2ecf20Sopenharmony_ci pr_err("Login request has both ISCSI_FLAG_LOGIN_CONTINUE" 1928c2ecf20Sopenharmony_ci " and ISCSI_FLAG_LOGIN_TRANSIT set, protocol error.\n"); 1938c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 1948c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 1958c2ecf20Sopenharmony_ci return -1; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci req_csg = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags); 1998c2ecf20Sopenharmony_ci req_nsg = ISCSI_LOGIN_NEXT_STAGE(login_req->flags); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (req_csg != login->current_stage) { 2028c2ecf20Sopenharmony_ci pr_err("Initiator unexpectedly changed login stage" 2038c2ecf20Sopenharmony_ci " from %d to %d, login failed.\n", login->current_stage, 2048c2ecf20Sopenharmony_ci req_csg); 2058c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2068c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 2078c2ecf20Sopenharmony_ci return -1; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if ((req_nsg == 2) || (req_csg >= 2) || 2118c2ecf20Sopenharmony_ci ((login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 2128c2ecf20Sopenharmony_ci (req_nsg <= req_csg))) { 2138c2ecf20Sopenharmony_ci pr_err("Illegal login_req->flags Combination, CSG: %d," 2148c2ecf20Sopenharmony_ci " NSG: %d, ISCSI_FLAG_LOGIN_TRANSIT: %d.\n", req_csg, 2158c2ecf20Sopenharmony_ci req_nsg, (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)); 2168c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2178c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 2188c2ecf20Sopenharmony_ci return -1; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if ((login_req->max_version != login->version_max) || 2228c2ecf20Sopenharmony_ci (login_req->min_version != login->version_min)) { 2238c2ecf20Sopenharmony_ci pr_err("Login request changed Version Max/Nin" 2248c2ecf20Sopenharmony_ci " unexpectedly to 0x%02x/0x%02x, protocol error\n", 2258c2ecf20Sopenharmony_ci login_req->max_version, login_req->min_version); 2268c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2278c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 2288c2ecf20Sopenharmony_ci return -1; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (memcmp(login_req->isid, login->isid, 6) != 0) { 2328c2ecf20Sopenharmony_ci pr_err("Login request changed ISID unexpectedly," 2338c2ecf20Sopenharmony_ci " protocol error.\n"); 2348c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2358c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 2368c2ecf20Sopenharmony_ci return -1; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (login_req->itt != login->init_task_tag) { 2408c2ecf20Sopenharmony_ci pr_err("Login request changed ITT unexpectedly to" 2418c2ecf20Sopenharmony_ci " 0x%08x, protocol error.\n", login_req->itt); 2428c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2438c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 2448c2ecf20Sopenharmony_ci return -1; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (payload_length > MAX_KEY_VALUE_PAIRS) { 2488c2ecf20Sopenharmony_ci pr_err("Login request payload exceeds default" 2498c2ecf20Sopenharmony_ci " MaxRecvDataSegmentLength: %u, protocol error.\n", 2508c2ecf20Sopenharmony_ci MAX_KEY_VALUE_PAIRS); 2518c2ecf20Sopenharmony_ci return -1; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iscsi_target_check_login_request); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int iscsi_target_check_first_request( 2598c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 2608c2ecf20Sopenharmony_ci struct iscsi_login *login) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct iscsi_param *param = NULL; 2638c2ecf20Sopenharmony_ci struct se_node_acl *se_nacl; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci login->first_request = 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci list_for_each_entry(param, &conn->param_list->param_list, p_list) { 2688c2ecf20Sopenharmony_ci if (!strncmp(param->name, SESSIONTYPE, 11)) { 2698c2ecf20Sopenharmony_ci if (!IS_PSTATE_ACCEPTOR(param)) { 2708c2ecf20Sopenharmony_ci pr_err("SessionType key not received" 2718c2ecf20Sopenharmony_ci " in first login request.\n"); 2728c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2738c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 2748c2ecf20Sopenharmony_ci return -1; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci if (!strncmp(param->value, DISCOVERY, 9)) 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (!strncmp(param->name, INITIATORNAME, 13)) { 2818c2ecf20Sopenharmony_ci if (!IS_PSTATE_ACCEPTOR(param)) { 2828c2ecf20Sopenharmony_ci if (!login->leading_connection) 2838c2ecf20Sopenharmony_ci continue; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci pr_err("InitiatorName key not received" 2868c2ecf20Sopenharmony_ci " in first login request.\n"); 2878c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 2888c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 2898c2ecf20Sopenharmony_ci return -1; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * For non-leading connections, double check that the 2948c2ecf20Sopenharmony_ci * received InitiatorName matches the existing session's 2958c2ecf20Sopenharmony_ci * struct iscsi_node_acl. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci if (!login->leading_connection) { 2988c2ecf20Sopenharmony_ci se_nacl = conn->sess->se_sess->se_node_acl; 2998c2ecf20Sopenharmony_ci if (!se_nacl) { 3008c2ecf20Sopenharmony_ci pr_err("Unable to locate" 3018c2ecf20Sopenharmony_ci " struct se_node_acl\n"); 3028c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, 3038c2ecf20Sopenharmony_ci ISCSI_STATUS_CLS_INITIATOR_ERR, 3048c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); 3058c2ecf20Sopenharmony_ci return -1; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (strcmp(param->value, 3098c2ecf20Sopenharmony_ci se_nacl->initiatorname)) { 3108c2ecf20Sopenharmony_ci pr_err("Incorrect" 3118c2ecf20Sopenharmony_ci " InitiatorName: %s for this" 3128c2ecf20Sopenharmony_ci " iSCSI Initiator Node.\n", 3138c2ecf20Sopenharmony_ci param->value); 3148c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, 3158c2ecf20Sopenharmony_ci ISCSI_STATUS_CLS_INITIATOR_ERR, 3168c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); 3178c2ecf20Sopenharmony_ci return -1; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci u32 padding = 0; 3298c2ecf20Sopenharmony_ci struct iscsi_login_rsp *login_rsp; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci login_rsp = (struct iscsi_login_rsp *) login->rsp; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci login_rsp->opcode = ISCSI_OP_LOGIN_RSP; 3348c2ecf20Sopenharmony_ci hton24(login_rsp->dlength, login->rsp_length); 3358c2ecf20Sopenharmony_ci memcpy(login_rsp->isid, login->isid, 6); 3368c2ecf20Sopenharmony_ci login_rsp->tsih = cpu_to_be16(login->tsih); 3378c2ecf20Sopenharmony_ci login_rsp->itt = login->init_task_tag; 3388c2ecf20Sopenharmony_ci login_rsp->statsn = cpu_to_be32(conn->stat_sn++); 3398c2ecf20Sopenharmony_ci login_rsp->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); 3408c2ecf20Sopenharmony_ci login_rsp->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x," 3438c2ecf20Sopenharmony_ci " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:" 3448c2ecf20Sopenharmony_ci " %u\n", login_rsp->flags, (__force u32)login_rsp->itt, 3458c2ecf20Sopenharmony_ci ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn), 3468c2ecf20Sopenharmony_ci ntohl(login_rsp->statsn), login->rsp_length); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci padding = ((-login->rsp_length) & 3); 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * Before sending the last login response containing the transition 3518c2ecf20Sopenharmony_ci * bit for full-feature-phase, go ahead and start up TX/RX threads 3528c2ecf20Sopenharmony_ci * now to avoid potential resource allocation failures after the 3538c2ecf20Sopenharmony_ci * final login response has been sent. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci if (login->login_complete) { 3568c2ecf20Sopenharmony_ci int rc = iscsit_start_kthreads(conn); 3578c2ecf20Sopenharmony_ci if (rc) { 3588c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 3598c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 3608c2ecf20Sopenharmony_ci return -1; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (conn->conn_transport->iscsit_put_login_tx(conn, login, 3658c2ecf20Sopenharmony_ci login->rsp_length + padding) < 0) 3668c2ecf20Sopenharmony_ci goto err; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci login->rsp_length = 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cierr: 3738c2ecf20Sopenharmony_ci if (login->login_complete) { 3748c2ecf20Sopenharmony_ci if (conn->rx_thread && conn->rx_thread_active) { 3758c2ecf20Sopenharmony_ci send_sig(SIGINT, conn->rx_thread, 1); 3768c2ecf20Sopenharmony_ci complete(&conn->rx_login_comp); 3778c2ecf20Sopenharmony_ci kthread_stop(conn->rx_thread); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci if (conn->tx_thread && conn->tx_thread_active) { 3808c2ecf20Sopenharmony_ci send_sig(SIGINT, conn->tx_thread, 1); 3818c2ecf20Sopenharmony_ci kthread_stop(conn->tx_thread); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci spin_lock(&iscsit_global->ts_bitmap_lock); 3848c2ecf20Sopenharmony_ci bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, 3858c2ecf20Sopenharmony_ci get_order(1)); 3868c2ecf20Sopenharmony_ci spin_unlock(&iscsit_global->ts_bitmap_lock); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci return -1; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic void iscsi_target_sk_data_ready(struct sock *sk) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct iscsi_conn *conn = sk->sk_user_data; 3948c2ecf20Sopenharmony_ci bool rc; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 3998c2ecf20Sopenharmony_ci if (!sk->sk_user_data) { 4008c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4018c2ecf20Sopenharmony_ci return; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { 4048c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4058c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_READY=0, conn: %p >>>>\n", conn); 4068c2ecf20Sopenharmony_ci return; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { 4098c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4108c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_CLOSED=1, conn: %p >>>>\n", conn); 4118c2ecf20Sopenharmony_ci return; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { 4148c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4158c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn); 4168c2ecf20Sopenharmony_ci if (iscsi_target_sk_data_ready == conn->orig_data_ready) 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci conn->orig_data_ready(sk); 4198c2ecf20Sopenharmony_ci return; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci rc = schedule_delayed_work(&conn->login_work, 0); 4238c2ecf20Sopenharmony_ci if (!rc) { 4248c2ecf20Sopenharmony_ci pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" 4258c2ecf20Sopenharmony_ci " got false\n"); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void iscsi_target_sk_state_change(struct sock *); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct sock *sk; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (!conn->sock) 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci sk = conn->sock->sk; 4408c2ecf20Sopenharmony_ci pr_debug("Entering iscsi_target_set_sock_callbacks: conn: %p\n", conn); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 4438c2ecf20Sopenharmony_ci sk->sk_user_data = conn; 4448c2ecf20Sopenharmony_ci conn->orig_data_ready = sk->sk_data_ready; 4458c2ecf20Sopenharmony_ci conn->orig_state_change = sk->sk_state_change; 4468c2ecf20Sopenharmony_ci sk->sk_data_ready = iscsi_target_sk_data_ready; 4478c2ecf20Sopenharmony_ci sk->sk_state_change = iscsi_target_sk_state_change; 4488c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci sk->sk_sndtimeo = TA_LOGIN_TIMEOUT * HZ; 4518c2ecf20Sopenharmony_ci sk->sk_rcvtimeo = TA_LOGIN_TIMEOUT * HZ; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct sock *sk; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (!conn->sock) 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci sk = conn->sock->sk; 4628c2ecf20Sopenharmony_ci pr_debug("Entering iscsi_target_restore_sock_callbacks: conn: %p\n", conn); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 4658c2ecf20Sopenharmony_ci if (!sk->sk_user_data) { 4668c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4678c2ecf20Sopenharmony_ci return; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci sk->sk_user_data = NULL; 4708c2ecf20Sopenharmony_ci sk->sk_data_ready = conn->orig_data_ready; 4718c2ecf20Sopenharmony_ci sk->sk_state_change = conn->orig_state_change; 4728c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; 4758c2ecf20Sopenharmony_ci sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic bool __iscsi_target_sk_check_close(struct sock *sk) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { 4838c2ecf20Sopenharmony_ci pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," 4848c2ecf20Sopenharmony_ci "returning TRUE\n"); 4858c2ecf20Sopenharmony_ci return true; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci return false; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic bool iscsi_target_sk_check_close(struct iscsi_conn *conn) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci bool state = false; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (conn->sock) { 4958c2ecf20Sopenharmony_ci struct sock *sk = conn->sock->sk; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 4988c2ecf20Sopenharmony_ci state = (__iscsi_target_sk_check_close(sk) || 4998c2ecf20Sopenharmony_ci test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); 5008c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci return state; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci bool state = false; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (conn->sock) { 5108c2ecf20Sopenharmony_ci struct sock *sk = conn->sock->sk; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci read_lock_bh(&sk->sk_callback_lock); 5138c2ecf20Sopenharmony_ci state = test_bit(flag, &conn->login_flags); 5148c2ecf20Sopenharmony_ci read_unlock_bh(&sk->sk_callback_lock); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci return state; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci bool state = false; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (conn->sock) { 5248c2ecf20Sopenharmony_ci struct sock *sk = conn->sock->sk; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 5278c2ecf20Sopenharmony_ci state = (__iscsi_target_sk_check_close(sk) || 5288c2ecf20Sopenharmony_ci test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)); 5298c2ecf20Sopenharmony_ci if (!state) 5308c2ecf20Sopenharmony_ci clear_bit(flag, &conn->login_flags); 5318c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci return state; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci bool zero_tsih = login->zero_tsih; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci iscsi_remove_failed_auth_entry(conn); 5418c2ecf20Sopenharmony_ci iscsi_target_nego_release(conn); 5428c2ecf20Sopenharmony_ci iscsi_target_login_sess_out(conn, zero_tsih, true); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistruct conn_timeout { 5468c2ecf20Sopenharmony_ci struct timer_list timer; 5478c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void iscsi_target_login_timeout(struct timer_list *t) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct conn_timeout *timeout = from_timer(timeout, t, timer); 5538c2ecf20Sopenharmony_ci struct iscsi_conn *conn = timeout->conn; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (conn->login_kworker) { 5588c2ecf20Sopenharmony_ci pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", 5598c2ecf20Sopenharmony_ci conn->login_kworker->comm, conn->login_kworker->pid); 5608c2ecf20Sopenharmony_ci send_sig(SIGINT, conn->login_kworker, 1); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic void iscsi_target_do_login_rx(struct work_struct *work) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct iscsi_conn *conn = container_of(work, 5678c2ecf20Sopenharmony_ci struct iscsi_conn, login_work.work); 5688c2ecf20Sopenharmony_ci struct iscsi_login *login = conn->login; 5698c2ecf20Sopenharmony_ci struct iscsi_np *np = login->np; 5708c2ecf20Sopenharmony_ci struct iscsi_portal_group *tpg = conn->tpg; 5718c2ecf20Sopenharmony_ci struct iscsi_tpg_np *tpg_np = conn->tpg_np; 5728c2ecf20Sopenharmony_ci struct conn_timeout timeout; 5738c2ecf20Sopenharmony_ci int rc, zero_tsih = login->zero_tsih; 5748c2ecf20Sopenharmony_ci bool state; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", 5778c2ecf20Sopenharmony_ci conn, current->comm, current->pid); 5788c2ecf20Sopenharmony_ci /* 5798c2ecf20Sopenharmony_ci * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready() 5808c2ecf20Sopenharmony_ci * before initial PDU processing in iscsi_target_start_negotiation() 5818c2ecf20Sopenharmony_ci * has completed, go ahead and retry until it's cleared. 5828c2ecf20Sopenharmony_ci * 5838c2ecf20Sopenharmony_ci * Otherwise if the TCP connection drops while this is occuring, 5848c2ecf20Sopenharmony_ci * iscsi_target_start_negotiation() will detect the failure, call 5858c2ecf20Sopenharmony_ci * cancel_delayed_work_sync(&conn->login_work), and cleanup the 5868c2ecf20Sopenharmony_ci * remaining iscsi connection resources from iscsi_np process context. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci if (iscsi_target_sk_check_flag(conn, LOGIN_FLAGS_INITIAL_PDU)) { 5898c2ecf20Sopenharmony_ci schedule_delayed_work(&conn->login_work, msecs_to_jiffies(10)); 5908c2ecf20Sopenharmony_ci return; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock(&tpg->tpg_state_lock); 5948c2ecf20Sopenharmony_ci state = (tpg->tpg_state == TPG_STATE_ACTIVE); 5958c2ecf20Sopenharmony_ci spin_unlock(&tpg->tpg_state_lock); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (!state) { 5988c2ecf20Sopenharmony_ci pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); 5998c2ecf20Sopenharmony_ci goto err; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (iscsi_target_sk_check_close(conn)) { 6038c2ecf20Sopenharmony_ci pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); 6048c2ecf20Sopenharmony_ci goto err; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci conn->login_kworker = current; 6088c2ecf20Sopenharmony_ci allow_signal(SIGINT); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci timeout.conn = conn; 6118c2ecf20Sopenharmony_ci timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0); 6128c2ecf20Sopenharmony_ci mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ); 6138c2ecf20Sopenharmony_ci pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci rc = conn->conn_transport->iscsit_get_login_rx(conn, login); 6168c2ecf20Sopenharmony_ci del_timer_sync(&timeout.timer); 6178c2ecf20Sopenharmony_ci destroy_timer_on_stack(&timeout.timer); 6188c2ecf20Sopenharmony_ci flush_signals(current); 6198c2ecf20Sopenharmony_ci conn->login_kworker = NULL; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (rc < 0) 6228c2ecf20Sopenharmony_ci goto err; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", 6258c2ecf20Sopenharmony_ci conn, current->comm, current->pid); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* 6288c2ecf20Sopenharmony_ci * LOGIN_FLAGS_READ_ACTIVE is cleared so that sk_data_ready 6298c2ecf20Sopenharmony_ci * could be triggered again after this. 6308c2ecf20Sopenharmony_ci * 6318c2ecf20Sopenharmony_ci * LOGIN_FLAGS_WRITE_ACTIVE is cleared after we successfully 6328c2ecf20Sopenharmony_ci * process a login PDU, so that sk_state_chage can do login 6338c2ecf20Sopenharmony_ci * cleanup as needed if the socket is closed. If a delayed work is 6348c2ecf20Sopenharmony_ci * ongoing (LOGIN_FLAGS_WRITE_ACTIVE or LOGIN_FLAGS_READ_ACTIVE), 6358c2ecf20Sopenharmony_ci * sk_state_change will leave the cleanup to the delayed work or 6368c2ecf20Sopenharmony_ci * it will schedule a delayed work to do cleanup. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci if (conn->sock) { 6398c2ecf20Sopenharmony_ci struct sock *sk = conn->sock->sk; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 6428c2ecf20Sopenharmony_ci if (!test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags)) { 6438c2ecf20Sopenharmony_ci clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); 6448c2ecf20Sopenharmony_ci set_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci rc = iscsi_target_do_login(conn, login); 6508c2ecf20Sopenharmony_ci if (rc < 0) { 6518c2ecf20Sopenharmony_ci goto err; 6528c2ecf20Sopenharmony_ci } else if (!rc) { 6538c2ecf20Sopenharmony_ci if (iscsi_target_sk_check_and_clear(conn, 6548c2ecf20Sopenharmony_ci LOGIN_FLAGS_WRITE_ACTIVE)) 6558c2ecf20Sopenharmony_ci goto err; 6568c2ecf20Sopenharmony_ci } else if (rc == 1) { 6578c2ecf20Sopenharmony_ci cancel_delayed_work(&conn->login_work); 6588c2ecf20Sopenharmony_ci iscsi_target_nego_release(conn); 6598c2ecf20Sopenharmony_ci iscsi_post_login_handler(np, conn, zero_tsih); 6608c2ecf20Sopenharmony_ci iscsit_deaccess_np(np, tpg, tpg_np); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci return; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cierr: 6658c2ecf20Sopenharmony_ci iscsi_target_restore_sock_callbacks(conn); 6668c2ecf20Sopenharmony_ci cancel_delayed_work(&conn->login_work); 6678c2ecf20Sopenharmony_ci iscsi_target_login_drop(conn, login); 6688c2ecf20Sopenharmony_ci iscsit_deaccess_np(np, tpg, tpg_np); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic void iscsi_target_sk_state_change(struct sock *sk) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct iscsi_conn *conn; 6748c2ecf20Sopenharmony_ci void (*orig_state_change)(struct sock *); 6758c2ecf20Sopenharmony_ci bool state; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci pr_debug("Entering iscsi_target_sk_state_change\n"); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 6808c2ecf20Sopenharmony_ci conn = sk->sk_user_data; 6818c2ecf20Sopenharmony_ci if (!conn) { 6828c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 6838c2ecf20Sopenharmony_ci return; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci orig_state_change = conn->orig_state_change; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { 6888c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_READY=0 sk_state_change conn: %p\n", 6898c2ecf20Sopenharmony_ci conn); 6908c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 6918c2ecf20Sopenharmony_ci orig_state_change(sk); 6928c2ecf20Sopenharmony_ci return; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci state = __iscsi_target_sk_check_close(sk); 6958c2ecf20Sopenharmony_ci pr_debug("__iscsi_target_sk_close_change: state: %d\n", state); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags) || 6988c2ecf20Sopenharmony_ci test_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags)) { 6998c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_{READ|WRITE}_ACTIVE=1" 7008c2ecf20Sopenharmony_ci " sk_state_change conn: %p\n", conn); 7018c2ecf20Sopenharmony_ci if (state) 7028c2ecf20Sopenharmony_ci set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); 7038c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 7048c2ecf20Sopenharmony_ci orig_state_change(sk); 7058c2ecf20Sopenharmony_ci return; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { 7088c2ecf20Sopenharmony_ci pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n", 7098c2ecf20Sopenharmony_ci conn); 7108c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 7118c2ecf20Sopenharmony_ci orig_state_change(sk); 7128c2ecf20Sopenharmony_ci return; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * If the TCP connection has dropped, go ahead and set LOGIN_FLAGS_CLOSED, 7168c2ecf20Sopenharmony_ci * but only queue conn->login_work -> iscsi_target_do_login_rx() 7178c2ecf20Sopenharmony_ci * processing if LOGIN_FLAGS_INITIAL_PDU has already been cleared. 7188c2ecf20Sopenharmony_ci * 7198c2ecf20Sopenharmony_ci * When iscsi_target_do_login_rx() runs, iscsi_target_sk_check_close() 7208c2ecf20Sopenharmony_ci * will detect the dropped TCP connection from delayed workqueue context. 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * If LOGIN_FLAGS_INITIAL_PDU is still set, which means the initial 7238c2ecf20Sopenharmony_ci * iscsi_target_start_negotiation() is running, iscsi_target_do_login() 7248c2ecf20Sopenharmony_ci * via iscsi_target_sk_check_close() or iscsi_target_start_negotiation() 7258c2ecf20Sopenharmony_ci * via iscsi_target_sk_check_and_clear() is responsible for detecting the 7268c2ecf20Sopenharmony_ci * dropped TCP connection in iscsi_np process context, and cleaning up 7278c2ecf20Sopenharmony_ci * the remaining iscsi connection resources. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci if (state) { 7308c2ecf20Sopenharmony_ci pr_debug("iscsi_target_sk_state_change got failed state\n"); 7318c2ecf20Sopenharmony_ci set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); 7328c2ecf20Sopenharmony_ci state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); 7338c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci orig_state_change(sk); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (!state) 7388c2ecf20Sopenharmony_ci schedule_delayed_work(&conn->login_work, 0); 7398c2ecf20Sopenharmony_ci return; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci orig_state_change(sk); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/* 7478c2ecf20Sopenharmony_ci * NOTE: We check for existing sessions or connections AFTER the initiator 7488c2ecf20Sopenharmony_ci * has been successfully authenticated in order to protect against faked 7498c2ecf20Sopenharmony_ci * ISID/TSIH combinations. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_cistatic int iscsi_target_check_for_existing_instances( 7528c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 7538c2ecf20Sopenharmony_ci struct iscsi_login *login) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci if (login->checked_for_existing) 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci login->checked_for_existing = 1; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (!login->tsih) 7618c2ecf20Sopenharmony_ci return iscsi_check_for_session_reinstatement(conn); 7628c2ecf20Sopenharmony_ci else 7638c2ecf20Sopenharmony_ci return iscsi_login_post_auth_non_zero_tsih(conn, login->cid, 7648c2ecf20Sopenharmony_ci login->initial_exp_statsn); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic int iscsi_target_do_authentication( 7688c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 7698c2ecf20Sopenharmony_ci struct iscsi_login *login) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci int authret; 7728c2ecf20Sopenharmony_ci u32 payload_length; 7738c2ecf20Sopenharmony_ci struct iscsi_param *param; 7748c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 7758c2ecf20Sopenharmony_ci struct iscsi_login_rsp *login_rsp; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 7788c2ecf20Sopenharmony_ci login_rsp = (struct iscsi_login_rsp *) login->rsp; 7798c2ecf20Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); 7828c2ecf20Sopenharmony_ci if (!param) 7838c2ecf20Sopenharmony_ci return -1; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci authret = iscsi_handle_authentication( 7868c2ecf20Sopenharmony_ci conn, 7878c2ecf20Sopenharmony_ci login->req_buf, 7888c2ecf20Sopenharmony_ci login->rsp_buf, 7898c2ecf20Sopenharmony_ci payload_length, 7908c2ecf20Sopenharmony_ci &login->rsp_length, 7918c2ecf20Sopenharmony_ci param->value); 7928c2ecf20Sopenharmony_ci switch (authret) { 7938c2ecf20Sopenharmony_ci case 0: 7948c2ecf20Sopenharmony_ci pr_debug("Received OK response" 7958c2ecf20Sopenharmony_ci " from LIO Authentication, continuing.\n"); 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci case 1: 7988c2ecf20Sopenharmony_ci pr_debug("iSCSI security negotiation" 7998c2ecf20Sopenharmony_ci " completed successfully.\n"); 8008c2ecf20Sopenharmony_ci login->auth_complete = 1; 8018c2ecf20Sopenharmony_ci if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && 8028c2ecf20Sopenharmony_ci (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { 8038c2ecf20Sopenharmony_ci login_rsp->flags |= (ISCSI_FLAG_LOGIN_NEXT_STAGE1 | 8048c2ecf20Sopenharmony_ci ISCSI_FLAG_LOGIN_TRANSIT); 8058c2ecf20Sopenharmony_ci login->current_stage = 1; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci return iscsi_target_check_for_existing_instances( 8088c2ecf20Sopenharmony_ci conn, login); 8098c2ecf20Sopenharmony_ci case 2: 8108c2ecf20Sopenharmony_ci pr_err("Security negotiation" 8118c2ecf20Sopenharmony_ci " failed.\n"); 8128c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 8138c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_AUTH_FAILED); 8148c2ecf20Sopenharmony_ci return -1; 8158c2ecf20Sopenharmony_ci default: 8168c2ecf20Sopenharmony_ci pr_err("Received unknown error %d from LIO" 8178c2ecf20Sopenharmony_ci " Authentication\n", authret); 8188c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 8198c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_TARGET_ERROR); 8208c2ecf20Sopenharmony_ci return -1; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return 0; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int iscsi_target_handle_csg_zero( 8278c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 8288c2ecf20Sopenharmony_ci struct iscsi_login *login) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci int ret; 8318c2ecf20Sopenharmony_ci u32 payload_length; 8328c2ecf20Sopenharmony_ci struct iscsi_param *param; 8338c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 8348c2ecf20Sopenharmony_ci struct iscsi_login_rsp *login_rsp; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 8378c2ecf20Sopenharmony_ci login_rsp = (struct iscsi_login_rsp *) login->rsp; 8388c2ecf20Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); 8418c2ecf20Sopenharmony_ci if (!param) 8428c2ecf20Sopenharmony_ci return -1; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ret = iscsi_decode_text_input( 8458c2ecf20Sopenharmony_ci PHASE_SECURITY|PHASE_DECLARATIVE, 8468c2ecf20Sopenharmony_ci SENDER_INITIATOR|SENDER_RECEIVER, 8478c2ecf20Sopenharmony_ci login->req_buf, 8488c2ecf20Sopenharmony_ci payload_length, 8498c2ecf20Sopenharmony_ci conn); 8508c2ecf20Sopenharmony_ci if (ret < 0) 8518c2ecf20Sopenharmony_ci return -1; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (ret > 0) { 8548c2ecf20Sopenharmony_ci if (login->auth_complete) { 8558c2ecf20Sopenharmony_ci pr_err("Initiator has already been" 8568c2ecf20Sopenharmony_ci " successfully authenticated, but is still" 8578c2ecf20Sopenharmony_ci " sending %s keys.\n", param->value); 8588c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 8598c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 8608c2ecf20Sopenharmony_ci return -1; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci goto do_auth; 8648c2ecf20Sopenharmony_ci } else if (!payload_length) { 8658c2ecf20Sopenharmony_ci pr_err("Initiator sent zero length security payload," 8668c2ecf20Sopenharmony_ci " login failed\n"); 8678c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 8688c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_AUTH_FAILED); 8698c2ecf20Sopenharmony_ci return -1; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (login->first_request) 8738c2ecf20Sopenharmony_ci if (iscsi_target_check_first_request(conn, login) < 0) 8748c2ecf20Sopenharmony_ci return -1; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci ret = iscsi_encode_text_output( 8778c2ecf20Sopenharmony_ci PHASE_SECURITY|PHASE_DECLARATIVE, 8788c2ecf20Sopenharmony_ci SENDER_TARGET, 8798c2ecf20Sopenharmony_ci login->rsp_buf, 8808c2ecf20Sopenharmony_ci &login->rsp_length, 8818c2ecf20Sopenharmony_ci conn->param_list, 8828c2ecf20Sopenharmony_ci conn->tpg->tpg_attrib.login_keys_workaround); 8838c2ecf20Sopenharmony_ci if (ret < 0) 8848c2ecf20Sopenharmony_ci return -1; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (!iscsi_check_negotiated_keys(conn->param_list)) { 8878c2ecf20Sopenharmony_ci if (conn->tpg->tpg_attrib.authentication && 8888c2ecf20Sopenharmony_ci !strncmp(param->value, NONE, 4)) { 8898c2ecf20Sopenharmony_ci pr_err("Initiator sent AuthMethod=None but" 8908c2ecf20Sopenharmony_ci " Target is enforcing iSCSI Authentication," 8918c2ecf20Sopenharmony_ci " login failed.\n"); 8928c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 8938c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_AUTH_FAILED); 8948c2ecf20Sopenharmony_ci return -1; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (conn->tpg->tpg_attrib.authentication && 8988c2ecf20Sopenharmony_ci !login->auth_complete) 8998c2ecf20Sopenharmony_ci return 0; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (strncmp(param->value, NONE, 4) && !login->auth_complete) 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && 9058c2ecf20Sopenharmony_ci (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { 9068c2ecf20Sopenharmony_ci login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE1 | 9078c2ecf20Sopenharmony_ci ISCSI_FLAG_LOGIN_TRANSIT; 9088c2ecf20Sopenharmony_ci login->current_stage = 1; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_cido_auth: 9148c2ecf20Sopenharmony_ci return iscsi_target_do_authentication(conn, login); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_login *login) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci int ret; 9208c2ecf20Sopenharmony_ci u32 payload_length; 9218c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 9228c2ecf20Sopenharmony_ci struct iscsi_login_rsp *login_rsp; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 9258c2ecf20Sopenharmony_ci login_rsp = (struct iscsi_login_rsp *) login->rsp; 9268c2ecf20Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci ret = iscsi_decode_text_input( 9298c2ecf20Sopenharmony_ci PHASE_OPERATIONAL|PHASE_DECLARATIVE, 9308c2ecf20Sopenharmony_ci SENDER_INITIATOR|SENDER_RECEIVER, 9318c2ecf20Sopenharmony_ci login->req_buf, 9328c2ecf20Sopenharmony_ci payload_length, 9338c2ecf20Sopenharmony_ci conn); 9348c2ecf20Sopenharmony_ci if (ret < 0) { 9358c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 9368c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 9378c2ecf20Sopenharmony_ci return -1; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (login->first_request) 9418c2ecf20Sopenharmony_ci if (iscsi_target_check_first_request(conn, login) < 0) 9428c2ecf20Sopenharmony_ci return -1; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (iscsi_target_check_for_existing_instances(conn, login) < 0) 9458c2ecf20Sopenharmony_ci return -1; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = iscsi_encode_text_output( 9488c2ecf20Sopenharmony_ci PHASE_OPERATIONAL|PHASE_DECLARATIVE, 9498c2ecf20Sopenharmony_ci SENDER_TARGET, 9508c2ecf20Sopenharmony_ci login->rsp_buf, 9518c2ecf20Sopenharmony_ci &login->rsp_length, 9528c2ecf20Sopenharmony_ci conn->param_list, 9538c2ecf20Sopenharmony_ci conn->tpg->tpg_attrib.login_keys_workaround); 9548c2ecf20Sopenharmony_ci if (ret < 0) { 9558c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 9568c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_INIT_ERR); 9578c2ecf20Sopenharmony_ci return -1; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (!login->auth_complete && 9618c2ecf20Sopenharmony_ci conn->tpg->tpg_attrib.authentication) { 9628c2ecf20Sopenharmony_ci pr_err("Initiator is requesting CSG: 1, has not been" 9638c2ecf20Sopenharmony_ci " successfully authenticated, and the Target is" 9648c2ecf20Sopenharmony_ci " enforcing iSCSI Authentication, login failed.\n"); 9658c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 9668c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_AUTH_FAILED); 9678c2ecf20Sopenharmony_ci return -1; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (!iscsi_check_negotiated_keys(conn->param_list)) 9718c2ecf20Sopenharmony_ci if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE3) && 9728c2ecf20Sopenharmony_ci (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) 9738c2ecf20Sopenharmony_ci login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE3 | 9748c2ecf20Sopenharmony_ci ISCSI_FLAG_LOGIN_TRANSIT; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *login) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci int pdu_count = 0; 9828c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 9838c2ecf20Sopenharmony_ci struct iscsi_login_rsp *login_rsp; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 9868c2ecf20Sopenharmony_ci login_rsp = (struct iscsi_login_rsp *) login->rsp; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci while (1) { 9898c2ecf20Sopenharmony_ci if (++pdu_count > MAX_LOGIN_PDUS) { 9908c2ecf20Sopenharmony_ci pr_err("MAX_LOGIN_PDUS count reached.\n"); 9918c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 9928c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_TARGET_ERROR); 9938c2ecf20Sopenharmony_ci return -1; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci switch (ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)) { 9978c2ecf20Sopenharmony_ci case 0: 9988c2ecf20Sopenharmony_ci login_rsp->flags &= ~ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK; 9998c2ecf20Sopenharmony_ci if (iscsi_target_handle_csg_zero(conn, login) < 0) 10008c2ecf20Sopenharmony_ci return -1; 10018c2ecf20Sopenharmony_ci break; 10028c2ecf20Sopenharmony_ci case 1: 10038c2ecf20Sopenharmony_ci login_rsp->flags |= ISCSI_FLAG_LOGIN_CURRENT_STAGE1; 10048c2ecf20Sopenharmony_ci if (iscsi_target_handle_csg_one(conn, login) < 0) 10058c2ecf20Sopenharmony_ci return -1; 10068c2ecf20Sopenharmony_ci if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { 10078c2ecf20Sopenharmony_ci /* 10088c2ecf20Sopenharmony_ci * Check to make sure the TCP connection has not 10098c2ecf20Sopenharmony_ci * dropped asynchronously while session reinstatement 10108c2ecf20Sopenharmony_ci * was occuring in this kthread context, before 10118c2ecf20Sopenharmony_ci * transitioning to full feature phase operation. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_ci if (iscsi_target_sk_check_close(conn)) 10148c2ecf20Sopenharmony_ci return -1; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci login->tsih = conn->sess->tsih; 10178c2ecf20Sopenharmony_ci login->login_complete = 1; 10188c2ecf20Sopenharmony_ci iscsi_target_restore_sock_callbacks(conn); 10198c2ecf20Sopenharmony_ci if (iscsi_target_do_tx_login_io(conn, 10208c2ecf20Sopenharmony_ci login) < 0) 10218c2ecf20Sopenharmony_ci return -1; 10228c2ecf20Sopenharmony_ci return 1; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci default: 10268c2ecf20Sopenharmony_ci pr_err("Illegal CSG: %d received from" 10278c2ecf20Sopenharmony_ci " Initiator, protocol error.\n", 10288c2ecf20Sopenharmony_ci ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)); 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (iscsi_target_do_tx_login_io(conn, login) < 0) 10338c2ecf20Sopenharmony_ci return -1; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { 10368c2ecf20Sopenharmony_ci login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; 10378c2ecf20Sopenharmony_ci login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void iscsi_initiatorname_tolower( 10468c2ecf20Sopenharmony_ci char *param_buf) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci char *c; 10498c2ecf20Sopenharmony_ci u32 iqn_size = strlen(param_buf), i; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci for (i = 0; i < iqn_size; i++) { 10528c2ecf20Sopenharmony_ci c = ¶m_buf[i]; 10538c2ecf20Sopenharmony_ci if (!isupper(*c)) 10548c2ecf20Sopenharmony_ci continue; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci *c = tolower(*c); 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/* 10618c2ecf20Sopenharmony_ci * Processes the first Login Request.. 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ciint iscsi_target_locate_portal( 10648c2ecf20Sopenharmony_ci struct iscsi_np *np, 10658c2ecf20Sopenharmony_ci struct iscsi_conn *conn, 10668c2ecf20Sopenharmony_ci struct iscsi_login *login) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL; 10698c2ecf20Sopenharmony_ci char *tmpbuf, *start = NULL, *end = NULL, *key, *value; 10708c2ecf20Sopenharmony_ci struct iscsi_session *sess = conn->sess; 10718c2ecf20Sopenharmony_ci struct iscsi_tiqn *tiqn; 10728c2ecf20Sopenharmony_ci struct iscsi_tpg_np *tpg_np = NULL; 10738c2ecf20Sopenharmony_ci struct iscsi_login_req *login_req; 10748c2ecf20Sopenharmony_ci struct se_node_acl *se_nacl; 10758c2ecf20Sopenharmony_ci u32 payload_length, queue_depth = 0; 10768c2ecf20Sopenharmony_ci int sessiontype = 0, ret = 0, tag_num, tag_size; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx); 10798c2ecf20Sopenharmony_ci iscsi_target_set_sock_callbacks(conn); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci login->np = np; 10828c2ecf20Sopenharmony_ci conn->tpg = NULL; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci login_req = (struct iscsi_login_req *) login->req; 10858c2ecf20Sopenharmony_ci payload_length = ntoh24(login_req->dlength); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); 10888c2ecf20Sopenharmony_ci if (!tmpbuf) { 10898c2ecf20Sopenharmony_ci pr_err("Unable to allocate memory for tmpbuf.\n"); 10908c2ecf20Sopenharmony_ci return -1; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci memcpy(tmpbuf, login->req_buf, payload_length); 10948c2ecf20Sopenharmony_ci tmpbuf[payload_length] = '\0'; 10958c2ecf20Sopenharmony_ci start = tmpbuf; 10968c2ecf20Sopenharmony_ci end = (start + payload_length); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* 10998c2ecf20Sopenharmony_ci * Locate the initial keys expected from the Initiator node in 11008c2ecf20Sopenharmony_ci * the first login request in order to progress with the login phase. 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ci while (start < end) { 11038c2ecf20Sopenharmony_ci if (iscsi_extract_key_value(start, &key, &value) < 0) { 11048c2ecf20Sopenharmony_ci ret = -1; 11058c2ecf20Sopenharmony_ci goto out; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (!strncmp(key, "InitiatorName", 13)) 11098c2ecf20Sopenharmony_ci i_buf = value; 11108c2ecf20Sopenharmony_ci else if (!strncmp(key, "SessionType", 11)) 11118c2ecf20Sopenharmony_ci s_buf = value; 11128c2ecf20Sopenharmony_ci else if (!strncmp(key, "TargetName", 10)) 11138c2ecf20Sopenharmony_ci t_buf = value; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci start += strlen(key) + strlen(value) + 2; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci /* 11188c2ecf20Sopenharmony_ci * See 5.3. Login Phase. 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_ci if (!i_buf) { 11218c2ecf20Sopenharmony_ci pr_err("InitiatorName key not received" 11228c2ecf20Sopenharmony_ci " in first login request.\n"); 11238c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 11248c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 11258c2ecf20Sopenharmony_ci ret = -1; 11268c2ecf20Sopenharmony_ci goto out; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci /* 11298c2ecf20Sopenharmony_ci * Convert the incoming InitiatorName to lowercase following 11308c2ecf20Sopenharmony_ci * RFC-3720 3.2.6.1. section c) that says that iSCSI IQNs 11318c2ecf20Sopenharmony_ci * are NOT case sensitive. 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_ci iscsi_initiatorname_tolower(i_buf); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (!s_buf) { 11368c2ecf20Sopenharmony_ci if (!login->leading_connection) 11378c2ecf20Sopenharmony_ci goto get_target; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci pr_err("SessionType key not received" 11408c2ecf20Sopenharmony_ci " in first login request.\n"); 11418c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 11428c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 11438c2ecf20Sopenharmony_ci ret = -1; 11448c2ecf20Sopenharmony_ci goto out; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* 11488c2ecf20Sopenharmony_ci * Use default portal group for discovery sessions. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci sessiontype = strncmp(s_buf, DISCOVERY, 9); 11518c2ecf20Sopenharmony_ci if (!sessiontype) { 11528c2ecf20Sopenharmony_ci if (!login->leading_connection) 11538c2ecf20Sopenharmony_ci goto get_target; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci sess->sess_ops->SessionType = 1; 11568c2ecf20Sopenharmony_ci /* 11578c2ecf20Sopenharmony_ci * Setup crc32c modules from libcrypto 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci if (iscsi_login_setup_crypto(conn) < 0) { 11608c2ecf20Sopenharmony_ci pr_err("iscsi_login_setup_crypto() failed\n"); 11618c2ecf20Sopenharmony_ci ret = -1; 11628c2ecf20Sopenharmony_ci goto out; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci /* 11658c2ecf20Sopenharmony_ci * Serialize access across the discovery struct iscsi_portal_group to 11668c2ecf20Sopenharmony_ci * process login attempt. 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_ci conn->tpg = iscsit_global->discovery_tpg; 11698c2ecf20Sopenharmony_ci if (iscsit_access_np(np, conn->tpg) < 0) { 11708c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 11718c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 11728c2ecf20Sopenharmony_ci conn->tpg = NULL; 11738c2ecf20Sopenharmony_ci ret = -1; 11748c2ecf20Sopenharmony_ci goto out; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci ret = 0; 11778c2ecf20Sopenharmony_ci goto alloc_tags; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ciget_target: 11818c2ecf20Sopenharmony_ci if (!t_buf) { 11828c2ecf20Sopenharmony_ci pr_err("TargetName key not received" 11838c2ecf20Sopenharmony_ci " in first login request while" 11848c2ecf20Sopenharmony_ci " SessionType=Normal.\n"); 11858c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 11868c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_MISSING_FIELDS); 11878c2ecf20Sopenharmony_ci ret = -1; 11888c2ecf20Sopenharmony_ci goto out; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* 11928c2ecf20Sopenharmony_ci * Locate Target IQN from Storage Node. 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci tiqn = iscsit_get_tiqn_for_login(t_buf); 11958c2ecf20Sopenharmony_ci if (!tiqn) { 11968c2ecf20Sopenharmony_ci pr_err("Unable to locate Target IQN: %s in" 11978c2ecf20Sopenharmony_ci " Storage Node\n", t_buf); 11988c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 11998c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 12008c2ecf20Sopenharmony_ci ret = -1; 12018c2ecf20Sopenharmony_ci goto out; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci pr_debug("Located Storage Object: %s\n", tiqn->tiqn); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * Locate Target Portal Group from Storage Node. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np); 12098c2ecf20Sopenharmony_ci if (!conn->tpg) { 12108c2ecf20Sopenharmony_ci pr_err("Unable to locate Target Portal Group" 12118c2ecf20Sopenharmony_ci " on %s\n", tiqn->tiqn); 12128c2ecf20Sopenharmony_ci iscsit_put_tiqn_for_login(tiqn); 12138c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 12148c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 12158c2ecf20Sopenharmony_ci ret = -1; 12168c2ecf20Sopenharmony_ci goto out; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci conn->tpg_np = tpg_np; 12198c2ecf20Sopenharmony_ci pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); 12208c2ecf20Sopenharmony_ci /* 12218c2ecf20Sopenharmony_ci * Setup crc32c modules from libcrypto 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci if (iscsi_login_setup_crypto(conn) < 0) { 12248c2ecf20Sopenharmony_ci pr_err("iscsi_login_setup_crypto() failed\n"); 12258c2ecf20Sopenharmony_ci kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); 12268c2ecf20Sopenharmony_ci iscsit_put_tiqn_for_login(tiqn); 12278c2ecf20Sopenharmony_ci conn->tpg = NULL; 12288c2ecf20Sopenharmony_ci ret = -1; 12298c2ecf20Sopenharmony_ci goto out; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci /* 12328c2ecf20Sopenharmony_ci * Serialize access across the struct iscsi_portal_group to 12338c2ecf20Sopenharmony_ci * process login attempt. 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_ci if (iscsit_access_np(np, conn->tpg) < 0) { 12368c2ecf20Sopenharmony_ci kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); 12378c2ecf20Sopenharmony_ci iscsit_put_tiqn_for_login(tiqn); 12388c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 12398c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 12408c2ecf20Sopenharmony_ci conn->tpg = NULL; 12418c2ecf20Sopenharmony_ci ret = -1; 12428c2ecf20Sopenharmony_ci goto out; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * conn->sess->node_acl will be set when the referenced 12478c2ecf20Sopenharmony_ci * struct iscsi_session is located from received ISID+TSIH in 12488c2ecf20Sopenharmony_ci * iscsi_login_non_zero_tsih_s2(). 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci if (!login->leading_connection) { 12518c2ecf20Sopenharmony_ci ret = 0; 12528c2ecf20Sopenharmony_ci goto out; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* 12568c2ecf20Sopenharmony_ci * This value is required in iscsi_login_zero_tsih_s2() 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_ci sess->sess_ops->SessionType = 0; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * Locate incoming Initiator IQN reference from Storage Node. 12628c2ecf20Sopenharmony_ci */ 12638c2ecf20Sopenharmony_ci sess->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( 12648c2ecf20Sopenharmony_ci &conn->tpg->tpg_se_tpg, i_buf); 12658c2ecf20Sopenharmony_ci if (!sess->se_sess->se_node_acl) { 12668c2ecf20Sopenharmony_ci pr_err("iSCSI Initiator Node: %s is not authorized to" 12678c2ecf20Sopenharmony_ci " access iSCSI target portal group: %hu.\n", 12688c2ecf20Sopenharmony_ci i_buf, conn->tpg->tpgt); 12698c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 12708c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_TGT_FORBIDDEN); 12718c2ecf20Sopenharmony_ci ret = -1; 12728c2ecf20Sopenharmony_ci goto out; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci se_nacl = sess->se_sess->se_node_acl; 12758c2ecf20Sopenharmony_ci queue_depth = se_nacl->queue_depth; 12768c2ecf20Sopenharmony_ci /* 12778c2ecf20Sopenharmony_ci * Setup pre-allocated tags based upon allowed per NodeACL CmdSN 12788c2ecf20Sopenharmony_ci * depth for non immediate commands, plus extra tags for immediate 12798c2ecf20Sopenharmony_ci * commands. 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * Also enforce a ISCSIT_MIN_TAGS to prevent unnecessary contention 12828c2ecf20Sopenharmony_ci * in per-cpu-ida tag allocation logic + small queue_depth. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_cialloc_tags: 12858c2ecf20Sopenharmony_ci tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); 12868c2ecf20Sopenharmony_ci tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; 12878c2ecf20Sopenharmony_ci tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); 12908c2ecf20Sopenharmony_ci if (ret < 0) { 12918c2ecf20Sopenharmony_ci iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, 12928c2ecf20Sopenharmony_ci ISCSI_LOGIN_STATUS_NO_RESOURCES); 12938c2ecf20Sopenharmony_ci ret = -1; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ciout: 12968c2ecf20Sopenharmony_ci kfree(tmpbuf); 12978c2ecf20Sopenharmony_ci return ret; 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ciint iscsi_target_start_negotiation( 13018c2ecf20Sopenharmony_ci struct iscsi_login *login, 13028c2ecf20Sopenharmony_ci struct iscsi_conn *conn) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci int ret; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (conn->sock) { 13078c2ecf20Sopenharmony_ci struct sock *sk = conn->sock->sk; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 13108c2ecf20Sopenharmony_ci set_bit(LOGIN_FLAGS_READY, &conn->login_flags); 13118c2ecf20Sopenharmony_ci set_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags); 13128c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * If iscsi_target_do_login returns zero to signal more PDU 13168c2ecf20Sopenharmony_ci * exchanges are required to complete the login, go ahead and 13178c2ecf20Sopenharmony_ci * clear LOGIN_FLAGS_INITIAL_PDU but only if the TCP connection 13188c2ecf20Sopenharmony_ci * is still active. 13198c2ecf20Sopenharmony_ci * 13208c2ecf20Sopenharmony_ci * Otherwise if TCP connection dropped asynchronously, go ahead 13218c2ecf20Sopenharmony_ci * and perform connection cleanup now. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ci ret = iscsi_target_do_login(conn, login); 13248c2ecf20Sopenharmony_ci if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) 13258c2ecf20Sopenharmony_ci ret = -1; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (ret < 0) { 13288c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&conn->login_work); 13298c2ecf20Sopenharmony_ci iscsi_target_restore_sock_callbacks(conn); 13308c2ecf20Sopenharmony_ci iscsi_remove_failed_auth_entry(conn); 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci if (ret != 0) 13338c2ecf20Sopenharmony_ci iscsi_target_nego_release(conn); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return ret; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_civoid iscsi_target_nego_release(struct iscsi_conn *conn) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci struct iscsi_login *login = conn->conn_login; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (!login) 13438c2ecf20Sopenharmony_ci return; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci kfree(login->req_buf); 13468c2ecf20Sopenharmony_ci kfree(login->rsp_buf); 13478c2ecf20Sopenharmony_ci kfree(login); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci conn->conn_login = NULL; 13508c2ecf20Sopenharmony_ci} 1351