static void dissect_dlm_migrate_lockres(proto_tree *tree, tvbuff_t *tvb, int offset) { unsigned int i; guint32 num_locks; static const int * mres_flags[] = { &hf_dlm_mres_flag_recovery, &hf_dlm_mres_flag_migration, &hf_dlm_mres_flag_all_done, NULL }; /* master */ proto_tree_add_item(tree, hf_dlm_master, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* lockname_len */ proto_tree_add_item(tree, hf_dlm_namelen, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* num_locks */ proto_tree_add_item_ret_uint(tree, hf_dlm_mres_num_locks, tvb, offset, 1, ENC_BIG_ENDIAN, &num_locks); offset += 1; /* no locks were found on this lockres! done! */ if (num_locks == 0) return; /* flags */ proto_tree_add_bitmask_with_flags(tree, tvb, offset, hf_dlm_mres_flags, ett_mres_flags, mres_flags, ENC_BIG_ENDIAN, BMT_NO_INT | BMT_NO_FALSE | BMT_NO_TFS); offset += 1; /* total_locks */ proto_tree_add_item(tree, hf_dlm_mres_total_locks, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /* mig_cookie */ offset = dlm_cookie_handler(tree, tvb, offset, hf_dlm_mres_mig_cookie); /* lockname */ proto_tree_add_item(tree, hf_dlm_name, tvb, offset, 32, ENC_ASCII|ENC_NA); offset += 32; /* lvb */ proto_tree_add_item(tree, hf_dlm_lvb1, tvb, offset, 24, ENC_NA); offset += 24; proto_tree_add_item(tree, hf_dlm_lvb2, tvb, offset, 24, ENC_NA); offset += 24; proto_tree_add_item(tree, hf_dlm_lvb3, tvb, offset, 16, ENC_NA); offset += 16; /* dlm_migratable_lock */ for (i = 0; i < num_locks; i++) { proto_tree *subtree; subtree = proto_tree_add_subtree_format(tree, tvb, offset, 16, ett_migrate_lockres_locks, NULL, "Locks%d: ", i + 1); /* cookie */ offset = dlm_cookie_handler(subtree, tvb, offset, hf_dlm_mres_mig_cookie); proto_tree_add_item(subtree, hf_dlm_pad8, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* list */ proto_tree_add_item(subtree, hf_dlm_mres_list, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* flags */ proto_tree_add_item(subtree, hf_dlm_mres_ml_flags, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* type */ proto_tree_add_item(subtree, hf_dlm_mres_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* convert_type */ proto_tree_add_item(subtree, hf_dlm_mres_convert_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* highest_blocked */ proto_tree_add_item(subtree, hf_dlm_mres_highest_blocked, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(subtree, hf_dlm_mres_node, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; } }
/* *** Code to actually dissect the packets *** */ static int dissect_dvb_s2_gse(tvbuff_t *tvb, int cur_off, proto_tree *tree, packet_info *pinfo, int bytes_available) { int new_off = 0; int frag_len; guint16 gse_hdr, data_len, padding_len, gse_proto = 0; proto_item *ti; proto_tree *dvb_s2_gse_tree; tvbuff_t *next_tvb; static const int * gse_header_bitfields[] = { &hf_dvb_s2_gse_hdr_start, &hf_dvb_s2_gse_hdr_stop, &hf_dvb_s2_gse_hdr_labeltype, &hf_dvb_s2_gse_hdr_length, NULL }; col_append_str(pinfo->cinfo, COL_INFO, " GSE"); /* get the GSE header */ gse_hdr = tvb_get_ntohs(tvb, cur_off + DVB_S2_GSE_OFFS_HDR); /* check if this is just padding, which takes up the rest of the frame */ if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_START_POS) && BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_STOP_POS) && BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS1) && BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS2)) { padding_len = bytes_available; proto_tree_add_uint_format(tree, hf_dvb_s2_gse_padding, tvb, cur_off + new_off, padding_len, padding_len, "DVB-S2 GSE Padding, Length: %d", padding_len); col_append_str(pinfo->cinfo, COL_INFO, " pad"); new_off += padding_len; return new_off; } else { /* Not padding, parse as a GSE Header */ new_off += 2; frag_len = (gse_hdr & DVB_S2_GSE_HDR_LENGTH_MASK)+2; ti = proto_tree_add_item(tree, proto_dvb_s2_gse, tvb, cur_off, frag_len, ENC_NA); dvb_s2_gse_tree = proto_item_add_subtree(ti, ett_dvb_s2_gse); proto_tree_add_bitmask_with_flags(dvb_s2_gse_tree, tvb, cur_off + DVB_S2_GSE_OFFS_HDR, hf_dvb_s2_gse_hdr, ett_dvb_s2_gse_hdr, gse_header_bitfields, ENC_BIG_ENDIAN, BMT_NO_TFS); if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_START_POS) || BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) { proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_fragid, tvb, cur_off + new_off, 1, ENC_BIG_ENDIAN); new_off += 1; } if (BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_START_POS) && BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) { proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_totlength, tvb, cur_off + new_off, 2, ENC_BIG_ENDIAN); col_append_str(pinfo->cinfo, COL_INFO, "(frag) "); new_off += 2; } if (BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_START_POS)) { gse_proto = tvb_get_ntohs(tvb, cur_off + new_off); proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_proto, tvb, cur_off + new_off, 2, ENC_BIG_ENDIAN); new_off += 2; if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS1) && BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS2)) { /* 6 byte label */ if (BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) col_append_str(pinfo->cinfo, COL_INFO, "6 "); proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_label6, tvb, cur_off + new_off, 6, ENC_NA); new_off += 6; } else if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS1) && BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_LABELTYPE_POS2)) { /* 3 byte label */ if (BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) col_append_str(pinfo->cinfo, COL_INFO, "3 "); proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_label3, tvb, cur_off + new_off, 3, ENC_BIG_ENDIAN); new_off += 3; } else { /* 0 byte label */ if (BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) col_append_str(pinfo->cinfo, COL_INFO, "0 "); } if (gse_proto < 0x0600 && gse_proto >= 0x100) { /* Only display optional extension headers */ /* TODO: needs to be tested */ /* TODO: implementation needs to be checked (len of ext-header??) */ proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_exthdr, tvb, cur_off + new_off, 1, ENC_BIG_ENDIAN); new_off += 1; } } else { /* correct cinfo */ col_append_str(pinfo->cinfo, COL_INFO, "(frag) "); } next_tvb = tvb_new_subset_remaining(tvb, cur_off + new_off); if (dvb_s2_full_dissection) { switch (gse_proto) { case ETHERTYPE_IP: new_off += call_dissector(ip_handle, next_tvb, pinfo, tree); break; case ETHERTYPE_IPv6: new_off += call_dissector(ipv6_handle, next_tvb, pinfo, tree); break; default: if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_START_POS) && BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) { data_len = (gse_hdr & DVB_S2_GSE_HDR_LENGTH_MASK) - (new_off - DVB_S2_GSE_MINSIZE) - DVB_S2_GSE_CRC32_LEN; } else data_len = (gse_hdr & DVB_S2_GSE_HDR_LENGTH_MASK) - (new_off - DVB_S2_GSE_MINSIZE); proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_data, tvb, cur_off + new_off, data_len, ENC_NA); new_off += data_len; break; } } else { if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_START_POS) && BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) { data_len = (gse_hdr & DVB_S2_GSE_HDR_LENGTH_MASK) - (new_off - DVB_S2_GSE_MINSIZE) - DVB_S2_GSE_CRC32_LEN; } else data_len = (gse_hdr & DVB_S2_GSE_HDR_LENGTH_MASK) - (new_off - DVB_S2_GSE_MINSIZE); proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_data, tvb, cur_off + new_off, data_len, ENC_NA); new_off += data_len; } /* add crc32 if last fragment */ if (BIT_IS_CLEAR(gse_hdr, DVB_S2_GSE_HDR_START_POS) && BIT_IS_SET(gse_hdr, DVB_S2_GSE_HDR_STOP_POS)) { proto_tree_add_item(dvb_s2_gse_tree, hf_dvb_s2_gse_crc32, tvb, cur_off + new_off, DVB_S2_GSE_CRC32_LEN, ENC_BIG_ENDIAN); new_off += DVB_S2_GSE_CRC32_LEN; } } return new_off; }
/* G.7041 6.1.2 GFP payload area */ static void dissect_gfp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *gfp_tree, guint *offset, guint payload_len) { tvbuff_t *payload_tvb; proto_item *type_ti = NULL; proto_item *fcs_ti; proto_tree *fcs_tree = NULL; guint pti, pfi, exi, upi; guint fcs, fcs_calc; guint fcs_len = 0; /* G.7041 6.1.2.3 Payload area scrambling * Note that payload when sent on the wire is scrambled as per ATM * with a 1 + x^43 multiplicative scrambler. Likely already removed by * the time we get a capture file (as with ATM). Could have a pref, * but if it's present we have to save state over subsequent frames, * always would fail to decode the first 43 payload bytes of a capture. */ /* G.7041 6.1.2.1 Payload Header - at least 4 bytes */ tvb_ensure_bytes_exist(tvb, *offset, 4); payload_len -= 4; /* G.7041 6.1.2.1.1 GFP type field - mandatory 2 bytes */ pti = tvb_get_bits8(tvb, 8*(*offset), 3); pfi = tvb_get_bits8(tvb, 8*(*offset)+3, 1); exi = tvb_get_bits8(tvb, 8*(*offset)+4, 4); upi = tvb_get_guint8(tvb, *offset+1); p_add_proto_data(pinfo->pool, pinfo, proto_gfp, 0, GUINT_TO_POINTER(upi)); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pti, gfp_pti_vals, "Reserved PTI (%d)")); if (pti == GFP_USER_DATA || pti == GFP_MANAGEMENT_COMMUNICATIONS) { /* G.7041 Table 6-3 - GFP_MANAGEMENT_COMMUNICATIONS * uses the same UPI table as USER_DATA, though * "not all of these UPI types are applicable" in that case. */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_data_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_data_rvals, "Unknown 0x%02x")); } else if (pti == GFP_CLIENT_MANAGEMENT) { /* G.7041 Table 6-4 */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_management_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_management_rvals, "Unknown 0x%02x")); } /* G.7041 6.1.2.1.2 Type HEC (tHEC) - mandatory 2 bytes */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_thec, hf_gfp_thec_status, &ei_gfp_thec_bad); switch (exi) { case GFP_EXT_NULL: /* G.7041 6.1.2.1.3.1 Null extension header */ break; case GFP_EXT_LINEAR: /* G.7041 6.1.2.1.3.2 Extension header for a linear frame */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_exi_short); payload_len = 0; } else { payload_len -= 4; } proto_tree_add_item(gfp_tree, hf_gfp_cid, tvb, *offset, 1, ENC_BIG_ENDIAN); /* Next byte spare field, reserved */ /* 6.1.2.1.4 Extension HEC field */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_ehec, hf_gfp_ehec_status, &ei_gfp_ehec_bad); break; case GFP_EXT_RING: /* 6.1.2.1.3.3 Extension header for a ring frame */ /* "For further study." Undefined so fall through */ default: /* Reserved */ /* TODO: Mark as error / unhandled? */ break; } proto_item_set_end(gfp_tree, tvb, *offset); if (pfi == 1) { /* 6.1.2.2.1 Payload FCS field present */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_pfi_short); fcs_len = payload_len; payload_len = 0; } else { fcs_len = 4; payload_len -= 4; } proto_tree_set_appendix(gfp_tree, tvb, *offset + payload_len, fcs_len); fcs = tvb_get_ntohl(tvb, *offset + payload_len); /* Same CRC32 as ATM */ /* As with ATM, we can either compute the CRC as it would be * calculated and compare (last step involves taking the complement), * or we can include the passed CRC in the input and check to see * if the remainder is a known value. I like the first method * only because it lets us display what we should have received. */ /* Method 1: */ fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len); if (fcs == ~fcs_calc) { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [correct]", fcs); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); } else { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [incorrect, should be 0x%08x]", fcs, fcs_calc); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); expert_add_info(pinfo, fcs_ti, &ei_gfp_fcs_bad); } /* Method 2: */ /* fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len+4); fcs_ti = proto_tree_add_uint(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs); proto_item_append_text(fcs_ti, (fcs_calc == 0xC704DD7B) ? " [correct]" : " [incorrect]"); */ } /* Some client frames we can do. Others are not implemented yet. * Transparent mode types are much trickier than frame-mapped, * since they requires reassembling streams across multiple GFP packets. */ payload_tvb = tvb_new_subset_length(tvb, *offset, payload_len); switch (pti) { case GFP_USER_DATA: case GFP_MANAGEMENT_COMMUNICATIONS: if (!dissector_try_uint(gfp_dissector_table, upi, payload_tvb, pinfo, tree)) { expert_add_info_format(pinfo, type_ti, &ei_gfp_payload_undecoded, "Payload type 0x%02x (%s) unsupported", upi, rval_to_str_const(upi, gfp_upi_data_rvals, "UNKNOWN")); call_data_dissector(payload_tvb, pinfo, tree); } break; case GFP_CLIENT_MANAGEMENT: call_data_dissector(payload_tvb, pinfo, tree); break; default: break; } *offset += payload_len; *offset += fcs_len; }