ctld: Convert struct ctld_connection to a C++ class

Note that some of the functions for handling iSCSI login, discovery,
and kernel handoff are now functions of this class as they are logical
operations on an iSCSI connection and need access to various members
of this class.

This also fixes some memory leaks as ctld_connection wasn't properly
torn down once a connection finishes.  These leaks were harmless in
practice since the ctld process exits after handling each connection.

Sponsored by:	Chelsio Communications
Pull Request:	https://github.com/freebsd/freebsd-src/pull/1794
This commit is contained in:
John Baldwin 2025-08-04 15:38:08 -04:00
parent c6f1e9b8a4
commit ed076901ec
5 changed files with 213 additions and 208 deletions

View file

@ -1753,22 +1753,18 @@ pdu_fail(const struct connection *conn __unused, const char *reason __unused)
{
}
static struct ctld_connection *
connection_new(struct portal *portal, int fd, const char *host,
const struct sockaddr *client_sa)
ctld_connection::ctld_connection(struct portal *portal, int fd,
const char *host, const struct sockaddr *client_sa) :
conn_portal(portal), conn_initiator_addr(host),
conn_initiator_sa(client_sa)
{
struct ctld_connection *conn;
connection_init(&conn, &conn_ops, proxy_mode);
conn.conn_socket = fd;
}
conn = reinterpret_cast<struct ctld_connection *>(calloc(1, sizeof(*conn)));
if (conn == NULL)
log_err(1, "calloc");
connection_init(&conn->conn, &conn_ops, proxy_mode);
conn->conn.conn_socket = fd;
conn->conn_portal = portal;
conn->conn_initiator_addr = checked_strdup(host);
conn->conn_initiator_sa = client_sa;
return (conn);
ctld_connection::~ctld_connection()
{
chap_delete(conn_chap);
}
bool
@ -2349,7 +2345,6 @@ static void
handle_connection(struct portal *portal, int fd,
const struct sockaddr *client_sa, bool dont_fork)
{
struct ctld_connection *conn;
struct portal_group *pg;
int error;
pid_t pid;
@ -2395,16 +2390,16 @@ handle_connection(struct portal *portal, int fd,
log_set_peer_addr(host);
setproctitle("%s", host);
conn = connection_new(portal, fd, host, client_sa);
ctld_connection conn(portal, fd, host, client_sa);
start_timer(conf->timeout(), true);
kernel_capsicate();
login(conn);
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
kernel_handoff(conn);
conn.login();
if (conn.session_type() == CONN_SESSION_TYPE_NORMAL) {
conn.kernel_handoff();
log_debugx("connection handed off to the kernel");
} else {
assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
discovery(conn);
assert(conn.session_type() == CONN_SESSION_TYPE_DISCOVERY);
conn.discovery();
}
log_debugx("nothing more to do; exiting");
exit(0);

View file

@ -533,22 +533,43 @@ private:
#define CONN_SESSION_TYPE_NORMAL 2
struct ctld_connection {
ctld_connection(struct portal *portal, int fd, const char *host,
const struct sockaddr *client_sa);
~ctld_connection();
int session_type() const { return conn_session_type; }
void login();
void discovery();
void kernel_handoff();
private:
void login_chap(struct auth_group *ag);
void login_negotiate_key(struct pdu *request, const char *name,
const char *value, bool skipped_security,
struct keys *response_keys);
bool login_portal_redirect(struct pdu *request);
bool login_target_redirect(struct pdu *request);
void login_negotiate(struct pdu *request);
void login_wait_transition();
bool discovery_target_filtered_out(const struct port *port) const;
struct connection conn;
struct portal *conn_portal;
const struct port *conn_port;
struct target *conn_target;
int conn_session_type;
char *conn_initiator_name;
char *conn_initiator_addr;
char *conn_initiator_alias;
struct portal *conn_portal = nullptr;
const struct port *conn_port = nullptr;
struct target *conn_target = nullptr;
int conn_session_type = CONN_SESSION_TYPE_NONE;
std::string conn_initiator_name;
std::string conn_initiator_addr;
std::string conn_initiator_alias;
uint8_t conn_initiator_isid[6];
const struct sockaddr *conn_initiator_sa;
int conn_max_recv_data_segment_limit;
int conn_max_send_data_segment_limit;
int conn_max_burst_limit;
int conn_first_burst_limit;
const char *conn_user;
struct chap *conn_chap;
const struct sockaddr *conn_initiator_sa = nullptr;
int conn_max_recv_data_segment_limit = 0;
int conn_max_send_data_segment_limit = 0;
int conn_max_burst_limit = 0;
int conn_first_burst_limit = 0;
std::string conn_user;
struct chap *conn_chap = nullptr;
};
extern int ctl_fd;
@ -564,7 +585,6 @@ bool option_new(nvlist_t *nvl,
const char *name, const char *value);
void kernel_init(void);
void kernel_handoff(struct ctld_connection *conn);
void kernel_capsicate(void);
#ifdef ICL_KERNEL_PROXY
@ -577,10 +597,6 @@ void kernel_send(struct pdu *pdu);
void kernel_receive(struct pdu *pdu);
#endif
void login(struct ctld_connection *conn);
void discovery(struct ctld_connection *conn);
void start_timer(int timeout, bool fatal = false);
void stop_timer();

View file

@ -144,9 +144,8 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
}
}
static bool
discovery_target_filtered_out(const struct ctld_connection *conn,
const struct port *port)
bool
ctld_connection::discovery_target_filtered_out(const struct port *port) const
{
const struct auth_group *ag;
const struct portal_group *pg;
@ -158,19 +157,19 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
ag = port->auth_group();
if (ag == nullptr)
ag = targ->auth_group();
pg = conn->conn_portal->portal_group();
pg = conn_portal->portal_group();
assert(pg->discovery_filter() != discovery_filter::UNKNOWN);
if (pg->discovery_filter() >= discovery_filter::PORTAL &&
!ag->initiator_permitted(conn->conn_initiator_sa)) {
!ag->initiator_permitted(conn_initiator_sa)) {
log_debugx("initiator does not match initiator portals "
"allowed for target \"%s\"; skipping", targ->name());
return (true);
}
if (pg->discovery_filter() >= discovery_filter::PORTAL_NAME &&
!ag->initiator_permitted(conn->conn_initiator_name)) {
!ag->initiator_permitted(conn_initiator_name)) {
log_debugx("initiator does not match initiator names "
"allowed for target \"%s\"; skipping", targ->name());
return (true);
@ -178,7 +177,7 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
if (pg->discovery_filter() >= discovery_filter::PORTAL_NAME_AUTH &&
ag->type() != auth_type::NO_AUTHENTICATION) {
if (conn->conn_chap == NULL) {
if (conn_chap == nullptr) {
assert(pg->discovery_auth_group()->type() ==
auth_type::NO_AUTHENTICATION);
@ -187,19 +186,20 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
return (true);
}
assert(conn->conn_user != NULL);
auth = ag->find_auth(conn->conn_user);
assert(!conn_user.empty());
auth = ag->find_auth(conn_user);
if (auth == NULL) {
log_debugx("CHAP user \"%s\" doesn't match target "
"\"%s\"; skipping", conn->conn_user, targ->name());
"\"%s\"; skipping", conn_user.c_str(),
targ->name());
return (true);
}
error = chap_authenticate(conn->conn_chap, auth->secret());
error = chap_authenticate(conn_chap, auth->secret());
if (error != 0) {
log_debugx("password for CHAP user \"%s\" doesn't "
"match target \"%s\"; skipping",
conn->conn_user, targ->name());
conn_user.c_str(), targ->name());
return (true);
}
}
@ -208,7 +208,7 @@ discovery_target_filtered_out(const struct ctld_connection *conn,
}
void
discovery(struct ctld_connection *conn)
ctld_connection::discovery()
{
struct pdu *request, *response;
struct keys *request_keys, *response_keys;
@ -216,10 +216,10 @@ discovery(struct ctld_connection *conn)
const struct portal_group *pg;
const char *send_targets;
pg = conn->conn_portal->portal_group();
pg = conn_portal->portal_group();
log_debugx("beginning discovery session; waiting for TextRequest PDU");
request_keys = text_read_request(&conn->conn, &request);
request_keys = text_read_request(&conn, &request);
send_targets = keys_find(request_keys, "SendTargets");
if (send_targets == NULL)
@ -230,7 +230,7 @@ discovery(struct ctld_connection *conn)
if (strcmp(send_targets, "All") == 0) {
for (const auto &kv : pg->ports()) {
port = kv.second;
if (discovery_target_filtered_out(conn, port)) {
if (discovery_target_filtered_out(port)) {
/* Ignore this target. */
continue;
}
@ -242,7 +242,7 @@ discovery(struct ctld_connection *conn)
log_debugx("initiator requested information on unknown "
"target \"%s\"; returning nothing", send_targets);
} else {
if (discovery_target_filtered_out(conn, port)) {
if (discovery_target_filtered_out(port)) {
/* Ignore this target. */
} else {
discovery_add_target(response_keys,
@ -257,7 +257,7 @@ discovery(struct ctld_connection *conn)
keys_delete(request_keys);
log_debugx("done sending targets; waiting for Logout PDU");
request = logout_receive(&conn->conn);
request = logout_receive(&conn);
response = logout_new_response(request);
pdu_send(response);

View file

@ -706,51 +706,51 @@ lun::kernel_remove() const
}
void
kernel_handoff(struct ctld_connection *conn)
ctld_connection::kernel_handoff()
{
struct portal_group *pg = conn->conn_portal->portal_group();
struct portal_group *pg = conn_portal->portal_group();
struct ctl_iscsi req;
bzero(&req, sizeof(req));
req.type = CTL_ISCSI_HANDOFF;
strlcpy(req.data.handoff.initiator_name,
conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
strlcpy(req.data.handoff.initiator_addr,
conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
if (conn->conn_initiator_alias != NULL) {
strlcpy(req.data.handoff.initiator_name, conn_initiator_name.c_str(),
sizeof(req.data.handoff.initiator_name));
strlcpy(req.data.handoff.initiator_addr, conn_initiator_addr.c_str(),
sizeof(req.data.handoff.initiator_addr));
if (!conn_initiator_alias.empty()) {
strlcpy(req.data.handoff.initiator_alias,
conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
conn_initiator_alias.c_str(),
sizeof(req.data.handoff.initiator_alias));
}
memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
memcpy(req.data.handoff.initiator_isid, conn_initiator_isid,
sizeof(req.data.handoff.initiator_isid));
strlcpy(req.data.handoff.target_name,
conn->conn_target->name(), sizeof(req.data.handoff.target_name));
strlcpy(req.data.handoff.target_name, conn_target->name(),
sizeof(req.data.handoff.target_name));
strlcpy(req.data.handoff.offload, pg->offload(),
sizeof(req.data.handoff.offload));
#ifdef ICL_KERNEL_PROXY
if (proxy_mode)
req.data.handoff.connection_id = conn->conn.conn_socket;
req.data.handoff.connection_id = conn.conn_socket;
else
req.data.handoff.socket = conn->conn.conn_socket;
req.data.handoff.socket = conn.conn_socket;
#else
req.data.handoff.socket = conn->conn.conn_socket;
req.data.handoff.socket = conn.conn_socket;
#endif
req.data.handoff.portal_group_tag = pg->tag();
if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C)
if (conn.conn_header_digest == CONN_DIGEST_CRC32C)
req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C)
if (conn.conn_data_digest == CONN_DIGEST_CRC32C)
req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
req.data.handoff.cmdsn = conn->conn.conn_cmdsn;
req.data.handoff.statsn = conn->conn.conn_statsn;
req.data.handoff.cmdsn = conn.conn_cmdsn;
req.data.handoff.statsn = conn.conn_statsn;
req.data.handoff.max_recv_data_segment_length =
conn->conn.conn_max_recv_data_segment_length;
conn.conn_max_recv_data_segment_length;
req.data.handoff.max_send_data_segment_length =
conn->conn.conn_max_send_data_segment_length;
req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length;
req.data.handoff.first_burst_length =
conn->conn.conn_first_burst_length;
req.data.handoff.immediate_data = conn->conn.conn_immediate_data;
conn.conn_max_send_data_segment_length;
req.data.handoff.max_burst_length = conn.conn_max_burst_length;
req.data.handoff.first_burst_length = conn.conn_first_burst_length;
req.data.handoff.immediate_data = conn.conn_immediate_data;
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
log_err(1, "error issuing CTL_ISCSI ioctl; "

View file

@ -454,8 +454,8 @@ login_send_chap_success(struct pdu *request,
pdu_delete(response);
}
static void
login_chap(struct ctld_connection *conn, struct auth_group *ag)
void
ctld_connection::login_chap(struct auth_group *ag)
{
std::string user;
const struct auth *auth;
@ -466,7 +466,7 @@ login_chap(struct ctld_connection *conn, struct auth_group *ag)
* Receive CHAP_A PDU.
*/
log_debugx("beginning CHAP authentication; waiting for CHAP_A");
request = login_receive_chap_a(&conn->conn);
request = login_receive_chap_a(&conn);
/*
* Generate the challenge.
@ -485,7 +485,7 @@ login_chap(struct ctld_connection *conn, struct auth_group *ag)
* Receive CHAP_N/CHAP_R PDU and authenticate.
*/
log_debugx("waiting for CHAP_N/CHAP_R");
request = login_receive_chap_r(&conn->conn, ag, chap, &auth, user);
request = login_receive_chap_r(&conn, ag, chap, &auth, user);
/*
* Yay, authentication succeeded!
@ -498,19 +498,18 @@ login_chap(struct ctld_connection *conn, struct auth_group *ag)
/*
* Leave username and CHAP information for discovery().
*/
conn->conn_user = checked_strdup(user.c_str());
conn->conn_chap = chap;
conn_user = user;
conn_chap = chap;
}
static void
login_negotiate_key(struct pdu *request, const char *name,
void
ctld_connection::login_negotiate_key(struct pdu *request, const char *name,
const char *value, bool skipped_security, struct keys *response_keys)
{
int which;
size_t tmp;
struct ctld_connection *conn;
conn = (struct ctld_connection *)request->pdu_connection;
assert(request->pdu_connection == &conn);
if (strcmp(name, "InitiatorName") == 0) {
if (!skipped_security)
@ -522,16 +521,14 @@ login_negotiate_key(struct pdu *request, const char *name,
if (!skipped_security)
log_errx(1, "initiator resent TargetName");
} else if (strcmp(name, "InitiatorAlias") == 0) {
if (conn->conn_initiator_alias != NULL)
free(conn->conn_initiator_alias);
conn->conn_initiator_alias = checked_strdup(value);
conn_initiator_alias = value;
} else if (strcmp(value, "Irrelevant") == 0) {
/* Ignore. */
} else if (strcmp(name, "HeaderDigest") == 0) {
/*
* We don't handle digests for discovery sessions.
*/
if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
if (conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
log_debugx("discovery session; digests disabled");
keys_add(response_keys, name, "None");
return;
@ -542,7 +539,7 @@ login_negotiate_key(struct pdu *request, const char *name,
case 1:
log_debugx("initiator prefers CRC32C "
"for header digest; we'll use it");
conn->conn.conn_header_digest = CONN_DIGEST_CRC32C;
conn.conn_header_digest = CONN_DIGEST_CRC32C;
keys_add(response_keys, name, "CRC32C");
break;
case 2:
@ -557,7 +554,7 @@ login_negotiate_key(struct pdu *request, const char *name,
break;
}
} else if (strcmp(name, "DataDigest") == 0) {
if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
if (conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
log_debugx("discovery session; digests disabled");
keys_add(response_keys, name, "None");
return;
@ -568,7 +565,7 @@ login_negotiate_key(struct pdu *request, const char *name,
case 1:
log_debugx("initiator prefers CRC32C "
"for data digest; we'll use it");
conn->conn.conn_data_digest = CONN_DIGEST_CRC32C;
conn.conn_data_digest = CONN_DIGEST_CRC32C;
keys_add(response_keys, name, "CRC32C");
break;
case 2:
@ -587,15 +584,15 @@ login_negotiate_key(struct pdu *request, const char *name,
} else if (strcmp(name, "InitialR2T") == 0) {
keys_add(response_keys, name, "Yes");
} else if (strcmp(name, "ImmediateData") == 0) {
if (conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
if (conn_session_type == CONN_SESSION_TYPE_DISCOVERY) {
log_debugx("discovery session; ImmediateData irrelevant");
keys_add(response_keys, name, "Irrelevant");
} else {
if (strcmp(value, "Yes") == 0) {
conn->conn.conn_immediate_data = true;
conn.conn_immediate_data = true;
keys_add(response_keys, name, "Yes");
} else {
conn->conn.conn_immediate_data = false;
conn.conn_immediate_data = false;
keys_add(response_keys, name, "No");
}
}
@ -613,25 +610,25 @@ login_negotiate_key(struct pdu *request, const char *name,
* our MaxRecvDataSegmentLength is not influenced by the
* initiator in any way.
*/
if ((int)tmp > conn->conn_max_send_data_segment_limit) {
if ((int)tmp > conn_max_send_data_segment_limit) {
log_debugx("capping MaxRecvDataSegmentLength "
"from %zd to %d", tmp,
conn->conn_max_send_data_segment_limit);
tmp = conn->conn_max_send_data_segment_limit;
conn_max_send_data_segment_limit);
tmp = conn_max_send_data_segment_limit;
}
conn->conn.conn_max_send_data_segment_length = tmp;
conn.conn_max_send_data_segment_length = tmp;
} else if (strcmp(name, "MaxBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
if (tmp <= 0) {
login_send_error(request, 0x02, 0x00);
log_errx(1, "received invalid MaxBurstLength");
}
if ((int)tmp > conn->conn_max_burst_limit) {
if ((int)tmp > conn_max_burst_limit) {
log_debugx("capping MaxBurstLength from %zd to %d",
tmp, conn->conn_max_burst_limit);
tmp = conn->conn_max_burst_limit;
tmp, conn_max_burst_limit);
tmp = conn_max_burst_limit;
}
conn->conn.conn_max_burst_length = tmp;
conn.conn_max_burst_length = tmp;
keys_add_int(response_keys, name, tmp);
} else if (strcmp(name, "FirstBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
@ -639,12 +636,12 @@ login_negotiate_key(struct pdu *request, const char *name,
login_send_error(request, 0x02, 0x00);
log_errx(1, "received invalid FirstBurstLength");
}
if ((int)tmp > conn->conn_first_burst_limit) {
if ((int)tmp > conn_first_burst_limit) {
log_debugx("capping FirstBurstLength from %zd to %d",
tmp, conn->conn_first_burst_limit);
tmp = conn->conn_first_burst_limit;
tmp, conn_first_burst_limit);
tmp = conn_first_burst_limit;
}
conn->conn.conn_first_burst_length = tmp;
conn.conn_first_burst_length = tmp;
keys_add_int(response_keys, name, tmp);
} else if (strcmp(name, "DefaultTime2Wait") == 0) {
keys_add(response_keys, name, value);
@ -696,12 +693,12 @@ login_redirect(struct pdu *request, const char *target_address)
keys_delete(response_keys);
}
static bool
login_portal_redirect(struct ctld_connection *conn, struct pdu *request)
bool
ctld_connection::login_portal_redirect(struct pdu *request)
{
const struct portal_group *pg;
pg = conn->conn_portal->portal_group();
pg = conn_portal->portal_group();
if (!pg->is_redirecting())
return (false);
@ -712,87 +709,84 @@ login_portal_redirect(struct ctld_connection *conn, struct pdu *request)
return (true);
}
static bool
login_target_redirect(struct ctld_connection *conn, struct pdu *request)
bool
ctld_connection::login_target_redirect(struct pdu *request)
{
const char *target_address;
assert(!conn->conn_portal->portal_group()->is_redirecting());
assert(!conn_portal->portal_group()->is_redirecting());
if (conn->conn_target == NULL)
if (conn_target == NULL)
return (false);
if (!conn->conn_target->has_redirection())
if (!conn_target->has_redirection())
return (false);
target_address = conn->conn_target->redirection();
target_address = conn_target->redirection();
log_debugx("target \"%s\" configured to redirect to %s",
conn->conn_target->name(), target_address);
conn_target->name(), target_address);
login_redirect(request, target_address);
return (true);
}
static void
login_negotiate(struct ctld_connection *conn, struct pdu *request)
void
ctld_connection::login_negotiate(struct pdu *request)
{
struct portal_group *pg = conn->conn_portal->portal_group();
struct portal_group *pg = conn_portal->portal_group();
struct pdu *response;
struct iscsi_bhs_login_response *bhslr2;
struct keys *request_keys, *response_keys;
int i;
bool redirected, skipped_security;
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
if (conn_session_type == CONN_SESSION_TYPE_NORMAL) {
/*
* Query the kernel for various size limits. In case of
* offload, it depends on hardware capabilities.
*/
assert(conn->conn_target != NULL);
conn->conn_max_recv_data_segment_limit = (1 << 24) - 1;
conn->conn_max_send_data_segment_limit = (1 << 24) - 1;
conn->conn_max_burst_limit = (1 << 24) - 1;
conn->conn_first_burst_limit = (1 << 24) - 1;
assert(conn_target != NULL);
conn_max_recv_data_segment_limit = (1 << 24) - 1;
conn_max_send_data_segment_limit = (1 << 24) - 1;
conn_max_burst_limit = (1 << 24) - 1;
conn_first_burst_limit = (1 << 24) - 1;
kernel_limits(pg->offload(),
conn->conn.conn_socket,
&conn->conn_max_recv_data_segment_limit,
&conn->conn_max_send_data_segment_limit,
&conn->conn_max_burst_limit,
&conn->conn_first_burst_limit);
conn.conn_socket,
&conn_max_recv_data_segment_limit,
&conn_max_send_data_segment_limit,
&conn_max_burst_limit,
&conn_first_burst_limit);
/* We expect legal, usable values at this point. */
assert(conn->conn_max_recv_data_segment_limit >= 512);
assert(conn->conn_max_recv_data_segment_limit < (1 << 24));
assert(conn->conn_max_send_data_segment_limit >= 512);
assert(conn->conn_max_send_data_segment_limit < (1 << 24));
assert(conn->conn_max_burst_limit >= 512);
assert(conn->conn_max_burst_limit < (1 << 24));
assert(conn->conn_first_burst_limit >= 512);
assert(conn->conn_first_burst_limit < (1 << 24));
assert(conn->conn_first_burst_limit <=
conn->conn_max_burst_limit);
assert(conn_max_recv_data_segment_limit >= 512);
assert(conn_max_recv_data_segment_limit < (1 << 24));
assert(conn_max_send_data_segment_limit >= 512);
assert(conn_max_send_data_segment_limit < (1 << 24));
assert(conn_max_burst_limit >= 512);
assert(conn_max_burst_limit < (1 << 24));
assert(conn_first_burst_limit >= 512);
assert(conn_first_burst_limit < (1 << 24));
assert(conn_first_burst_limit <= conn_max_burst_limit);
/*
* Limit default send length in case it won't be negotiated.
* We can't do it for other limits, since they may affect both
* sender and receiver operation, and we must obey defaults.
*/
if (conn->conn_max_send_data_segment_limit <
conn->conn.conn_max_send_data_segment_length) {
conn->conn.conn_max_send_data_segment_length =
conn->conn_max_send_data_segment_limit;
if (conn_max_send_data_segment_limit <
conn.conn_max_send_data_segment_length) {
conn.conn_max_send_data_segment_length =
conn_max_send_data_segment_limit;
}
} else {
conn->conn_max_recv_data_segment_limit =
MAX_DATA_SEGMENT_LENGTH;
conn->conn_max_send_data_segment_limit =
MAX_DATA_SEGMENT_LENGTH;
conn_max_recv_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
conn_max_send_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
}
if (request == NULL) {
log_debugx("beginning operational parameter negotiation; "
"waiting for Login PDU");
request = login_receive(&conn->conn, false);
request = login_receive(&conn, false);
skipped_security = false;
} else
skipped_security = true;
@ -803,7 +797,7 @@ login_negotiate(struct ctld_connection *conn, struct pdu *request)
* authentication, but MUST be accepted afterwards; that's
* why we're doing it here and not earlier.
*/
redirected = login_target_redirect(conn, request);
redirected = login_target_redirect(request);
if (redirected) {
log_debugx("initiator redirected; exiting");
exit(0);
@ -820,10 +814,10 @@ login_negotiate(struct ctld_connection *conn, struct pdu *request)
response_keys = keys_new();
if (skipped_security &&
conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
if (conn->conn_target->has_alias())
conn_session_type == CONN_SESSION_TYPE_NORMAL) {
if (conn_target->has_alias())
keys_add(response_keys,
"TargetAlias", conn->conn_target->alias());
"TargetAlias", conn_target->alias());
keys_add_int(response_keys, "TargetPortalGroupTag",
pg->tag());
}
@ -844,16 +838,15 @@ login_negotiate(struct ctld_connection *conn, struct pdu *request)
* pairs in the order they are in the request we might have ended up
* with illegal values here.
*/
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL &&
conn->conn.conn_first_burst_length >
conn->conn.conn_max_burst_length) {
if (conn_session_type == CONN_SESSION_TYPE_NORMAL &&
conn.conn_first_burst_length > conn.conn_max_burst_length) {
log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength");
}
conn->conn.conn_max_recv_data_segment_length =
conn->conn_max_recv_data_segment_limit;
conn.conn_max_recv_data_segment_length =
conn_max_recv_data_segment_limit;
keys_add_int(response_keys, "MaxRecvDataSegmentLength",
conn->conn.conn_max_recv_data_segment_length);
conn.conn_max_recv_data_segment_length);
log_debugx("operational parameter negotiation done; "
"transitioning to Full Feature Phase");
@ -866,14 +859,14 @@ login_negotiate(struct ctld_connection *conn, struct pdu *request)
keys_delete(request_keys);
}
static void
login_wait_transition(struct ctld_connection *conn)
void
ctld_connection::login_wait_transition()
{
struct pdu *request, *response;
struct iscsi_bhs_login_request *bhslr;
log_debugx("waiting for state transition request");
request = login_receive(&conn->conn, false);
request = login_receive(&conn, false);
bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0) {
login_send_error(request, 0x02, 0x00);
@ -887,11 +880,11 @@ login_wait_transition(struct ctld_connection *conn)
pdu_send(response);
pdu_delete(response);
login_negotiate(conn, NULL);
login_negotiate(nullptr);
}
void
login(struct ctld_connection *conn)
ctld_connection::login()
{
struct pdu *request, *response;
struct iscsi_bhs_login_request *bhslr;
@ -908,17 +901,17 @@ login(struct ctld_connection *conn)
* is required, or call appropriate authentication code.
*/
log_debugx("beginning Login Phase; waiting for Login PDU");
request = login_receive(&conn->conn, true);
request = login_receive(&conn, true);
bhslr = (struct iscsi_bhs_login_request *)request->pdu_bhs;
if (bhslr->bhslr_tsih != 0) {
login_send_error(request, 0x02, 0x0a);
log_errx(1, "received Login PDU with non-zero TSIH");
}
pg = conn->conn_portal->portal_group();
pg = conn_portal->portal_group();
memcpy(conn->conn_initiator_isid, bhslr->bhslr_isid,
sizeof(conn->conn_initiator_isid));
memcpy(conn_initiator_isid, bhslr->bhslr_isid,
sizeof(conn_initiator_isid));
/*
* XXX: Implement the C flag some day.
@ -926,7 +919,7 @@ login(struct ctld_connection *conn)
request_keys = keys_new();
keys_load_pdu(request_keys, request);
assert(conn->conn_initiator_name == NULL);
assert(conn_initiator_name.empty());
initiator_name = keys_find(request_keys, "InitiatorName");
if (initiator_name == NULL) {
login_send_error(request, 0x02, 0x07);
@ -936,11 +929,12 @@ login(struct ctld_connection *conn)
login_send_error(request, 0x02, 0x00);
log_errx(1, "received Login PDU with invalid InitiatorName");
}
conn->conn_initiator_name = checked_strdup(initiator_name);
log_set_peer_name(conn->conn_initiator_name);
setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
conn_initiator_name = initiator_name;
log_set_peer_name(conn_initiator_name.c_str());
setproctitle("%s (%s)", conn_initiator_addr.c_str(),
conn_initiator_name.c_str());
redirected = login_portal_redirect(conn, request);
redirected = login_portal_redirect(request);
if (redirected) {
log_debugx("initiator redirected; exiting");
exit(0);
@ -948,58 +942,58 @@ login(struct ctld_connection *conn)
initiator_alias = keys_find(request_keys, "InitiatorAlias");
if (initiator_alias != NULL)
conn->conn_initiator_alias = checked_strdup(initiator_alias);
conn_initiator_alias = initiator_alias;
assert(conn->conn_session_type == CONN_SESSION_TYPE_NONE);
assert(conn_session_type == CONN_SESSION_TYPE_NONE);
session_type = keys_find(request_keys, "SessionType");
if (session_type != NULL) {
if (strcmp(session_type, "Normal") == 0) {
conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
conn_session_type = CONN_SESSION_TYPE_NORMAL;
} else if (strcmp(session_type, "Discovery") == 0) {
conn->conn_session_type = CONN_SESSION_TYPE_DISCOVERY;
conn_session_type = CONN_SESSION_TYPE_DISCOVERY;
} else {
login_send_error(request, 0x02, 0x00);
log_errx(1, "received Login PDU with invalid "
"SessionType \"%s\"", session_type);
}
} else
conn->conn_session_type = CONN_SESSION_TYPE_NORMAL;
conn_session_type = CONN_SESSION_TYPE_NORMAL;
assert(conn->conn_target == NULL);
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
assert(conn_target == NULL);
if (conn_session_type == CONN_SESSION_TYPE_NORMAL) {
target_name = keys_find(request_keys, "TargetName");
if (target_name == NULL) {
login_send_error(request, 0x02, 0x07);
log_errx(1, "received Login PDU without TargetName");
}
conn->conn_port = pg->find_port(target_name);
if (conn->conn_port == NULL) {
conn_port = pg->find_port(target_name);
if (conn_port == NULL) {
login_send_error(request, 0x02, 0x03);
log_errx(1, "requested target \"%s\" not found",
target_name);
}
conn->conn_target = conn->conn_port->target();
conn_target = conn_port->target();
}
/*
* At this point we know what kind of authentication we need.
*/
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
ag = conn->conn_port->auth_group();
if (conn_session_type == CONN_SESSION_TYPE_NORMAL) {
ag = conn_port->auth_group();
if (ag == nullptr)
ag = conn->conn_target->auth_group();
if (conn->conn_port->auth_group() == nullptr &&
conn->conn_target->private_auth()) {
ag = conn_target->auth_group();
if (conn_port->auth_group() == nullptr &&
conn_target->private_auth()) {
log_debugx("initiator requests to connect "
"to target \"%s\"", conn->conn_target->name());
"to target \"%s\"", conn_target->name());
} else {
log_debugx("initiator requests to connect "
"to target \"%s\"; %s",
conn->conn_target->name(), ag->label());
conn_target->name(), ag->label());
}
} else {
assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
assert(conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
ag = pg->discovery_auth_group();
log_debugx("initiator requests discovery session; %s",
ag->label());
@ -1026,7 +1020,7 @@ login(struct ctld_connection *conn)
log_errx(1, "initiator does not match allowed initiator names");
}
if (!ag->initiator_permitted(conn->conn_initiator_sa)) {
if (!ag->initiator_permitted(conn_initiator_sa)) {
login_send_error(request, 0x02, 0x02);
log_errx(1, "initiator does not match allowed "
"initiator portals");
@ -1047,7 +1041,7 @@ login(struct ctld_connection *conn)
log_debugx("initiator skipped the authentication, "
"and we don't need it; proceeding with negotiation");
login_negotiate(conn, request);
login_negotiate(request);
return;
}
@ -1082,10 +1076,10 @@ login(struct ctld_connection *conn)
fail = true;
}
}
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
if (conn->conn_target->has_alias())
if (conn_session_type == CONN_SESSION_TYPE_NORMAL) {
if (conn_target->has_alias())
keys_add(response_keys,
"TargetAlias", conn->conn_target->alias());
"TargetAlias", conn_target->alias());
keys_add_int(response_keys,
"TargetPortalGroupTag", pg->tag());
}
@ -1103,11 +1097,11 @@ login(struct ctld_connection *conn)
}
if (ag->type() != auth_type::NO_AUTHENTICATION) {
login_chap(conn, ag);
login_negotiate(conn, NULL);
login_chap(ag);
login_negotiate(nullptr);
} else if (trans) {
login_negotiate(conn, NULL);
login_negotiate(nullptr);
} else {
login_wait_transition(conn);
login_wait_transition();
}
}