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