Browse Source

Add iscsi_rx_buffered_data() and supporting infrastructure.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
3a7d762c1c
2 changed files with 87 additions and 24 deletions
  1. 6
    0
      src/include/gpxe/iscsi.h
  2. 81
    24
      src/net/tcp/iscsi.c

+ 6
- 0
src/include/gpxe/iscsi.h View File

583
 	enum iscsi_tx_state tx_state;
583
 	enum iscsi_tx_state tx_state;
584
 	/** Byte offset within the current TX state */
584
 	/** Byte offset within the current TX state */
585
 	size_t tx_offset;
585
 	size_t tx_offset;
586
+	/** Length of the current TX state */
587
+	size_t tx_len;
586
 
588
 
587
 	/** Basic header segment for current RX PDU */
589
 	/** Basic header segment for current RX PDU */
588
 	union iscsi_bhs rx_bhs;
590
 	union iscsi_bhs rx_bhs;
590
 	enum iscsi_rx_state rx_state;
592
 	enum iscsi_rx_state rx_state;
591
 	/** Byte offset within the current RX state */
593
 	/** Byte offset within the current RX state */
592
 	size_t rx_offset;
594
 	size_t rx_offset;
595
+	/** Length of the current RX state */
596
+	size_t rx_len;
597
+	/** Buffer for received data (not always used) */
598
+	void *rx_buffer;
593
 	/** State of strings received during login phase */
599
 	/** State of strings received during login phase */
594
 	struct iscsi_string_state string;
600
 	struct iscsi_string_state string;
595
 
601
 

+ 81
- 24
src/net/tcp/iscsi.c View File

38
 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
38
 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
39
 				   unsigned int datasn );
39
 				   unsigned int datasn );
40
 
40
 
41
+/**
42
+ * Receive PDU data into buffer
43
+ *
44
+ * @v iscsi		iSCSI session
45
+ * @v data		Data to receive
46
+ * @v len		Length of data
47
+ * @ret rc		Return status code
48
+ *
49
+ * This can be used when the RX PDU type handler wishes to buffer up
50
+ * all received data and process the PDU as a single unit.  The caller
51
+ * is repsonsible for calling iscsi_rx_buffered_data_done() after
52
+ * processing the data.
53
+ */
54
+static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
55
+				    const void *data, size_t len ) {
56
+
57
+	/* Allocate buffer on first call */
58
+	if ( ! iscsi->rx_buffer ) {
59
+		iscsi->rx_buffer = malloc ( iscsi->rx_len );
60
+		if ( ! iscsi->rx_buffer )
61
+			return -ENOMEM;
62
+	}
63
+
64
+	/* Copy data to buffer */
65
+	assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
66
+	memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
67
+
68
+	return 0;
69
+}
70
+
71
+/**
72
+ * Finish receiving PDU data into buffer
73
+ *
74
+ * @v iscsi		iSCSI session
75
+ */
76
+static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
77
+	free ( iscsi->rx_buffer );
78
+	iscsi->rx_buffer = NULL;
79
+}
80
+
41
 /**
81
 /**
42
  * Mark iSCSI operation as complete
82
  * Mark iSCSI operation as complete
43
  *
83
  *
52
  * should both be idle.
92
  * should both be idle.
53
  */
93
  */
54
 static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
94
 static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
95
+
55
 	/* Clear current SCSI command */
96
 	/* Clear current SCSI command */
56
 	iscsi->command = NULL;
97
 	iscsi->command = NULL;
57
-	/* Free any memory that may have been used for CHAP */
98
+
99
+	/* Free any dynamically allocated memory */
58
 	chap_finish ( &iscsi->chap );
100
 	chap_finish ( &iscsi->chap );
101
+	iscsi_rx_buffered_data_done ( iscsi );
102
+
59
 	/* Mark asynchronous operation as complete */
103
 	/* Mark asynchronous operation as complete */
60
 	async_done ( &iscsi->aop, rc );
104
 	async_done ( &iscsi->aop, rc );
61
 }
105
 }
283
 
327
 
284
 	offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
328
 	offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
285
 		   iscsi->tx_offset );
329
 		   iscsi->tx_offset );
286
-	remaining = ( ISCSI_DATA_LEN ( data_out->lengths ) - iscsi->tx_offset);
330
+	remaining = ( iscsi->tx_len - iscsi->tx_offset );
287
 	assert ( iscsi->command != NULL );
331
 	assert ( iscsi->command != NULL );
288
 	assert ( iscsi->command->data_out );
332
 	assert ( iscsi->command->data_out );
289
 	assert ( ( offset + remaining ) <= iscsi->command->data_out_len );
