/* returns TRUE if this TCP segment carries a MPA FPDU and FALSE otherwise */ static gboolean is_mpa_fpdu(packet_info *pinfo) { conversation_t *conversation = NULL; mpa_state_t *state = NULL; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conversation) { return FALSE; } state = get_mpa_state(conversation); if (!state) { return FALSE; } /* make sure all MPA connection parameters have been set */ if (!state->full_operation) { return FALSE; } if (pinfo->fd->num == state->req_frame_num || pinfo->fd->num == state->rep_frame_num) { return FALSE; } else { return TRUE; } }
/* returns TRUE if this TCP segment carries a MPA REQUEST and FLASE otherwise */ static gboolean is_mpa_req(tvbuff_t *tvb, packet_info *pinfo) { conversation_t *conversation = NULL; mpa_state_t *state = NULL; guint8 mcrres; if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME || tvb_get_ntoh64(tvb, 8) != MPA_ID_REQ_FRAME) return FALSE; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conversation) { conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } if (!get_mpa_state(conversation)) { /* associate a MPA connection state to this conversation if * there is no MPA state already associated to this connection */ state = init_mpa_state(); /* anaylize MPA connection parameter and record them */ mcrres = tvb_get_guint8(tvb, 16); state->ini_exp_m_res = mcrres & MPA_MARKER_FLAG; state->crc = mcrres & MPA_CRC_FLAG; state->revision = tvb_get_guint8(tvb, 17); state->req_frame_num = pinfo->fd->num; state->minfo[MPA_INITIATOR].port = pinfo->srcport; state->minfo[MPA_RESPONDER].port = pinfo->destport; conversation_add_proto_data(conversation, proto_iwarp_mpa, state); /* update expert info */ if (mcrres & MPA_RESERVED_FLAG) expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN, "Res field is NOT set to zero as required by RFC 5044"); if (state->revision != 1) expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN, "Rev field is NOT set to one as required by RFC 5044"); } return TRUE; }
/* returns TRUE if this TCP segment carries a MPA REPLY and FALSE otherwise */ static gboolean is_mpa_rep(tvbuff_t *tvb, packet_info *pinfo) { conversation_t *conversation = NULL; mpa_state_t *state = NULL; guint8 mcrres; if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME || tvb_get_ntoh64(tvb, 8) != MPA_ID_REP_FRAME) { return FALSE; } conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conversation) { return FALSE; } state = get_mpa_state(conversation); if (!state) { return FALSE; } if (!state->full_operation) { /* update state of this conversation */ mcrres = tvb_get_guint8(tvb, 16); state->res_exp_m_ini = mcrres & MPA_MARKER_FLAG; state->crc = state->crc | (mcrres & MPA_CRC_FLAG); state->rep_frame_num = pinfo->fd->num; /* enter Full Operation Phase only if the Reject bit is not set */ if (!(mcrres & MPA_REJECT_FLAG)) state->full_operation = TRUE; else expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_NOTE, "Reject bit set by Responder"); } return TRUE; }
/* returns TRUE if this TCP segment carries a MPA REQUEST and FLASE otherwise */ static gboolean is_mpa_req(tvbuff_t *tvb, packet_info *pinfo) { conversation_t *conversation = NULL; mpa_state_t *state = NULL; guint8 mcrres; if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME || tvb_get_ntoh64(tvb, 8) != MPA_ID_REQ_FRAME) return FALSE; conversation = find_or_create_conversation(pinfo); if (!get_mpa_state(conversation)) { /* associate a MPA connection state to this conversation if * there is no MPA state already associated to this connection */ state = init_mpa_state(); /* anaylize MPA connection parameter and record them */ mcrres = tvb_get_guint8(tvb, 16); state->ini_exp_m_res = mcrres & MPA_MARKER_FLAG; state->crc = mcrres & MPA_CRC_FLAG; state->revision = tvb_get_guint8(tvb, 17); state->req_frame_num = pinfo->fd->num; state->minfo[MPA_INITIATOR].port = pinfo->srcport; state->minfo[MPA_RESPONDER].port = pinfo->destport; conversation_add_proto_data(conversation, proto_iwarp_mpa, state); /* update expert info */ if (mcrres & MPA_RESERVED_FLAG) expert_add_info(pinfo, NULL, &ei_mpa_res_field_not_set0); if (state->revision != 1) expert_add_info(pinfo, NULL, &ei_mpa_rev_field_not_set1); } return TRUE; }
/* * Main dissection routine. */ static gboolean dissect_iwarp_mpa(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { tvbuff_t *next_tvb = NULL; conversation_t *conversation = NULL; mpa_state_t *state = NULL; struct tcpinfo *tcpinfo; guint8 endpoint = 3; guint16 ulpdu_length = 0; if (data == NULL) return FALSE; tcpinfo = (struct tcpinfo *)data; /* FPDU */ if (tvb_length(tvb) >= MPA_SMALLEST_FPDU_LEN && is_mpa_fpdu(pinfo)) { conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); state = get_mpa_state(conversation); if (pinfo->srcport == state->minfo[MPA_INITIATOR].port) { endpoint = MPA_INITIATOR; } else if (pinfo->srcport == state->minfo[MPA_RESPONDER].port) { endpoint = MPA_RESPONDER; } else { REPORT_DISSECTOR_BUG("endpoint cannot be determined"); } /* Markers are used by either the Initiator or the Responder or both. */ if ((state->ini_exp_m_res || state->res_exp_m_ini) && endpoint <= MPA_RESPONDER) { /* find the TCP sequence number of the first FPDU */ if (!state->minfo[endpoint].valid) { state->minfo[endpoint].seq = tcpinfo->seq; state->minfo[endpoint].valid = TRUE; } } /* dissect FPDU */ ulpdu_length = dissect_mpa_fpdu(tvb, pinfo, tree, state, tcpinfo, endpoint); /* an ulpdu_length of 0 should never happen */ if (!ulpdu_length) return FALSE; /* removes Markers if any and prepares new tvbuff for next dissector */ if (endpoint <= MPA_RESPONDER && state->minfo[endpoint].valid && number_of_markers(state, tcpinfo, endpoint) > 0) { next_tvb = tvb_new_subset_length(remove_markers(tvb, pinfo, get_first_marker_offset(state, tcpinfo, endpoint), number_of_markers(state, tcpinfo, endpoint), fpdu_total_length(tcpinfo)), MPA_ULPDU_LENGTH_LEN, ulpdu_length); } else { next_tvb = tvb_new_subset_length(tvb, MPA_ULPDU_LENGTH_LEN, ulpdu_length); } /* call subdissector */ if (ddp_rdmap_handle) { call_dissector(ddp_rdmap_handle, next_tvb, pinfo, tree); } else { REPORT_DISSECTOR_BUG("ddp_handle was null"); } return TRUE; } /* MPA REQUEST or MPA REPLY */ if (tvb_length(tvb) >= MPA_REQ_REP_FRAME_HEADER_LEN) { if (is_mpa_req(tvb, pinfo)) return dissect_mpa_req_rep(tvb, pinfo, tree, MPA_REQUEST_FRAME); else if (is_mpa_rep(tvb, pinfo)) return dissect_mpa_req_rep(tvb, pinfo, tree, MPA_REPLY_FRAME); } return FALSE; }