aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/ctld/login.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ctld/login.c')
-rw-r--r--usr.sbin/ctld/login.c69
1 files changed, 53 insertions, 16 deletions
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index 5216c7e8f853..5c3586821b2f 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -550,23 +550,32 @@ login_negotiate_key(struct pdu *request, const char *name,
log_errx(1, "received invalid "
"MaxRecvDataSegmentLength");
}
- if (tmp > conn->conn_data_segment_limit) {
- log_debugx("capping MaxRecvDataSegmentLength "
- "from %zd to %zd", tmp, conn->conn_data_segment_limit);
- tmp = conn->conn_data_segment_limit;
+
+ /*
+ * MaxRecvDataSegmentLength is a direction-specific parameter.
+ * We'll limit our _send_ to what the initiator can handle but
+ * our MaxRecvDataSegmentLength is not influenced by the
+ * initiator in any way.
+ */
+ if ((int)tmp > conn->conn_max_send_data_segment_length) {
+ log_debugx("capping max_send_data_segment_length "
+ "from %zd to %d", tmp,
+ conn->conn_max_send_data_segment_length);
+ tmp = conn->conn_max_send_data_segment_length;
}
- conn->conn_max_data_segment_length = tmp;
- keys_add_int(response_keys, name, conn->conn_data_segment_limit);
+ conn->conn_max_send_data_segment_length = tmp;
+ keys_add_int(response_keys, name,
+ conn->conn_max_recv_data_segment_length);
} 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 (tmp > MAX_BURST_LENGTH) {
+ if ((int)tmp > conn->conn_max_burst_length) {
log_debugx("capping MaxBurstLength from %zd to %d",
- tmp, MAX_BURST_LENGTH);
- tmp = MAX_BURST_LENGTH;
+ tmp, conn->conn_max_burst_length);
+ tmp = conn->conn_max_burst_length;
}
conn->conn_max_burst_length = tmp;
keys_add_int(response_keys, name, tmp);
@@ -576,10 +585,10 @@ login_negotiate_key(struct pdu *request, const char *name,
login_send_error(request, 0x02, 0x00);
log_errx(1, "received invalid FirstBurstLength");
}
- if (tmp > FIRST_BURST_LENGTH) {
+ if ((int)tmp > conn->conn_first_burst_length) {
log_debugx("capping FirstBurstLength from %zd to %d",
- tmp, FIRST_BURST_LENGTH);
- tmp = FIRST_BURST_LENGTH;
+ tmp, conn->conn_first_burst_length);
+ tmp = conn->conn_first_burst_length;
}
conn->conn_first_burst_length = tmp;
keys_add_int(response_keys, name, tmp);
@@ -681,14 +690,30 @@ login_negotiate(struct connection *conn, struct pdu *request)
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
/*
- * Query the kernel for MaxDataSegmentLength it can handle.
- * In case of offload, it depends on hardware capabilities.
+ * Query the kernel for various size limits. In case of
+ * offload, it depends on hardware capabilities.
*/
assert(conn->conn_target != NULL);
kernel_limits(conn->conn_portal->p_portal_group->pg_offload,
- &conn->conn_data_segment_limit);
+ &conn->conn_max_recv_data_segment_length,
+ &conn->conn_max_send_data_segment_length,
+ &conn->conn_max_burst_length,
+ &conn->conn_first_burst_length);
+
+ /* We expect legal, usable values at this point. */
+ assert(conn->conn_max_recv_data_segment_length >= 512);
+ assert(conn->conn_max_recv_data_segment_length < (1 << 24));
+ assert(conn->conn_max_burst_length >= 512);
+ assert(conn->conn_max_burst_length < (1 << 24));
+ assert(conn->conn_first_burst_length >= 512);
+ assert(conn->conn_first_burst_length < (1 << 24));
+ assert(conn->conn_first_burst_length <=
+ conn->conn_max_burst_length);
} else {
- conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
+ conn->conn_max_recv_data_segment_length =
+ MAX_DATA_SEGMENT_LENGTH;
+ conn->conn_max_send_data_segment_length =
+ MAX_DATA_SEGMENT_LENGTH;
}
if (request == NULL) {
@@ -739,6 +764,18 @@ login_negotiate(struct connection *conn, struct pdu *request)
response_keys);
}
+ /*
+ * We'd started with usable values at our end. But a bad initiator
+ * could have presented a large FirstBurstLength and then a smaller
+ * MaxBurstLength (in that order) and because we process the key/value
+ * 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_first_burst_length > conn->conn_max_burst_length) {
+ log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength");
+ }
+
log_debugx("operational parameter negotiation done; "
"transitioning to Full Feature Phase");