333
 	assert ( ( offset + remaining ) <= iscsi->command->data_out_len );
693
 	}
737
 	}
694
 }
738
 }
695
 
739
 
740
+static void iscsi_handle_strings ( struct iscsi_session *iscsi,
741
+				   const char *strings, size_t len ) {
742
+	for ( ; len-- ; strings++ ) {
743
+		iscsi_handle_string_byte ( iscsi,
744
+					   * ( ( uint8_t * ) strings ) );
745
+	}
746
+}
747
+
696
 /**
748
 /**
697
  * Receive data segment of an iSCSI login response PDU
749
  * Receive data segment of an iSCSI login response PDU
698
  *
750
  *
706
 				      size_t len, size_t remaining ) {
758
 				      size_t len, size_t remaining ) {
707
 	struct iscsi_bhs_login_response *response
759
 	struct iscsi_bhs_login_response *response
708
 		= &iscsi->rx_bhs.login_response;
760
 		= &iscsi->rx_bhs.login_response;
761
+	int rc;
762
+
763
+	/* Buffer up the PDU data */
764
+	if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
765
+		DBG ( "iSCSI %p could not buffer login response\n", iscsi );
766
+		iscsi_close ( iscsi, rc );
767
+		return;
768
+	}
769
+	if ( remaining )
770
+		return;
771
+
772
+	/* Process string data and discard string buffer */
773
+	iscsi_handle_strings ( iscsi, iscsi->rx_buffer, iscsi->rx_len );
774
+	iscsi_rx_buffered_data_done ( iscsi );
709
 
775
 
710
 	/* Check for fatal errors */
776
 	/* Check for fatal errors */
711
 	if ( response->status_class != 0 ) {
777
 	if ( response->status_class != 0 ) {
715
 		return;
781
 		return;
716
 	}
782
 	}
717
 
783
 
718
-	/* Process strings data */
719
-	for ( ; len-- ; data++ ) {
720
-		iscsi_handle_string_byte ( iscsi, * ( ( uint8_t * ) data ) );
721
-	}
722
-	if ( remaining )
723
-		return;
724
-
725
 	/* Handle login transitions */
784
 	/* Handle login transitions */
726
 	if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
785
 	if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
727
 		switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
786
 		switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
848
 static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
907
 static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
849
 	struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
908
 	struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
850
 	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
909
 	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
851
-	size_t max_tx_offset;
852
 	enum iscsi_tx_state next_state;
910
 	enum iscsi_tx_state next_state;
853
 	
911
 	
854
 	iscsi->tx_offset += len;
912
 	iscsi->tx_offset += len;
855
 	while ( 1 ) {
913
 	while ( 1 ) {
856
 		switch ( iscsi->tx_state ) {
914
 		switch ( iscsi->tx_state ) {
857
 		case ISCSI_TX_BHS:
915
 		case ISCSI_TX_BHS:
858
-			max_tx_offset = sizeof ( iscsi->tx_bhs );
916
+			iscsi->tx_len = sizeof ( iscsi->tx_bhs );
859
 			next_state = ISCSI_TX_AHS;
917
 			next_state = ISCSI_TX_AHS;
860
 			break;
918
 			break;
861
 		case ISCSI_TX_AHS:
919
 		case ISCSI_TX_AHS:
862
-			max_tx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
920
+			iscsi->tx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
863
 			next_state = ISCSI_TX_DATA;
921
 			next_state = ISCSI_TX_DATA;
864
 			break;
922
 			break;
865
 		case ISCSI_TX_DATA:
923
 		case ISCSI_TX_DATA:
866
-			max_tx_offset = ISCSI_DATA_LEN ( common->lengths );
924
+			iscsi->tx_len = ISCSI_DATA_LEN ( common->lengths );
867
 			next_state = ISCSI_TX_DATA_PADDING;
925
 			next_state = ISCSI_TX_DATA_PADDING;
868
 			break;
926
 			break;
869
 		case ISCSI_TX_DATA_PADDING:
927
 		case ISCSI_TX_DATA_PADDING:
870
-			max_tx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
928
+			iscsi->tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
871
 			next_state = ISCSI_TX_IDLE;
929
 			next_state = ISCSI_TX_IDLE;
872
 			break;
930
 			break;
873
 		case ISCSI_TX_IDLE:
931
 		case ISCSI_TX_IDLE:
876
 			assert ( 0 );
934
 			assert ( 0 );
877
 			return;
935
 			return;
878
 		}
936
 		}
879
-		assert ( iscsi->tx_offset <= max_tx_offset );
937
+		assert ( iscsi->tx_offset <= iscsi->tx_len );
880
 
938
 
881
 		/* If the whole of the current portion has not yet
939
 		/* If the whole of the current portion has not yet
882
 		 * been acked, stay in this state for now.
940
 		 * been acked, stay in this state for now.
883
 		 */
941
 		 */
884
-		if ( iscsi->tx_offset != max_tx_offset )
942
+		if ( iscsi->tx_offset != iscsi->tx_len )
885
 			return;
943
 			return;
886
 
944
 
887
 		/* Move to next state.  Call iscsi_tx_done() when PDU
945
 		/* Move to next state.  Call iscsi_tx_done() when PDU
1033
 	struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
1091
 	struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
1034
 	void ( *process ) ( struct iscsi_session *iscsi, void *data,
1092
 	void ( *process ) ( struct iscsi_session *iscsi, void *data,
1035
 			    size_t len, size_t remaining );
1093
 			    size_t len, size_t remaining );
1036
-	size_t max_rx_offset;
1037
 	enum iscsi_rx_state next_state;
1094
 	enum iscsi_rx_state next_state;
1038
 	size_t frag_len;
1095
 	size_t frag_len;
1039
 	size_t remaining;
1096
 	size_t remaining;
1042
 		switch ( iscsi->rx_state ) {
1099
 		switch ( iscsi->rx_state ) {
1043
 		case ISCSI_RX_BHS:
1100
 		case ISCSI_RX_BHS:
1044
 			process = iscsi_rx_bhs;
1101
 			process = iscsi_rx_bhs;
1045
-			max_rx_offset = sizeof ( iscsi->rx_bhs );
1102
+			iscsi->rx_len = sizeof ( iscsi->rx_bhs );
1046
 			next_state = ISCSI_RX_AHS;			
1103
 			next_state = ISCSI_RX_AHS;			
1047
 			break;
1104
 			break;
1048
 		case ISCSI_RX_AHS:
1105
 		case ISCSI_RX_AHS:
1049
 			process = iscsi_rx_discard;
1106
 			process = iscsi_rx_discard;
1050
-			max_rx_offset = 4 * ISCSI_AHS_LEN ( common->lengths );
1107
+			iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
1051
 			next_state = ISCSI_RX_DATA;
1108
 			next_state = ISCSI_RX_DATA;
1052
 			break;
1109
 			break;
1053
 		case ISCSI_RX_DATA:
1110
 		case ISCSI_RX_DATA:
1054
 			process = iscsi_rx_data;
1111
 			process = iscsi_rx_data;
1055
-			max_rx_offset = ISCSI_DATA_LEN ( common->lengths );
1112
+			iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
1056
 			next_state = ISCSI_RX_DATA_PADDING;
1113
 			next_state = ISCSI_RX_DATA_PADDING;
1057
 			break;
1114
 			break;
1058
 		case ISCSI_RX_DATA_PADDING:
1115
 		case ISCSI_RX_DATA_PADDING:
1059
 			process = iscsi_rx_discard;
1116
 			process = iscsi_rx_discard;
1060
-			max_rx_offset = ISCSI_DATA_PAD_LEN ( common->lengths );
1117
+			iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
1061
 			next_state = ISCSI_RX_BHS;
1118
 			next_state = ISCSI_RX_BHS;
1062
 			break;
1119
 			break;
1063
 		default:
1120
 		default:
1065
 			return;
1122
 			return;
1066
 		}
1123
 		}
1067
 
1124
 
1068
-		frag_len = max_rx_offset - iscsi->rx_offset;
1125
+		frag_len = iscsi->rx_len - iscsi->rx_offset;
1069
 		if ( frag_len > len )
1126
 		if ( frag_len > len )
1070
 			frag_len = len;
1127
 			frag_len = len;
1071
-		remaining = max_rx_offset - iscsi->rx_offset - frag_len;
1128
+		remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
1072
 		process ( iscsi, data, frag_len, remaining );
1129
 		process ( iscsi, data, frag_len, remaining );
1073
 
1130
 
1074
 		iscsi->rx_offset += frag_len;
1131
 		iscsi->rx_offset += frag_len;
1078
 		/* If all the data for this state has not yet been
1135
 		/* If all the data for this state has not yet been
1079
 		 * received, stay in this state for now.
1136
 		 * received, stay in this state for now.
1080
 		 */
1137
 		 */
1081
-		if ( iscsi->rx_offset != max_rx_offset )
1138
+		if ( iscsi->rx_offset != iscsi->rx_len )
1082
 			return;
1139
 			return;
1083
 
1140
 
1084
 		iscsi->rx_state = next_state;
1141
 		iscsi->rx_state = next_state;

Loading…
Cancel
Save