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,6 +583,8 @@ struct iscsi_session {
583 583
 	enum iscsi_tx_state tx_state;
584 584
 	/** Byte offset within the current TX state */
585 585
 	size_t tx_offset;
586
+	/** Length of the current TX state */
587
+	size_t tx_len;
586 588
 
587 589
 	/** Basic header segment for current RX PDU */
588 590
 	union iscsi_bhs rx_bhs;
@@ -590,6 +592,10 @@ struct iscsi_session {
590 592
 	enum iscsi_rx_state rx_state;
591 593
 	/** Byte offset within the current RX state */
592 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 599
 	/** State of strings received during login phase */
594 600
 	struct iscsi_string_state string;
595 601
 

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

@@ -38,6 +38,46 @@ static void iscsi_start_tx ( struct iscsi_session *iscsi );
38 38
 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
39 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 82
  * Mark iSCSI operation as complete
43 83
  *
@@ -52,10 +92,14 @@ static void iscsi_start_data_out ( struct iscsi_session *iscsi,
52 92
  * should both be idle.
53 93
  */
54 94
 static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
95
+
55 96
 	/* Clear current SCSI command */
56 97
 	iscsi->command = NULL;
57
-	/* Free any memory that may have been used for CHAP */
98
+
99
+	/* Free any dynamically allocated memory */
58 100
 	chap_finish ( &iscsi->chap );
101
+	iscsi_rx_buffered_data_done ( iscsi );
102
+
59 103
 	/* Mark asynchronous operation as complete */
60 104
 	async_done ( &iscsi->aop, rc );
61 105
 }
@@ -283,7 +327,7 @@ static void iscsi_tx_data_out ( struct iscsi_session *iscsi,
283 327
 
284 328
 	offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
285 329
 		   iscsi->tx_offset );
286
-	remaining = ( ISCSI_DATA_LEN ( data_out->lengths ) - iscsi->tx_offset);
330
+	remaining = ( iscsi->tx_len - iscsi->tx_offset );
287 331
 	assert ( iscsi->command != NULL );
288 332
 	assert ( iscsi->command->data_out );
289 333
 	assert ( ( offset + remaining ) <= iscsi->command->data_out_len );
@@ -693,6 +737,14 @@ static void iscsi_handle_string_byte ( struct iscsi_session *iscsi,
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 749
  * Receive data segment of an iSCSI login response PDU
698 750
  *
@@ -706,6 +758,20 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
706 758
 				      size_t len, size_t remaining ) {
707 759
 	struct iscsi_bhs_login_response *response
708 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 776
 	/* Check for fatal errors */
711 777
 	if ( response->status_class != 0 ) {
@@ -715,13 +781,6 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
715 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 784
 	/* Handle login transitions */
726 785
 	if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
727 786
 		switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
@@ -848,26 +907,25 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
848 907
 static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
849 908
 	struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
850 909
 	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
851
-	size_t max_tx_offset;
852 910
 	enum iscsi_tx_state next_state;
853 911
 	
854 912
 	iscsi->tx_offset += len;
855 913
 	while ( 1 ) {
856 914
 		switch ( iscsi->tx_state ) {
857 915
 		case ISCSI_TX_BHS:
858
-			max_tx_offset = sizeof ( iscsi->tx_bhs );
916
+			iscsi->tx_len = sizeof ( iscsi->tx_bhs );
859 917
 			next_state = ISCSI_TX_AHS;
860 918
 			break;
861 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 921
 			next_state = ISCSI_TX_DATA;
864 922
 			break;
865 923
 		case ISCSI_TX_DATA:
866
-			max_tx_offset = ISCSI_DATA_LEN ( common->lengths );
924
+			iscsi->tx_len = ISCSI_DATA_LEN ( common->lengths );
867 925
 			next_state = ISCSI_TX_DATA_PADDING;
868 926
 			break;
869 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 929
 			next_state = ISCSI_TX_IDLE;
872 930
 			break;
873 931
 		case ISCSI_TX_IDLE:
@@ -876,12 +934,12 @@ static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
876 934
 			assert ( 0 );
877 935
 			return;
878 936
 		}
879
-		assert ( iscsi->tx_offset <= max_tx_offset );
937
+		assert ( iscsi->tx_offset <= iscsi->tx_len );
880 938
 
881 939
 		/* If the whole of the current portion has not yet
882 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 943
 			return;
886 944
 
887 945
 		/* Move to next state.  Call iscsi_tx_done() when PDU
@@ -1033,7 +1091,6 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data,
1033 1091
 	struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
1034 1092
 	void ( *process ) ( struct iscsi_session *iscsi, void *data,
1035 1093
 			    size_t len, size_t remaining );
1036
-	size_t max_rx_offset;
1037 1094
 	enum iscsi_rx_state next_state;
1038 1095
 	size_t frag_len;
1039 1096
 	size_t remaining;
@@ -1042,22 +1099,22 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data,
1042 1099
 		switch ( iscsi->rx_state ) {
1043 1100
 		case ISCSI_RX_BHS:
1044 1101
 			process = iscsi_rx_bhs;
1045
-			max_rx_offset = sizeof ( iscsi->rx_bhs );
1102
+			iscsi->rx_len = sizeof ( iscsi->rx_bhs );
1046 1103
 			next_state = ISCSI_RX_AHS;			
1047 1104
 			break;
1048 1105
 		case ISCSI_RX_AHS:
1049 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 1108
 			next_state = ISCSI_RX_DATA;
1052 1109
 			break;
1053 1110
 		case ISCSI_RX_DATA:
1054 1111
 			process = iscsi_rx_data;
1055
-			max_rx_offset = ISCSI_DATA_LEN ( common->lengths );
1112
+			iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
1056 1113
 			next_state = ISCSI_RX_DATA_PADDING;
1057 1114
 			break;
1058 1115
 		case ISCSI_RX_DATA_PADDING:
1059 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 1118
 			next_state = ISCSI_RX_BHS;
1062 1119
 			break;
1063 1120
 		default:
@@ -1065,10 +1122,10 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data,
1065 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 1126
 		if ( frag_len > len )
1070 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 1129
 		process ( iscsi, data, frag_len, remaining );
1073 1130
 
1074 1131
 		iscsi->rx_offset += frag_len;
@@ -1078,7 +1135,7 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data,
1078 1135
 		/* If all the data for this state has not yet been
1079 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 1139
 			return;
1083 1140
 
1084 1141
 		iscsi->rx_state = next_state;

Loading…
Cancel
Save