in iscsi/iscsi_target_login.c [1219:1429]
static int __iscsi_target_login_thread(struct iscsi_np *np)
{
u8 *buffer, zero_tsih = 0;
int ret = 0, rc;
struct iscsi_conn *conn = NULL;
struct iscsi_login *login;
struct iscsi_portal_group *tpg = NULL;
struct iscsi_login_req *pdu;
struct iscsi_tpg_np *tpg_np;
bool new_sess = false;
flush_signals(current);
spin_lock_bh(&np->np_thread_lock);
if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
return 1;
} else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) {
spin_unlock_bh(&np->np_thread_lock);
goto exit;
} else {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
}
spin_unlock_bh(&np->np_thread_lock);
conn = iscsit_alloc_conn(np);
if (!conn) {
/* Get another socket */
return 1;
}
rc = np->np_transport->iscsit_accept_np(np, conn);
if (rc == -ENOSYS) {
complete(&np->np_restart_comp);
iscsit_free_conn(conn);
goto exit;
} else if (rc < 0) {
spin_lock_bh(&np->np_thread_lock);
if (atomic_dec_if_positive(&np->np_reset_count) >= 0) {
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
spin_unlock_bh(&np->np_thread_lock);
complete(&np->np_restart_comp);
iscsit_free_conn(conn);
/* Get another socket */
return 1;
}
spin_unlock_bh(&np->np_thread_lock);
iscsit_free_conn(conn);
return 1;
}
/*
* Perform the remaining iSCSI connection initialization items..
*/
login = iscsi_login_init_conn(conn);
if (!login) {
goto new_sess_out;
}
iscsi_start_login_thread_timer(np);
pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
conn->conn_state = TARG_CONN_STATE_XPT_UP;
/*
* This will process the first login request + payload..
*/
rc = np->np_transport->iscsit_get_login_rx(conn, login);
if (rc == 1)
return 1;
else if (rc < 0)
goto new_sess_out;
buffer = &login->req[0];
pdu = (struct iscsi_login_req *)buffer;
/*
* Used by iscsit_tx_login_rsp() for Login Resonses PDUs
* when Status-Class != 0.
*/
conn->login_itt = pdu->itt;
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
spin_unlock_bh(&np->np_thread_lock);
pr_err("iSCSI Network Portal on %pISpc currently not"
" active.\n", &np->np_sockaddr);
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
goto new_sess_out;
}
spin_unlock_bh(&np->np_thread_lock);
conn->network_transport = np->np_network_transport;
pr_debug("Received iSCSI login request from %pISpc on %s Network"
" Portal %pISpc\n", &conn->login_sockaddr, np->np_transport->name,
&conn->local_sockaddr);
pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
conn->conn_state = TARG_CONN_STATE_IN_LOGIN;
if (iscsi_login_check_initiator_version(conn, pdu->max_version,
pdu->min_version) < 0)
goto new_sess_out;
zero_tsih = (pdu->tsih == 0x0000);
if (zero_tsih) {
/*
* This is the leading connection of a new session.
* We wait until after authentication to check for
* session reinstatement.
*/
if (iscsi_login_zero_tsih_s1(conn, buffer) < 0)
goto new_sess_out;
} else {
/*
* Add a new connection to an existing session.
* We check for a non-existant session in
* iscsi_login_non_zero_tsih_s2() below based
* on ISID/TSIH, but wait until after authentication
* to check for connection reinstatement, etc.
*/
if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
goto new_sess_out;
}
/*
* SessionType: Discovery
*
* Locates Default Portal
*
* SessionType: Normal
*
* Locates Target Portal from NP -> Target IQN
*/
rc = iscsi_target_locate_portal(np, conn, login);
if (rc < 0) {
tpg = conn->tpg;
goto new_sess_out;
}
login->zero_tsih = zero_tsih;
if (conn->sess)
conn->sess->se_sess->sup_prot_ops =
conn->conn_transport->iscsit_get_sup_prot_ops(conn);
tpg = conn->tpg;
if (!tpg) {
pr_err("Unable to locate struct iscsi_conn->tpg\n");
goto new_sess_out;
}
if (zero_tsih) {
if (iscsi_login_zero_tsih_s2(conn) < 0)
goto new_sess_out;
} else {
if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
goto old_sess_out;
}
if (conn->conn_transport->iscsit_validate_params) {
ret = conn->conn_transport->iscsit_validate_params(conn);
if (ret < 0) {
if (zero_tsih)
goto new_sess_out;
else
goto old_sess_out;
}
}
ret = iscsi_target_start_negotiation(login, conn);
if (ret < 0)
goto new_sess_out;
iscsi_stop_login_thread_timer(np);
if (ret == 1) {
tpg_np = conn->tpg_np;
iscsi_post_login_handler(np, conn, zero_tsih);
iscsit_deaccess_np(np, tpg, tpg_np);
}
tpg = NULL;
tpg_np = NULL;
/* Get another socket */
return 1;
new_sess_out:
new_sess = true;
old_sess_out:
iscsi_stop_login_thread_timer(np);
tpg_np = conn->tpg_np;
iscsi_target_login_sess_out(conn, zero_tsih, new_sess);
new_sess = false;
if (tpg) {
iscsit_deaccess_np(np, tpg, tpg_np);
tpg = NULL;
tpg_np = NULL;
}
return 1;
exit:
iscsi_stop_login_thread_timer(np);
spin_lock_bh(&np->np_thread_lock);
np->np_thread_state = ISCSI_NP_THREAD_EXIT;
spin_unlock_bh(&np->np_thread_lock);
return 0;
}