Commit 2f9bc894 authored by Nicholas Bellinger's avatar Nicholas Bellinger

iscsi-target: Fix discovery with INADDR_ANY and IN6ADDR_ANY_INIT

This patch addresses a bug with sendtargets discovery where INADDR_ANY (0.0.0.0)
+ IN6ADDR_ANY_INIT ([0:0:0:0:0:0:0:0]) network portals where incorrectly being
reported back to initiators instead of the address of the connecting interface.
To address this, save local socket ->getname() output during iscsi login setup,
and makes iscsit_build_sendtargets_response() return these TargetAddress keys
when INADDR_ANY or IN6ADDR_ANY_INIT portals are in use.
Reported-by: default avatarDax Kelson <dkelson@gurulabs.com>
Reported-by: default avatarAndy Grover <agrover@redhat.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 4949314c
...@@ -3164,6 +3164,30 @@ static int iscsit_send_task_mgt_rsp( ...@@ -3164,6 +3164,30 @@ static int iscsit_send_task_mgt_rsp(
return 0; return 0;
} }
static bool iscsit_check_inaddr_any(struct iscsi_np *np)
{
bool ret = false;
if (np->np_sockaddr.ss_family == AF_INET6) {
const struct sockaddr_in6 sin6 = {
.sin6_addr = IN6ADDR_ANY_INIT };
struct sockaddr_in6 *sock_in6 =
(struct sockaddr_in6 *)&np->np_sockaddr;
if (!memcmp(sock_in6->sin6_addr.s6_addr,
sin6.sin6_addr.s6_addr, 16))
ret = true;
} else {
struct sockaddr_in * sock_in =
(struct sockaddr_in *)&np->np_sockaddr;
if (sock_in->sin_addr.s_addr == INADDR_ANY)
ret = true;
}
return ret;
}
static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
{ {
char *payload = NULL; char *payload = NULL;
...@@ -3213,12 +3237,17 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) ...@@ -3213,12 +3237,17 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
spin_lock(&tpg->tpg_np_lock); spin_lock(&tpg->tpg_np_lock);
list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, list_for_each_entry(tpg_np, &tpg->tpg_gnp_list,
tpg_np_list) { tpg_np_list) {
struct iscsi_np *np = tpg_np->tpg_np;
bool inaddr_any = iscsit_check_inaddr_any(np);
len = sprintf(buf, "TargetAddress=" len = sprintf(buf, "TargetAddress="
"%s%s%s:%hu,%hu", "%s%s%s:%hu,%hu",
(tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? (np->np_sockaddr.ss_family == AF_INET6) ?
"[" : "", tpg_np->tpg_np->np_ip, "[" : "", (inaddr_any == false) ?
(tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? np->np_ip : conn->local_ip,
"]" : "", tpg_np->tpg_np->np_port, (np->np_sockaddr.ss_family == AF_INET6) ?
"]" : "", (inaddr_any == false) ?
np->np_port : conn->local_port,
tpg->tpgt); tpg->tpgt);
len += 1; len += 1;
......
...@@ -508,6 +508,7 @@ struct iscsi_conn { ...@@ -508,6 +508,7 @@ struct iscsi_conn {
u16 cid; u16 cid;
/* Remote TCP Port */ /* Remote TCP Port */
u16 login_port; u16 login_port;
u16 local_port;
int net_size; int net_size;
u32 auth_id; u32 auth_id;
#define CONNFLAG_SCTP_STRUCT_FILE 0x01 #define CONNFLAG_SCTP_STRUCT_FILE 0x01
...@@ -527,6 +528,7 @@ struct iscsi_conn { ...@@ -527,6 +528,7 @@ struct iscsi_conn {
unsigned char bad_hdr[ISCSI_HDR_LEN]; unsigned char bad_hdr[ISCSI_HDR_LEN];
#define IPV6_ADDRESS_SPACE 48 #define IPV6_ADDRESS_SPACE 48
unsigned char login_ip[IPV6_ADDRESS_SPACE]; unsigned char login_ip[IPV6_ADDRESS_SPACE];
unsigned char local_ip[IPV6_ADDRESS_SPACE];
int conn_usage_count; int conn_usage_count;
int conn_waiting_on_uc; int conn_waiting_on_uc;
atomic_t check_immediate_queue; atomic_t check_immediate_queue;
......
...@@ -615,8 +615,8 @@ static int iscsi_post_login_handler( ...@@ -615,8 +615,8 @@ static int iscsi_post_login_handler(
} }
pr_debug("iSCSI Login successful on CID: %hu from %s to" pr_debug("iSCSI Login successful on CID: %hu from %s to"
" %s:%hu,%hu\n", conn->cid, conn->login_ip, np->np_ip, " %s:%hu,%hu\n", conn->cid, conn->login_ip,
np->np_port, tpg->tpgt); conn->local_ip, conn->local_port, tpg->tpgt);
list_add_tail(&conn->conn_list, &sess->sess_conn_list); list_add_tail(&conn->conn_list, &sess->sess_conn_list);
atomic_inc(&sess->nconn); atomic_inc(&sess->nconn);
...@@ -658,7 +658,8 @@ static int iscsi_post_login_handler( ...@@ -658,7 +658,8 @@ static int iscsi_post_login_handler(
sess->session_state = TARG_SESS_STATE_LOGGED_IN; sess->session_state = TARG_SESS_STATE_LOGGED_IN;
pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n", pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n",
conn->cid, conn->login_ip, np->np_ip, np->np_port, tpg->tpgt); conn->cid, conn->login_ip, conn->local_ip, conn->local_port,
tpg->tpgt);
spin_lock_bh(&sess->conn_lock); spin_lock_bh(&sess->conn_lock);
list_add_tail(&conn->conn_list, &sess->sess_conn_list); list_add_tail(&conn->conn_list, &sess->sess_conn_list);
...@@ -1020,6 +1021,18 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) ...@@ -1020,6 +1021,18 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
&sock_in6.sin6_addr.in6_u); &sock_in6.sin6_addr.in6_u);
conn->login_port = ntohs(sock_in6.sin6_port); conn->login_port = ntohs(sock_in6.sin6_port);
if (conn->sock->ops->getname(conn->sock,
(struct sockaddr *)&sock_in6, &err, 0) < 0) {
pr_err("sock_ops->getname() failed.\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_TARGET_ERROR);
goto new_sess_out;
}
snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
&sock_in6.sin6_addr.in6_u);
conn->local_port = ntohs(sock_in6.sin6_port);
} else { } else {
memset(&sock_in, 0, sizeof(struct sockaddr_in)); memset(&sock_in, 0, sizeof(struct sockaddr_in));
...@@ -1032,6 +1045,16 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) ...@@ -1032,6 +1045,16 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
} }
sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr); sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
conn->login_port = ntohs(sock_in.sin_port); conn->login_port = ntohs(sock_in.sin_port);
if (conn->sock->ops->getname(conn->sock,
(struct sockaddr *)&sock_in, &err, 0) < 0) {
pr_err("sock_ops->getname() failed.\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_TARGET_ERROR);
goto new_sess_out;
}
sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
conn->local_port = ntohs(sock_in.sin_port);
} }
conn->network_transport = np->np_network_transport; conn->network_transport = np->np_network_transport;
...@@ -1039,7 +1062,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) ...@@ -1039,7 +1062,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
pr_debug("Received iSCSI login request from %s on %s Network" pr_debug("Received iSCSI login request from %s on %s Network"
" Portal %s:%hu\n", conn->login_ip, " Portal %s:%hu\n", conn->login_ip,
(conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP", (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
np->np_ip, np->np_port); conn->local_ip, conn->local_port);
pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
conn->conn_state = TARG_CONN_STATE_IN_LOGIN; conn->conn_state = TARG_CONN_STATE_IN_LOGIN;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment