|
@@ -123,6 +123,10 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
|
123
|
123
|
__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
|
124
|
124
|
#define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
|
125
|
125
|
__einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
|
|
126
|
+#define EPROTO_INVALID_NOP_IN \
|
|
127
|
+ __einfo_error ( EINFO_EPROTO_INVALID_NOP_IN )
|
|
128
|
+#define EINFO_EPROTO_INVALID_NOP_IN \
|
|
129
|
+ __einfo_uniqify ( EINFO_EPROTO, 0x05, "Invalid NOP-In received" )
|
126
|
130
|
|
127
|
131
|
/** iSCSI initiator name (explicitly specified) */
|
128
|
132
|
static char *iscsi_explicit_initiator_iqn;
|
|
@@ -589,6 +593,50 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
|
589
|
593
|
return xfer_deliver_iob ( &iscsi->socket, iobuf );
|
590
|
594
|
}
|
591
|
595
|
|
|
596
|
+/**
|
|
597
|
+ * Receive data segment of an iSCSI NOP-In
|
|
598
|
+ *
|
|
599
|
+ * @v iscsi iSCSI session
|
|
600
|
+ * @v data Received data
|
|
601
|
+ * @v len Length of received data
|
|
602
|
+ * @v remaining Data remaining after this data
|
|
603
|
+ * @ret rc Return status code
|
|
604
|
+ */
|
|
605
|
+static int iscsi_rx_nop_in ( struct iscsi_session *iscsi,
|
|
606
|
+ const void *data __unused, size_t len __unused,
|
|
607
|
+ size_t remaining __unused ) {
|
|
608
|
+ struct iscsi_nop_in *nop_in = &iscsi->rx_bhs.nop_in;
|
|
609
|
+
|
|
610
|
+ DBGC2 ( iscsi, "iSCSI %p received NOP-In\n", iscsi );
|
|
611
|
+
|
|
612
|
+ /* RFC 3720 section 10.19 states that "when a target sends a
|
|
613
|
+ * NOP-In that is not a response to a Nop-Out received from
|
|
614
|
+ * the initiator, the Initiator Task Tag MUST be set to
|
|
615
|
+ * 0xffffffff", and section 10.18 states that "upon receipt of
|
|
616
|
+ * a NOP-In with the Target Transfer Tag set to a valid value
|
|
617
|
+ * (not the reserved 0xffffffff), the initiator MUST respond
|
|
618
|
+ * with a NOP-Out". Since we never send unsolicited NOP-Outs,
|
|
619
|
+ * my reading of this is that we can handle all permitted
|
|
620
|
+ * NOP-Ins (which must have ITT set to 0xffffffff) by simply
|
|
621
|
+ * ignoring them.
|
|
622
|
+ *
|
|
623
|
+ * There is some ambiguity in the RFC, since there are other
|
|
624
|
+ * places that suggest that a target is supposed to be able to
|
|
625
|
+ * send an unsolicited NOP-In and expect a NOP-Out response.
|
|
626
|
+ * We catch any apparent attempts to use this immediately, so
|
|
627
|
+ * that the relevant error gets reported to the iPXE user,
|
|
628
|
+ * rather than just having the target drop the connection when
|
|
629
|
+ * it times out waiting for the NOP-Out response.
|
|
630
|
+ */
|
|
631
|
+ if ( nop_in->itt != htonl ( ISCSI_TAG_RESERVED ) ) {
|
|
632
|
+ DBGC ( iscsi, "iSCSI %p received invalid NOP-In with ITT "
|
|
633
|
+ "%08x\n", iscsi, ntohl ( nop_in->itt ) );
|
|
634
|
+ return -EPROTO_INVALID_NOP_IN;
|
|
635
|
+ }
|
|
636
|
+
|
|
637
|
+ return 0;
|
|
638
|
+}
|
|
639
|
+
|
592
|
640
|
/****************************************************************************
|
593
|
641
|
*
|
594
|
642
|
* iSCSI login
|
|
@@ -1539,6 +1587,8 @@ static int iscsi_rx_data ( struct iscsi_session *iscsi, const void *data,
|
1539
|
1587
|
return iscsi_rx_data_in ( iscsi, data, len, remaining );
|
1540
|
1588
|
case ISCSI_OPCODE_R2T:
|
1541
|
1589
|
return iscsi_rx_r2t ( iscsi, data, len, remaining );
|
|
1590
|
+ case ISCSI_OPCODE_NOP_IN:
|
|
1591
|
+ return iscsi_rx_nop_in ( iscsi, data, len, remaining );
|
1542
|
1592
|
default:
|
1543
|
1593
|
if ( remaining )
|
1544
|
1594
|
return 0;
|