Quellcode durchsuchen

[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>
tags/v1.20.1
Michael Brown vor 13 Jahren
Ursprung
Commit
711df439df
2 geänderte Dateien mit 84 neuen und 0 gelöschten Zeilen
  1. 34
    0
      src/include/ipxe/iscsi.h
  2. 50
    0
      src/net/tcp/iscsi.c

+ 34
- 0
src/include/ipxe/iscsi.h Datei anzeigen

@@ -93,6 +93,9 @@ struct iscsi_bhs_common {
93 93
 /** iSCSI tag magic marker */
94 94
 #define ISCSI_TAG_MAGIC 0x18ae0000
95 95
 
96
+/** iSCSI reserved tag value */
97
+#define ISCSI_TAG_RESERVED 0xffffffff
98
+
96 99
 /**
97 100
  * iSCSI basic header segment common request fields
98 101
  *
@@ -455,6 +458,36 @@ struct iscsi_bhs_r2t {
455 458
 /** R2T opcode */
456 459
 #define ISCSI_OPCODE_R2T 0x31
457 460
 
461
+/**
462
+ * iSCSI NOP-In basic header segment
463
+ *
464
+ */
465
+struct iscsi_nop_in {
466
+	/** Opcode */
467
+	uint8_t opcode;
468
+	/** Reserved */
469
+	uint8_t reserved_a[3];
470
+	/** Segment lengths */
471
+	union iscsi_segment_lengths lengths;
472
+	/** Logical Unit Number */
473
+	struct scsi_lun lun;
474
+	/** Initiator Task Tag */
475
+	uint32_t itt;
476
+	/** Target Transfer Tag */
477
+	uint32_t ttt;
478
+	/** Status sequence number */
479
+	uint32_t statsn;
480
+	/** Expected command sequence number */
481
+	uint32_t expcmdsn;
482
+	/** Maximum command sequence number */
483
+	uint32_t maxcmdsn;
484
+	/** Reserved */
485
+	uint8_t reserved_b[12];
486
+};
487
+
488
+/** NOP-In opcode */
489
+#define ISCSI_OPCODE_NOP_IN 0x20
490
+
458 491
 /**
459 492
  * An iSCSI basic header segment
460 493
  */
@@ -468,6 +501,7 @@ union iscsi_bhs {
468 501
 	struct iscsi_bhs_data_in data_in;
469 502
 	struct iscsi_bhs_data_out data_out;
470 503
 	struct iscsi_bhs_r2t r2t;
504
+	struct iscsi_nop_in nop_in;
471 505
 	unsigned char bytes[ sizeof ( struct iscsi_bhs_common ) ];
472 506
 };
473 507
 

+ 50
- 0
src/net/tcp/iscsi.c Datei anzeigen

@@ -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;

Laden…
Abbrechen
Speichern