in iscsi/iscsi_target_nego.c [1055:1286]
int iscsi_target_locate_portal(
struct iscsi_np *np,
struct iscsi_conn *conn,
struct iscsi_login *login)
{
char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL;
char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
struct iscsi_session *sess = conn->sess;
struct iscsi_tiqn *tiqn;
struct iscsi_tpg_np *tpg_np = NULL;
struct iscsi_login_req *login_req;
struct se_node_acl *se_nacl;
u32 payload_length, queue_depth = 0;
int sessiontype = 0, ret = 0, tag_num, tag_size;
INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx);
iscsi_target_set_sock_callbacks(conn);
login->np = np;
login_req = (struct iscsi_login_req *) login->req;
payload_length = ntoh24(login_req->dlength);
tmpbuf = kmemdup_nul(login->req_buf, payload_length, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate memory for tmpbuf.\n");
return -1;
}
start = tmpbuf;
end = (start + payload_length);
/*
* Locate the initial keys expected from the Initiator node in
* the first login request in order to progress with the login phase.
*/
while (start < end) {
if (iscsi_extract_key_value(start, &key, &value) < 0) {
ret = -1;
goto out;
}
if (!strncmp(key, "InitiatorName", 13))
i_buf = value;
else if (!strncmp(key, "SessionType", 11))
s_buf = value;
else if (!strncmp(key, "TargetName", 10))
t_buf = value;
start += strlen(key) + strlen(value) + 2;
}
/*
* See 5.3. Login Phase.
*/
if (!i_buf) {
pr_err("InitiatorName key not received"
" in first login request.\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
ISCSI_LOGIN_STATUS_MISSING_FIELDS);
ret = -1;
goto out;
}
/*
* Convert the incoming InitiatorName to lowercase following
* RFC-3720 3.2.6.1. section c) that says that iSCSI IQNs
* are NOT case sensitive.
*/
iscsi_initiatorname_tolower(i_buf);
if (!s_buf) {
if (!login->leading_connection)
goto get_target;
pr_err("SessionType key not received"
" in first login request.\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
ISCSI_LOGIN_STATUS_MISSING_FIELDS);
ret = -1;
goto out;
}
/*
* Use default portal group for discovery sessions.
*/
sessiontype = strncmp(s_buf, DISCOVERY, 9);
if (!sessiontype) {
conn->tpg = iscsit_global->discovery_tpg;
if (!login->leading_connection)
goto get_target;
sess->sess_ops->SessionType = 1;
/*
* Setup crc32c modules from libcrypto
*/
if (iscsi_login_setup_crypto(conn) < 0) {
pr_err("iscsi_login_setup_crypto() failed\n");
ret = -1;
goto out;
}
/*
* Serialize access across the discovery struct iscsi_portal_group to
* process login attempt.
*/
if (iscsit_access_np(np, conn->tpg) < 0) {
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
ret = -1;
goto out;
}
ret = 0;
goto alloc_tags;
}
get_target:
if (!t_buf) {
pr_err("TargetName key not received"
" in first login request while"
" SessionType=Normal.\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
ISCSI_LOGIN_STATUS_MISSING_FIELDS);
ret = -1;
goto out;
}
/*
* Locate Target IQN from Storage Node.
*/
tiqn = iscsit_get_tiqn_for_login(t_buf);
if (!tiqn) {
pr_err("Unable to locate Target IQN: %s in"
" Storage Node\n", t_buf);
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
ret = -1;
goto out;
}
pr_debug("Located Storage Object: %s\n", tiqn->tiqn);
/*
* Locate Target Portal Group from Storage Node.
*/
conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np);
if (!conn->tpg) {
pr_err("Unable to locate Target Portal Group"
" on %s\n", tiqn->tiqn);
iscsit_put_tiqn_for_login(tiqn);
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
ret = -1;
goto out;
}
conn->tpg_np = tpg_np;
pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt);
/*
* Setup crc32c modules from libcrypto
*/
if (iscsi_login_setup_crypto(conn) < 0) {
pr_err("iscsi_login_setup_crypto() failed\n");
kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
iscsit_put_tiqn_for_login(tiqn);
conn->tpg = NULL;
ret = -1;
goto out;
}
/*
* Serialize access across the struct iscsi_portal_group to
* process login attempt.
*/
if (iscsit_access_np(np, conn->tpg) < 0) {
kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
iscsit_put_tiqn_for_login(tiqn);
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
conn->tpg = NULL;
ret = -1;
goto out;
}
/*
* conn->sess->node_acl will be set when the referenced
* struct iscsi_session is located from received ISID+TSIH in
* iscsi_login_non_zero_tsih_s2().
*/
if (!login->leading_connection) {
ret = 0;
goto out;
}
/*
* This value is required in iscsi_login_zero_tsih_s2()
*/
sess->sess_ops->SessionType = 0;
/*
* Locate incoming Initiator IQN reference from Storage Node.
*/
sess->se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
&conn->tpg->tpg_se_tpg, i_buf);
if (!sess->se_sess->se_node_acl) {
pr_err("iSCSI Initiator Node: %s is not authorized to"
" access iSCSI target portal group: %hu.\n",
i_buf, conn->tpg->tpgt);
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
ISCSI_LOGIN_STATUS_TGT_FORBIDDEN);
ret = -1;
goto out;
}
se_nacl = sess->se_sess->se_node_acl;
queue_depth = se_nacl->queue_depth;
/*
* Setup pre-allocated tags based upon allowed per NodeACL CmdSN
* depth for non immediate commands, plus extra tags for immediate
* commands.
*
* Also enforce a ISCSIT_MIN_TAGS to prevent unnecessary contention
* in per-cpu-ida tag allocation logic + small queue_depth.
*/
alloc_tags:
tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS;
tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
if (ret < 0) {
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_NO_RESOURCES);
ret = -1;
}
out:
kfree(tmpbuf);
return ret;
}