FreeBSD/sys/dev/iscsi/icl_soft.c
/*
 * Somewhat contrary to the name, this attempts to receive only one
 * "part" of PDU at a time; call it repeatedly until it returns non-NULL.
 */
Somewhat contrary to the name, this attempts to receive only one
"part" of PDU at a time; call it repeatedly until it returns non-NULL.
Somewhat contrary to the name this attempts to receive only one " part " of PDU at a time ; call it repeatedly until it returns non - NULL .
static struct icl_pdu *
icl_conn_receive_pdu(struct icl_conn *ic, size_t *availablep)
{
	struct icl_pdu *request;
	struct socket *so;
	size_t len;
	int error;
	bool more_needed;
	so = ic->ic_socket;
	if (ic->ic_receive_state == ICL_CONN_STATE_BHS) {
		KASSERT(ic->ic_receive_pdu == NULL,
		    ("ic->ic_receive_pdu != NULL"));
		request = icl_pdu_new_empty(ic, M_NOWAIT);
		if (request == NULL) {
			ICL_DEBUG("failed to allocate PDU; "
			    "dropping connection");
			icl_conn_fail(ic);
			return (NULL);
		}
		ic->ic_receive_pdu = request;
	} else {
		KASSERT(ic->ic_receive_pdu != NULL,
		    ("ic->ic_receive_pdu == NULL"));
		request = ic->ic_receive_pdu;
	}
	if (*availablep < ic->ic_receive_len) {
#if 0
		ICL_DEBUG("not enough data; need %zd, "
		    "have %zd", ic->ic_receive_len, *availablep);
#endif
		return (NULL);
	}
	switch (ic->ic_receive_state) {
	case ICL_CONN_STATE_BHS:
		error = icl_pdu_receive_bhs(request, availablep);
		if (error != 0) {
			ICL_DEBUG("failed to receive BHS; "
			    "dropping connection");
			break;
		}
		len = icl_pdu_data_segment_length(request);
		if (len > ic->ic_max_data_segment_length) {
			ICL_WARN("received data segment "
			    "length %zd is larger than negotiated "
			    "MaxDataSegmentLength %zd; "
			    "dropping connection",
			    len, ic->ic_max_data_segment_length);
			error = EINVAL;
			break;
		}
		ic->ic_receive_state = ICL_CONN_STATE_AHS;
		ic->ic_receive_len = icl_pdu_ahs_length(request);
		break;
	case ICL_CONN_STATE_AHS:
		error = icl_pdu_receive_ahs(request, availablep);
		if (error != 0) {
			ICL_DEBUG("failed to receive AHS; "
			    "dropping connection");
			break;
		}
		ic->ic_receive_state = ICL_CONN_STATE_HEADER_DIGEST;
		if (ic->ic_header_crc32c == false)
			ic->ic_receive_len = 0;
		else
			ic->ic_receive_len = ISCSI_HEADER_DIGEST_SIZE;
		break;
	case ICL_CONN_STATE_HEADER_DIGEST:
		error = icl_pdu_check_header_digest(request, availablep);
		if (error != 0) {
			ICL_DEBUG("header digest failed; "
			    "dropping connection");
			break;
		}
		ic->ic_receive_state = ICL_CONN_STATE_DATA;
		ic->ic_receive_len =
		    icl_pdu_data_segment_receive_len(request);
		break;
	case ICL_CONN_STATE_DATA:
		error = icl_pdu_receive_data_segment(request, availablep,
		    &more_needed);
		if (error != 0) {
			ICL_DEBUG("failed to receive data segment;"
			    "dropping connection");
			break;
		}
		if (more_needed)
			break;
		ic->ic_receive_state = ICL_CONN_STATE_DATA_DIGEST;
		if (request->ip_data_len == 0 || ic->ic_data_crc32c == false)
			ic->ic_receive_len = 0;
		else
			ic->ic_receive_len = ISCSI_DATA_DIGEST_SIZE;
		break;
	case ICL_CONN_STATE_DATA_DIGEST:
		error = icl_pdu_check_data_digest(request, availablep);
		if (error != 0) {
			ICL_DEBUG("data digest failed; "
			    "dropping connection");
			break;
		}
		ic->ic_receive_state = ICL_CONN_STATE_BHS;
		ic->ic_receive_len = sizeof(struct iscsi_bhs);
		ic->ic_receive_pdu = NULL;
		return (request);
	default:
		panic("invalid ic_receive_state %d\n", ic->ic_receive_state);
	}
	if (error != 0) {
		icl_conn_fail(ic);
	}
	return (NULL);
}
static struct icl_pdu * icl_conn_receive_pdu ( struct icl_conn * ic , size_t * availablep ) { struct icl_pdu * request ; struct socket * so ; size_t len ; int error ; bool more_needed ; so = ic -> ic_socket ; if ( ic -> ic_receive_state == ICL_CONN_STATE_BHS ) { KASSERT ( ic -> ic_receive_pdu == NULL , ( " " ) ) ; request = icl_pdu_new_empty ( ic , M_NOWAIT ) ; if ( request == NULL ) { ICL_DEBUG ( " " " " ) ; icl_conn_fail ( ic ) ; return ( NULL ) ; } ic -> ic_receive_pdu = request ; } else { KASSERT ( ic -> ic_receive_pdu != NULL , ( " " ) ) ; request = ic -> ic_receive_pdu ; } if ( * availablep < ic -> ic_receive_len ) { #if 0 ICL_DEBUG ( " " " " , ic -> ic_receive_len , * availablep ) ; #endif return ( NULL ) ; } switch ( ic -> ic_receive_state ) { case ICL_CONN_STATE_BHS : error = icl_pdu_receive_bhs ( request , availablep ) ; if ( error != 0 ) { ICL_DEBUG ( " " " " ) ; break ; } len = icl_pdu_data_segment_length ( request ) ; if ( len > ic -> ic_max_data_segment_length ) { ICL_WARN ( " " " " " " " " , len , ic -> ic_max_data_segment_length ) ; error = EINVAL ; break ; } ic -> ic_receive_state = ICL_CONN_STATE_AHS ; ic -> ic_receive_len = icl_pdu_ahs_length ( request ) ; break ; case ICL_CONN_STATE_AHS : error = icl_pdu_receive_ahs ( request , availablep ) ; if ( error != 0 ) { ICL_DEBUG ( " " " " ) ; break ; } ic -> ic_receive_state = ICL_CONN_STATE_HEADER_DIGEST ; if ( ic -> ic_header_crc32c == false ) ic -> ic_receive_len = 0 ; else ic -> ic_receive_len = ISCSI_HEADER_DIGEST_SIZE ; break ; case ICL_CONN_STATE_HEADER_DIGEST : error = icl_pdu_check_header_digest ( request , availablep ) ; if ( error != 0 ) { ICL_DEBUG ( " " " " ) ; break ; } ic -> ic_receive_state = ICL_CONN_STATE_DATA ; ic -> ic_receive_len = icl_pdu_data_segment_receive_len ( request ) ; break ; case ICL_CONN_STATE_DATA : error = icl_pdu_receive_data_segment ( request , availablep , & more_needed ) ; if ( error != 0 ) { ICL_DEBUG ( " " " " ) ; break ; } if ( more_needed ) break ; ic -> ic_receive_state = ICL_CONN_STATE_DATA_DIGEST ; if ( request -> ip_data_len == 0 || ic -> ic_data_crc32c == false ) ic -> ic_receive_len = 0 ; else ic -> ic_receive_len = ISCSI_DATA_DIGEST_SIZE ; break ; case ICL_CONN_STATE_DATA_DIGEST : error = icl_pdu_check_data_digest ( request , availablep ) ; if ( error != 0 ) { ICL_DEBUG ( " " " " ) ; break ; } ic -> ic_receive_state = ICL_CONN_STATE_BHS ; ic -> ic_receive_len = sizeof ( struct iscsi_bhs ) ; ic -> ic_receive_pdu = NULL ; return ( request ) ; default : panic ( " \n " , ic -> ic_receive_state ) ; } if ( error != 0 ) { icl_conn_fail ( ic ) ; } return ( NULL ) ; }
Somewhat contrary to the name, this attempts to receive only one
 "part" of PDU at a time; call it repeatedly until it returns non-NULL.
Somewhat contrary to the name this attempts to receive only one " part " of PDU at a time ; call it repeatedly until it returns non - NULL .
//ICL_DEBUG("receiving BHS"); /*
		 * We don't enforce any limit for AHS length;
		 * its length is stored in 8 bit field.
		 */ //ICL_DEBUG("receiving AHS"); //ICL_DEBUG("receiving header digest"); //ICL_DEBUG("receiving data segment"); //ICL_DEBUG("receiving data digest"); /*
		 * We've received complete PDU; reset the receive state machine
		 * and return the PDU.
		 */ /*
		 * Don't free the PDU; it's pointed to by ic->ic_receive_pdu
		 * and will get freed in icl_soft_conn_close().
		 */