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