summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorMichael Brown2011-02-24 14:22:20 +0100
committerMichael Brown2011-02-24 14:25:32 +0100
commit711df439dfdc4abf88d335bc11d39adbf2bf67d4 (patch)
treecfcf832404bc337ae7f7e97f1490629afec45310 /src/net
parent[build] Use unique entry symbols for each prefix (diff)
downloadipxe-711df439dfdc4abf88d335bc11d39adbf2bf67d4.tar.gz
ipxe-711df439dfdc4abf88d335bc11d39adbf2bf67d4.tar.xz
ipxe-711df439dfdc4abf88d335bc11d39adbf2bf67d4.zip
[iscsi] Accept NOP-In PDUs sent by the target
Some iSCSI targets (observed with a Synology DS207+ NAS) send unsolicited NOP-Ins to the initiator. RFC 3720 is remarkably unclear and possibly self-contradictory on how NOPs are supposed to work, but it seems as though we can legitimately just ignore any unsolicited NOP-In PDU. Reported-by: Marc Lecuyer <marc@maxiscreen.com> Originally-implemented-by: Thomas Miletich <thomas.miletich@gmail.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/tcp/iscsi.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index 17cdaba24..6ef4c8968 100644
--- a/src/net/tcp/iscsi.c
+++ b/src/net/tcp/iscsi.c
@@ -123,6 +123,10 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
#define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
__einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
+#define EPROTO_INVALID_NOP_IN \
+ __einfo_error ( EINFO_EPROTO_INVALID_NOP_IN )
+#define EINFO_EPROTO_INVALID_NOP_IN \
+ __einfo_uniqify ( EINFO_EPROTO, 0x05, "Invalid NOP-In received" )
/** iSCSI initiator name (explicitly specified) */
static char *iscsi_explicit_initiator_iqn;
@@ -589,6 +593,50 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
return xfer_deliver_iob ( &iscsi->socket, iobuf );
}
+/**
+ * Receive data segment of an iSCSI NOP-In
+ *
+ * @v iscsi iSCSI session
+ * @v data Received data
+ * @v len Length of received data
+ * @v remaining Data remaining after this data
+ * @ret rc Return status code
+ */
+static int iscsi_rx_nop_in ( struct iscsi_session *iscsi,
+ const void *data __unused, size_t len __unused,
+ size_t remaining __unused ) {
+ struct iscsi_nop_in *nop_in = &iscsi->rx_bhs.nop_in;
+
+ DBGC2 ( iscsi, "iSCSI %p received NOP-In\n", iscsi );
+
+ /* RFC 3720 section 10.19 states that "when a target sends a
+ * NOP-In that is not a response to a Nop-Out received from
+ * the initiator, the Initiator Task Tag MUST be set to
+ * 0xffffffff", and section 10.18 states that "upon receipt of
+ * a NOP-In with the Target Transfer Tag set to a valid value
+ * (not the reserved 0xffffffff), the initiator MUST respond
+ * with a NOP-Out". Since we never send unsolicited NOP-Outs,
+ * my reading of this is that we can handle all permitted
+ * NOP-Ins (which must have ITT set to 0xffffffff) by simply
+ * ignoring them.
+ *
+ * There is some ambiguity in the RFC, since there are other
+ * places that suggest that a target is supposed to be able to
+ * send an unsolicited NOP-In and expect a NOP-Out response.
+ * We catch any apparent attempts to use this immediately, so
+ * that the relevant error gets reported to the iPXE user,
+ * rather than just having the target drop the connection when
+ * it times out waiting for the NOP-Out response.
+ */
+ if ( nop_in->itt != htonl ( ISCSI_TAG_RESERVED ) ) {
+ DBGC ( iscsi, "iSCSI %p received invalid NOP-In with ITT "
+ "%08x\n", iscsi, ntohl ( nop_in->itt ) );
+ return -EPROTO_INVALID_NOP_IN;
+ }
+
+ return 0;
+}
+
/****************************************************************************
*
* iSCSI login
@@ -1539,6 +1587,8 @@ static int iscsi_rx_data ( struct iscsi_session *iscsi, const void *data,
return iscsi_rx_data_in ( iscsi, data, len, remaining );
case ISCSI_OPCODE_R2T:
return iscsi_rx_r2t ( iscsi, data, len, remaining );
+ case ISCSI_OPCODE_NOP_IN:
+ return iscsi_rx_nop_in ( iscsi, data, len, remaining );
default:
if ( remaining )
return 0;