Browse Source

[iscsi] Fail immediately if target rejects any of our parameters

Some iSCSI targets (observed with stgt) can be configured to reject
connections that do not use header or data digests, and will respond
with "HeaderDigest=Reject" and/or "DataDigest=Reject", while still
allowing the connection to proceed to the full feature phase.

According to a strict reading of RFC3720, we are perfectly safe to
ignore these "Reject" messages: upon such a rejection "the negotiated
key is left at its current value (or default if no value was set)".
Since the default value for both HeaderDigest and DataDigest is
"None", then the only viable conclusion to be drawn is that the value
resulting from "Reject" is still "None".

Unfortunately, stgt doesn't seem to agree with this interpretation of
events, causing us to eventually report an unhelpful "connection timed
out" message to the user when we don't get any response to our first
PDU in full feature phase.

Fix by detecting any rejected parameters and immediately reporting an
error, which at least gives the user some insight as to what the real
problem may be.

Reported-by: Michal Suchanek <hramrach@centrum.cz>
Tested-by: Michal Suchanek <hramrach@centrum.cz>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
bd718b2110
1 changed files with 39 additions and 12 deletions
  1. 39
    12
      src/net/tcp/iscsi.c

+ 39
- 12
src/net/tcp/iscsi.c View File

@@ -131,6 +131,14 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
131 131
 	__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
132 132
 #define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
133 133
 	__einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
134
+#define EPROTO_INVALID_KEY_VALUE_PAIR \
135
+	__einfo_error ( EINFO_EPROTO_INVALID_KEY_VALUE_PAIR )
136
+#define EINFO_EPROTO_INVALID_KEY_VALUE_PAIR \
137
+	__einfo_uniqify ( EINFO_EPROTO, 0x05, "Invalid key/value pair" )
138
+#define EPROTO_VALUE_REJECTED \
139
+	__einfo_error ( EINFO_EPROTO_VALUE_REJECTED )
140
+#define EINFO_EPROTO_VALUE_REJECTED					\
141
+	__einfo_uniqify ( EINFO_EPROTO, 0x06, "Parameter rejected" )
134 142
 
135 143
 static void iscsi_start_tx ( struct iscsi_session *iscsi );
136 144
 static void iscsi_start_login ( struct iscsi_session *iscsi );
@@ -1083,8 +1091,8 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
1083 1091
 struct iscsi_string_type {
1084 1092
 	/** String key
1085 1093
 	 *
1086
-	 * This is the portion up to and including the "=" sign,
1087
-	 * e.g. "InitiatorName=", "CHAP_A=", etc.
1094
+	 * This is the portion preceding the "=" sign,
1095
+	 * e.g. "InitiatorName", "CHAP_A", etc.
1088 1096
 	 */
1089 1097
 	const char *key;
1090 1098
 	/** Handle iSCSI string value
@@ -1098,13 +1106,13 @@ struct iscsi_string_type {
1098 1106
 
1099 1107
 /** iSCSI text strings that we want to handle */
1100 1108
 static struct iscsi_string_type iscsi_string_types[] = {
1101
-	{ "TargetAddress=", iscsi_handle_targetaddress_value },
1102
-	{ "AuthMethod=", iscsi_handle_authmethod_value },
1103
-	{ "CHAP_A=", iscsi_handle_chap_a_value },
1104
-	{ "CHAP_I=", iscsi_handle_chap_i_value },
1105
-	{ "CHAP_C=", iscsi_handle_chap_c_value },
1106
-	{ "CHAP_N=", iscsi_handle_chap_n_value },
1107
-	{ "CHAP_R=", iscsi_handle_chap_r_value },
1109
+	{ "TargetAddress", iscsi_handle_targetaddress_value },
1110
+	{ "AuthMethod", iscsi_handle_authmethod_value },
1111
+	{ "CHAP_A", iscsi_handle_chap_a_value },
1112
+	{ "CHAP_I", iscsi_handle_chap_i_value },
1113
+	{ "CHAP_C", iscsi_handle_chap_c_value },
1114
+	{ "CHAP_N", iscsi_handle_chap_n_value },
1115
+	{ "CHAP_R", iscsi_handle_chap_r_value },
1108 1116
 	{ NULL, NULL }
1109 1117
 };
1110 1118
 
@@ -1118,16 +1126,35 @@ static struct iscsi_string_type iscsi_string_types[] = {
1118 1126
 static int iscsi_handle_string ( struct iscsi_session *iscsi,
1119 1127
 				 const char *string ) {
1120 1128
 	struct iscsi_string_type *type;
1129
+	const char *separator;
1130
+	const char *value;
1121 1131
 	size_t key_len;
1122 1132
 	int rc;
1123 1133
 
1134
+	/* Find separator */
1135
+	separator = strchr ( string, '=' );
1136
+	if ( ! separator ) {
1137
+		DBGC ( iscsi, "iSCSI %p malformed string %s\n",
1138
+		       iscsi, string );
1139
+		return -EPROTO_INVALID_KEY_VALUE_PAIR;
1140
+	}
1141
+	key_len = ( separator - string );
1142
+	value = ( separator + 1 );
1143
+
1144
+	/* Check for rejections.  Since we send only non-rejectable
1145
+	 * values, any rejection is a fatal protocol error.
1146
+	 */
1147
+	if ( strcmp ( value, "Reject" ) == 0 ) {
1148
+		DBGC ( iscsi, "iSCSI %p rejection: %s\n", iscsi, string );
1149
+		return -EPROTO_VALUE_REJECTED;
1150
+	}
1151
+
1152
+	/* Handle key/value pair */
1124 1153
 	for ( type = iscsi_string_types ; type->key ; type++ ) {
1125
-		key_len = strlen ( type->key );
1126 1154
 		if ( strncmp ( string, type->key, key_len ) != 0 )
1127 1155
 			continue;
1128 1156
 		DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string );
1129
-		if ( ( rc = type->handle ( iscsi,
1130
-					   ( string + key_len ) ) ) != 0 ) {
1157
+		if ( ( rc = type->handle ( iscsi, value ) ) != 0 ) {
1131 1158
 			DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n",
1132 1159
 			       iscsi, string, strerror ( rc ) );
1133 1160
 			return rc;

Loading…
Cancel
Save