static void dissect_stt_checksum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *stt_tree) { gboolean can_checksum = !pinfo->fragmented && tvb_bytes_exist(tvb, 0, tvb_reported_length(tvb)); if (can_checksum && pref_check_checksum) { vec_t cksum_vec[4]; guint32 phdr[2]; /* Set up the fields of the pseudo-header. */ SET_CKSUM_VEC_PTR(cksum_vec[0], (const guint8 *)pinfo->src.data, pinfo->src.len); SET_CKSUM_VEC_PTR(cksum_vec[1], (const guint8 *)pinfo->dst.data, pinfo->dst.len); switch (pinfo->src.type) { case AT_IPv4: phdr[0] = g_htonl((IP_PROTO_TCP<<16) + tvb_reported_length(tvb)); SET_CKSUM_VEC_PTR(cksum_vec[2], (const guint8 *)phdr, 4); break; case AT_IPv6: phdr[0] = g_htonl(tvb_reported_length(tvb)); phdr[1] = g_htonl(IP_PROTO_TCP); SET_CKSUM_VEC_PTR(cksum_vec[2], (const guint8 *)phdr, 8); break; default: /* STT runs only atop IPv4 and IPv6.... */ DISSECTOR_ASSERT_NOT_REACHED(); break; } SET_CKSUM_VEC_TVB(cksum_vec[3], tvb, 0, tvb_reported_length(tvb)); proto_tree_add_checksum(stt_tree, tvb, 16, hf_stt_checksum, hf_stt_checksum_status, &ei_stt_checksum_bad, pinfo, in_cksum(cksum_vec, 4), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY); } else { proto_tree_add_checksum(stt_tree, tvb, 16, hf_stt_checksum, hf_stt_checksum_status, &ei_stt_checksum_bad, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); } }
/* * dissect_pgm - The dissector for Pragmatic General Multicast */ static void dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 pgmhdr_sport; guint16 pgmhdr_dport; guint8 pgmhdr_type; guint8 pgmhdr_opts; guint16 pgmhdr_cksum; guint16 pgmhdr_tsdulen; guint32 sqn; guint16 afi; guint plen = 0; proto_item *ti; const char *pktname; const char *pollstname; char *gsi; gboolean isdata = FALSE; guint pgmlen, reportedlen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM"); col_clear(pinfo->cinfo, COL_INFO); if (tvb_reported_length_remaining(tvb, 0) < 18) { col_set_str(pinfo->cinfo, COL_INFO, "Packet too small"); return; } pinfo->srcport = pgmhdr_sport = tvb_get_ntohs(tvb, 0); pinfo->destport = pgmhdr_dport = tvb_get_ntohs(tvb, 2); pgmhdr_type = tvb_get_guint8(tvb, 4); pktname = val_to_str(pgmhdr_type, type_vals, "Unknown (0x%02x)"); pgmhdr_opts = tvb_get_guint8(tvb, 5); pgmhdr_cksum = tvb_get_ntohs(tvb, 6); gsi = tvb_bytes_to_str(wmem_packet_scope(), tvb, 8, 6); pgmhdr_tsdulen = tvb_get_ntohs(tvb, 14); sqn = tvb_get_ntohl(tvb, 16); switch(pgmhdr_type) { case PGM_SPM_PCKT: case PGM_NAK_PCKT: case PGM_NNAK_PCKT: case PGM_NCF_PCKT: case PGM_POLR_PCKT: case PGM_ACK_PCKT: col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s", pktname, sqn, gsi); break; case PGM_RDATA_PCKT: case PGM_ODATA_PCKT: col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, sqn, gsi, pgmhdr_tsdulen); isdata = TRUE; break; case PGM_POLL_PCKT: { guint16 poll_stype = tvb_get_ntohs(tvb, 22); pollstname = val_to_str(poll_stype, poll_subtype_vals, "Unknown (0x%02x)"); col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s subtype %s", pktname, sqn, gsi, pollstname); } break; default: return; } { proto_tree *pgm_tree = NULL; proto_tree *opt_tree = NULL; proto_tree *type_tree = NULL; proto_item *tf, *hidden_item; ptvcursor_t* cursor; ti = proto_tree_add_protocol_format(tree, proto_pgm, tvb, 0, -1, "Pragmatic General Multicast: Type %s" " Src Port %u, Dst Port %u, GSI %s", pktname, pgmhdr_sport, pgmhdr_dport, gsi); pgm_tree = proto_item_add_subtree(ti, ett_pgm); cursor = ptvcursor_new(pgm_tree, tvb, 0); hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 0, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 2, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); ptvcursor_add(cursor, hf_pgm_main_sport, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_dport, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_type, 1, ENC_BIG_ENDIAN); tf = proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_opts, tvb, ptvcursor_current_offset(cursor), 1, pgmhdr_opts, "%s (0x%x)", optsstr(pgmhdr_opts), pgmhdr_opts); opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_opt, 1, ENC_BIG_ENDIAN); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_netsig, 1, ENC_BIG_ENDIAN); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_varlen, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_opts_parity, 1, ENC_BIG_ENDIAN); ptvcursor_set_tree(cursor, pgm_tree); /* Checksum may be 0 (not available), but not for DATA packets */ if ((pgmhdr_type != PGM_RDATA_PCKT) && (pgmhdr_type != PGM_ODATA_PCKT) && (pgmhdr_cksum == 0)) { proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "not available"); } else { reportedlen = tvb_reported_length(tvb); pgmlen = tvb_captured_length(tvb); if (pgm_check_checksum && pgmlen >= reportedlen) { vec_t cksum_vec[1]; guint16 computed_cksum; SET_CKSUM_VEC_TVB(cksum_vec[0], tvb, 0, pgmlen); computed_cksum = in_cksum(&cksum_vec[0], 1); if (computed_cksum == 0) { proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "0x%04x [correct]", pgmhdr_cksum); } else { hidden_item = proto_tree_add_boolean(pgm_tree, hf_pgm_main_cksum_bad, tvb, ptvcursor_current_offset(cursor), 2, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_uint_format_value(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "0x%04x [incorrect, should be 0x%04x]", pgmhdr_cksum, in_cksum_shouldbe(pgmhdr_cksum, computed_cksum)); } } else { ptvcursor_add_no_advance(cursor, hf_pgm_main_cksum, 2, ENC_BIG_ENDIAN); } } ptvcursor_advance(cursor, 2); ptvcursor_add(cursor, hf_pgm_main_gsi, 6, ENC_NA); ptvcursor_add(cursor, hf_pgm_main_tsdulen, 2, ENC_BIG_ENDIAN); switch(pgmhdr_type) { case PGM_SPM_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_spm, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_lead, 4, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_spm_pathafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_res, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_spm_path, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_spm_path6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); ptvcursor_free(cursor); return; } break; case PGM_RDATA_PCKT: case PGM_ODATA_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_data, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); break; case PGM_NAK_PCKT: case PGM_NNAK_PCKT: case PGM_NCF_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_nak, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_nak_sqn, 4, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_nak_srcafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_nak_srcres, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_nak_src, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_nak_src6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); break; } afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_nak_grpafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_nak_grpres, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_nak_grp, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_nak_grp6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); ptvcursor_free(cursor); return; } break; case PGM_POLL_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_poll, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_poll_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_round, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_subtype, 2, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_poll_pathafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_res, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_poll_path, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_poll_path6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); break; } ptvcursor_add(cursor, hf_pgm_poll_backoff_ivl, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_rand_str, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_matching_bmask, 4, ENC_BIG_ENDIAN); break; case PGM_POLR_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_polr, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_polr_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_polr_round, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_polr_res, 2, ENC_BIG_ENDIAN); break; case PGM_ACK_PCKT: type_tree = proto_tree_add_subtree_format(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, ett_pgm_ack, NULL, "%s Packet", pktname); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_ack_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_ack_bitmap, 4, ENC_BIG_ENDIAN); break; } if (pgmhdr_opts & PGM_OPT) dissect_pgmopts(cursor, pinfo, pktname); if (isdata) decode_pgm_ports(tvb, ptvcursor_current_offset(cursor), pinfo, tree, pgmhdr_sport, pgmhdr_dport); ptvcursor_free(cursor); } }
static void display_xip_serval(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *xip_serval_tree; proto_item *ti, *check_ti, *hl_ti; tvbuff_t *next_tvb; vec_t cksum_vec; gint offset; guint16 packet_checksum, actual_checksum; guint8 xsh_len, protocol, bytes_remaining; /* Get XIP Serval header length, stored as number of 32-bit words. */ xsh_len = tvb_get_guint8(tvb, XSRVL_LEN) << 2; /* Create XIP Serval header tree. */ ti = proto_tree_add_item(tree, proto_xip_serval, tvb, 0, xsh_len, ENC_NA); xip_serval_tree = proto_item_add_subtree(ti, ett_xip_serval_tree); /* Add XIP Serval header length. */ hl_ti = proto_tree_add_item(xip_serval_tree, hf_xip_serval_hl, tvb, XSRVL_LEN, 1, ENC_BIG_ENDIAN); proto_item_append_text(hl_ti, " bytes"); if (tvb_captured_length(tvb) < xsh_len) expert_add_info_format(pinfo, hl_ti, &ei_xip_serval_bad_len, "Header Length field (%d bytes) cannot be greater than actual number of bytes left in packet (%d bytes)", xsh_len, tvb_captured_length(tvb)); /* Add XIP Serval protocol. If it's not data, TCP, or UDP, the * packet is malformed. */ proto_tree_add_item(xip_serval_tree, hf_xip_serval_proto, tvb, XSRVL_PRO, 1, ENC_BIG_ENDIAN); protocol = tvb_get_guint8(tvb, XSRVL_PRO); if (!try_val_to_str(protocol, xip_serval_proto_vals)) expert_add_info_format(pinfo, ti, &ei_xip_serval_bad_proto, "Unrecognized protocol type: %d", protocol); /* Compute checksum. */ SET_CKSUM_VEC_TVB(cksum_vec, tvb, 0, xsh_len); actual_checksum = in_cksum(&cksum_vec, 1); /* Get XIP Serval checksum. */ packet_checksum = tvb_get_ntohs(tvb, XSRVL_CHK); if (actual_checksum == 0) { /* Add XIP Serval checksum as correct. */ proto_tree_add_uint_format(xip_serval_tree, hf_xip_serval_check, tvb, XSRVL_CHK, 2, packet_checksum, "Header checksum: 0x%04x [correct]", packet_checksum); } else { /* Add XIP Serval checksum as incorrect. */ check_ti = proto_tree_add_uint_format(xip_serval_tree, hf_xip_serval_check, tvb, XSRVL_CHK, 2, packet_checksum, "Header checksum: 0x%04x [incorrect, should be 0x%04x]", packet_checksum, in_cksum_shouldbe(packet_checksum, actual_checksum)); expert_add_info_format(pinfo, check_ti, &ei_xip_serval_bad_checksum, "Bad checksum"); } offset = XSRVL_EXT; /* If there's still more room, check for extension headers. */ bytes_remaining = xsh_len - offset; while (bytes_remaining >= XIP_SERVAL_EXT_MIN_LEN) { gint8 bytes_displayed = display_xip_serval_ext(tvb, pinfo, ti, xip_serval_tree, offset); /* Extension headers are malformed, so we can't say * what the rest of the packet holds. Stop dissecting. */ if (bytes_displayed <= 0) return; offset += bytes_displayed; bytes_remaining -= bytes_displayed; } switch (protocol) { case XIP_SERVAL_PROTO_DATA: next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(data_handle, next_tvb, pinfo, tree); break; case IP_PROTO_TCP: { /* Get the Data Offset field of the TCP header, which is * the high nibble of the 12th octet and represents the * size of the TCP header of 32-bit words. */ guint8 tcp_len = hi_nibble(tvb_get_guint8(tvb, offset + 12))*4; next_tvb = tvb_new_subset(tvb, offset, tcp_len, tcp_len); call_dissector(tcp_handle, next_tvb, pinfo, tree); break; } case IP_PROTO_UDP: /* The UDP header is always 8 bytes. */ next_tvb = tvb_new_subset(tvb, offset, 8, 8); call_dissector(udp_handle, next_tvb, pinfo, tree); break; default: break; } }
static void dissect_stt_checksum(tvbuff_t *tvb, packet_info *pinfo, proto_tree *stt_tree) { proto_tree *checksum_tree; proto_item *item; guint16 checksum = tvb_get_ntohs(tvb, 16); gboolean can_checksum; guint16 computed_cksum; gboolean checksum_good = FALSE, checksum_bad = FALSE; item = proto_tree_add_uint_format_value(stt_tree, hf_stt_checksum, tvb, 16, 2, checksum, "0x%04x", checksum); can_checksum = !pinfo->fragmented && tvb_bytes_exist(tvb, 0, tvb_reported_length(tvb)); if (can_checksum && pref_check_checksum) { vec_t cksum_vec[4]; guint32 phdr[2]; /* Set up the fields of the pseudo-header. */ SET_CKSUM_VEC_PTR(cksum_vec[0], (const guint8 *)pinfo->src.data, pinfo->src.len); SET_CKSUM_VEC_PTR(cksum_vec[1], (const guint8 *)pinfo->dst.data, pinfo->dst.len); switch (pinfo->src.type) { case AT_IPv4: phdr[0] = g_htonl((IP_PROTO_TCP<<16) + tvb_reported_length(tvb)); SET_CKSUM_VEC_PTR(cksum_vec[2], (const guint8 *)phdr, 4); break; case AT_IPv6: phdr[0] = g_htonl(tvb_reported_length(tvb)); phdr[1] = g_htonl(IP_PROTO_TCP); SET_CKSUM_VEC_PTR(cksum_vec[2], (const guint8 *)phdr, 8); break; default: /* STT runs only atop IPv4 and IPv6.... */ DISSECTOR_ASSERT_NOT_REACHED(); break; } SET_CKSUM_VEC_TVB(cksum_vec[3], tvb, 0, tvb_reported_length(tvb)); computed_cksum = in_cksum(cksum_vec, 4); checksum_good = (computed_cksum == 0); checksum_bad = !checksum_good; if (checksum_good) { proto_item_append_text(item, " [correct]"); } else if (checksum_bad) { guint16 expected_cksum = in_cksum_shouldbe(checksum, computed_cksum); proto_item_append_text(item, " [incorrect, should be 0x%04x (maybe caused by \"TCP checksum offload\"?)]", expected_cksum); expert_add_info(pinfo, item, &ei_stt_checksum_bad); checksum = expected_cksum; } } else if (pref_check_checksum) { proto_item_append_text(item, " [unchecked, not all data available]"); } else { proto_item_append_text(item, " [validation disabled]"); } checksum_tree = proto_item_add_subtree(item, ett_stt_checksum); if (checksum_good || checksum_bad) { item = proto_tree_add_uint(checksum_tree, hf_stt_checksum_calculated, tvb, 16, 2, checksum); PROTO_ITEM_SET_GENERATED(item); } item = proto_tree_add_boolean(checksum_tree, hf_stt_checksum_good, tvb, 16, 2, checksum_good); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_stt_checksum_bad, tvb, 16, 2, checksum_bad); PROTO_ITEM_SET_GENERATED(item); }