static void dissect_v5dl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *v5dl_tree, *addr_tree; proto_item *v5dl_ti, *addr_ti; int direction; guint v5dl_header_len; guint16 control; #if 0 proto_tree *checksum_tree; proto_item *checksum_ti; guint16 checksum, checksum_calculated; guint checksum_offset; #endif guint16 addr, cr, eah, eal, v5addr; gboolean is_response = 0; #if 0 guint length, reported_length; #endif tvbuff_t *next_tvb; const char *srcname = "?"; const char *dstname = "?"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "V5DL"); col_clear(pinfo->cinfo, COL_INFO); addr = tvb_get_ntohs(tvb, 0); cr = addr & V5DL_CR; eal = (addr & V5DL_EAL) >> V5DL_EAL_SHIFT; eah = (addr & V5DL_EAH) >> V5DL_EAH_SHIFT; v5addr = (eah << 7) + eal; v5dl_header_len = 2; /* addr */ direction = pinfo->p2p_dir; if (pinfo->p2p_dir == P2P_DIR_RECV) { is_response = cr ? FALSE : TRUE; srcname = "Network"; dstname = "User"; } else if (pinfo->p2p_dir == P2P_DIR_SENT) { is_response = cr ? TRUE : FALSE; srcname = "User"; dstname = "Network"; } col_set_str(pinfo->cinfo, COL_RES_DL_SRC, srcname); col_set_str(pinfo->cinfo, COL_RES_DL_DST, dstname); if (tree) { proto_item *direction_ti; v5dl_ti = proto_tree_add_item(tree, proto_v5dl, tvb, 0, -1, ENC_NA); v5dl_tree = proto_item_add_subtree(v5dl_ti, ett_v5dl); /* * Don't show the direction if we don't know it. */ if (direction != P2P_DIR_UNKNOWN) { direction_ti = proto_tree_add_uint(v5dl_tree, hf_v5dl_direction, tvb, 0, 0, pinfo->p2p_dir); PROTO_ITEM_SET_GENERATED(direction_ti); } addr_ti = proto_tree_add_uint(v5dl_tree, hf_v5dl_ef, tvb, 0, 2, v5addr); addr_tree = proto_item_add_subtree(addr_ti, ett_v5dl_address); proto_tree_add_uint(addr_tree, hf_v5dl_eah, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_v5dl_cr, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_v5dl_ea1, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_v5dl_eal, tvb, 1, 1, addr); proto_tree_add_uint(addr_tree, hf_v5dl_ea2, tvb, 1, 1, addr); } else { v5dl_ti = NULL; v5dl_tree = NULL; } control = dissect_xdlc_control(tvb, 2, pinfo, v5dl_tree, hf_v5dl_control, ett_v5dl_control, &v5dl_cf_items, &v5dl_cf_items_ext, NULL, NULL, is_response, TRUE, FALSE); v5dl_header_len += XDLC_CONTROL_LEN(control, TRUE); if (tree) proto_item_set_len(v5dl_ti, v5dl_header_len); /* * XXX - the sample capture supplied with bug 7027 does not * appear to include checksums in the packets. */ #if 0 /* * Check the checksum, if available. * The checksum is a CCITT CRC-16 at the end of the packet, so * if we don't have the entire packet in the capture - i.e., if * tvb_captured_length(tvb) != tvb_reported_length(tvb) we can't check it. */ length = tvb_captured_length(tvb); reported_length = tvb_reported_length(tvb); /* * If the reported length isn't big enough for the V5DL header * and 2 bytes of checksum, the packet is malformed, as the * checksum overlaps the header. */ if (reported_length < v5dl_header_len + 2) THROW(ReportedBoundsError); if (length == reported_length) { /* * There's no snapshot length cutting off any of the * packet. */ checksum_offset = reported_length - 2; checksum = tvb_get_ntohs(tvb, checksum_offset); checksum_calculated = crc16_ccitt_tvb(tvb, checksum_offset); checksum_calculated = g_htons(checksum_calculated); /* Note: g_htons() macro may eval arg multiple times */ if (checksum == checksum_calculated) { checksum_ti = proto_tree_add_uint_format_value(v5dl_tree, hf_v5dl_checksum, tvb, checksum_offset, 2, 0, "0x%04x [correct]", checksum); checksum_tree = proto_item_add_subtree(checksum_ti, ett_v5dl_checksum); proto_tree_add_boolean(checksum_tree, hf_v5dl_checksum_good, tvb, checksum_offset, 2, TRUE); proto_tree_add_boolean(checksum_tree, hf_v5dl_checksum_bad, tvb, checksum_offset, 2, FALSE); } else { checksum_ti = proto_tree_add_uint_format_value(v5dl_tree, hf_v5dl_checksum, tvb, checksum_offset, 2, 0, "0x%04x [incorrect, should be 0x%04x]", checksum, checksum_calculated); checksum_tree = proto_item_add_subtree(checksum_ti, ett_v5dl_checksum); proto_tree_add_boolean(checksum_tree, hf_v5dl_checksum_good, tvb, checksum_offset, 2, FALSE); proto_tree_add_boolean(checksum_tree, hf_v5dl_checksum_bad, tvb, checksum_offset, 2, TRUE); } /* * Remove the V5DL header *and* the checksum. */ next_tvb = tvb_new_subset(tvb, v5dl_header_len, tvb_captured_length_remaining(tvb, v5dl_header_len) - 2, tvb_reported_length_remaining(tvb, v5dl_header_len) - 2); } else { /* * Some or all of the packet is cut off by a snapshot * length. */ if (length == reported_length - 1) { /* * One byte is cut off, so there's only one * byte of checksum in the captured data. * Remove that byte from the captured length * and both bytes from the reported length. */ next_tvb = tvb_new_subset(tvb, v5dl_header_len, tvb_captured_length_remaining(tvb, v5dl_header_len) - 1, tvb_reported_length_remaining(tvb, v5dl_header_len) - 2); } else { /* * Two or more bytes are cut off, so there are * no bytes of checksum in the captured data. * Just remove the checksum from the reported * length. */ next_tvb = tvb_new_subset(tvb, v5dl_header_len, tvb_captured_length_remaining(tvb, v5dl_header_len), tvb_reported_length_remaining(tvb, v5dl_header_len) - 2); } } #else next_tvb = tvb_new_subset_remaining(tvb, v5dl_header_len); #endif if (XDLC_IS_INFORMATION(control)) { /* call V5.2 dissector */ call_dissector(v52_handle, next_tvb, pinfo, tree); } }
/* Code to actually dissect the packets */ static void dissect_ehdlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 4; col_set_str(pinfo->cinfo, COL_PROTOCOL, "EHDLC"); col_clear(pinfo->cinfo, COL_INFO); while (tvb_reported_length_remaining(tvb, offset) > 0) { proto_item *ti = NULL; proto_tree *ehdlc_tree = NULL; guint16 len, msg_type; tvbuff_t *next_tvb; guint16 control; gboolean is_response = FALSE, is_extended = TRUE; gint header_length = 2; /* Address + Length field */ msg_type = tvb_get_guint8(tvb, offset); len = tvb_get_guint8(tvb, offset+1); #if 0 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str(msg_type, ehdlc_protocol_vals, "unknown 0x%02x")); #endif if (tree) { /* Use MIN(...,...) in the following to prevent a premature */ /* exception before we try to dissect whatever is available. */ ti = proto_tree_add_protocol_format(tree, proto_ehdlc, tvb, offset, MIN(len, tvb_length_remaining(tvb,offset)), "Ericsson HDLC protocol, type: %s", val_to_str(msg_type, ehdlc_protocol_vals, "unknown 0x%02x")); ehdlc_tree = proto_item_add_subtree(ti, ett_ehdlc); proto_tree_add_item(ehdlc_tree, hf_ehdlc_protocol, tvb, offset, 1, ENC_BIG_ENDIAN); #if 0 proto_tree_add_item(ehdlc_tree, hf_ehdlc_sapi, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ehdlc_tree, hf_ehdlc_c_r, tvb, offset, 1, ENC_BIG_ENDIAN); #endif proto_tree_add_item(ehdlc_tree, hf_ehdlc_data_len, tvb, offset+1, 1, ENC_BIG_ENDIAN); } control = dissect_xdlc_control(tvb, offset+2, pinfo, ehdlc_tree, hf_ehdlc_control, ett_ehdlc_control, &ehdlc_cf_items, &ehdlc_cf_items_ext, NULL, NULL, is_response, is_extended, FALSE); header_length += XDLC_CONTROL_LEN(control, is_extended); if (XDLC_IS_INFORMATION(control)) { next_tvb = tvb_new_subset(tvb, offset+header_length, len-header_length, len-header_length); switch (msg_type) { case 0x20: /* len == 4 seems to be some kind of ACK */ if (len <= 4) break; call_dissector(sub_handles[SUB_RSL], next_tvb, pinfo, tree); break; case 0xbc: case 0xdc: case 0xa0: case 0xc0: /* len == 4 seems to be some kind of ACK */ if (len <= 4) break; call_dissector(sub_handles[SUB_OML], next_tvb, pinfo, tree); break; default: call_dissector(sub_handles[SUB_DATA], next_tvb, pinfo, tree); break; } } else if (control == (XDLC_U | XDLC_XID)) { /* XID is formatted like ISO 8885, typically we see * something like * 82 format identifier * 80 group identifier * 00 09 length * 07 01 05 Window Size Tx * 09 01 04 Ack Timer (msec) * 08 01 05 Window Size Rx */ proto_tree_add_item(ehdlc_tree, hf_ehdlc_xid_payload, tvb, offset+header_length, len-header_length, ENC_NA); } if (len == 0) len = 1; offset += len; } }
void capture_llc(const guchar *pd, int offset, int len, packet_counts *ld) { int is_snap; guint16 control; int llc_header_len; if (!BYTES_ARE_IN_FRAME(offset, len, 2)) { ld->other++; return; } is_snap = (pd[offset] == SAP_SNAP) && (pd[offset+1] == SAP_SNAP); llc_header_len = 2; /* DSAP + SSAP */ /* * XXX - the page referred to in the comment above about the * Command/Response bit also implies that LLC Type 2 always * uses extended operation, so we don't need to determine * whether it's basic or extended operation; is that the case? */ control = get_xdlc_control(pd, offset+2, pd[offset+1] & SSAP_CR_BIT); llc_header_len += XDLC_CONTROL_LEN(control, TRUE); if (!BYTES_ARE_IN_FRAME(offset, len, llc_header_len)) { ld->other++; return; } if (!XDLC_IS_INFORMATION(control)) { ld->other++; return; } if (is_snap) capture_snap(pd, offset+llc_header_len, len, ld); else { /* non-SNAP */ switch (pd[offset]) { case SAP_IP: capture_ip(pd, offset + llc_header_len, len, ld); break; case SAP_NETWARE1: case SAP_NETWARE2: capture_ipx(ld); break; case SAP_NETBIOS: capture_netbios(ld); break; case SAP_VINES1: case SAP_VINES2: capture_vines(ld); break; default: ld->other++; break; } } }
static void dissect_sdlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *sdlc_tree; proto_item *sdlc_ti; guint8 addr; guint16 control; int sdlc_header_len; gboolean is_response; tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SDLC"); col_clear(pinfo->cinfo, COL_INFO); addr = tvb_get_guint8(tvb, 0); sdlc_header_len = 1; /* address */ /* * XXX - is there something in the SDLC header that indicates * how to interpret "command vs. response" based on the * direction? */ if (pinfo->p2p_dir == P2P_DIR_SENT) { is_response = FALSE; col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE"); col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE"); } else { /* XXX - what if the direction is unknown? */ is_response = TRUE; col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE"); col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE"); } if (tree) { sdlc_ti = proto_tree_add_item(tree, proto_sdlc, tvb, 0, -1, FALSE); sdlc_tree = proto_item_add_subtree(sdlc_ti, ett_sdlc); proto_tree_add_uint(sdlc_tree, hf_sdlc_address, tvb, 0, 1, addr); } else { sdlc_ti = NULL; sdlc_tree = NULL; } /* * XXX - SDLC has a mod-128 mode as well as a mod-7 mode. * We can infer the mode from an SNRM/SRME frame, but if * we don't see one of them, we may have to have a preference * to control what to use. */ control = dissect_xdlc_control(tvb, 1, pinfo, sdlc_tree, hf_sdlc_control, ett_sdlc_control, &sdlc_cf_items, NULL, NULL, NULL, is_response, FALSE, FALSE); sdlc_header_len += XDLC_CONTROL_LEN(control, FALSE); if (tree) proto_item_set_len(sdlc_ti, sdlc_header_len); /* * XXX - is there an FCS at the end, at least in Sniffer * captures? (There doesn't appear to be.) */ next_tvb = tvb_new_subset_remaining(tvb, sdlc_header_len); if (XDLC_IS_INFORMATION(control)) { /* call the SNA dissector */ call_dissector(sna_handle, next_tvb, pinfo, tree); } else call_dissector(data_handle, next_tvb, pinfo, tree); }
static void dissect_llc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *llc_tree = NULL; proto_item *ti = NULL; int is_snap; guint16 control; int llc_header_len; guint8 dsap, ssap, format; tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLC"); col_clear(pinfo->cinfo, COL_INFO); dsap = tvb_get_guint8(tvb, 0); if (tree) { ti = proto_tree_add_item(tree, proto_llc, tvb, 0, -1, ENC_NA); llc_tree = proto_item_add_subtree(ti, ett_llc); proto_tree_add_uint(llc_tree, hf_llc_dsap, tvb, 0, 1, dsap & SAP_MASK); proto_tree_add_boolean(llc_tree, hf_llc_dsap_ig, tvb, 0, 1, dsap & DSAP_GI_BIT); } else llc_tree = NULL; ssap = tvb_get_guint8(tvb, 1); if (tree) { proto_tree_add_uint(llc_tree, hf_llc_ssap, tvb, 1, 1, ssap & SAP_MASK); proto_tree_add_boolean(llc_tree, hf_llc_ssap_cr, tvb, 1, 1, ssap & SSAP_CR_BIT); } else llc_tree = NULL; is_snap = (dsap == SAP_SNAP) && (ssap == SAP_SNAP); llc_header_len = 2; /* DSAP + SSAP */ /* * XXX - the page referred to in the comment above about the * Command/Response bit also implies that LLC Type 2 always * uses extended operation, so we don't need to determine * whether it's basic or extended operation; is that the case? */ control = dissect_xdlc_control(tvb, 2, pinfo, llc_tree, hf_llc_ctrl, ett_llc_ctrl, &llc_cf_items, &llc_cf_items_ext, NULL, NULL, ssap & SSAP_CR_BIT, TRUE, FALSE); llc_header_len += XDLC_CONTROL_LEN(control, TRUE); if (is_snap) llc_header_len += 5; /* 3 bytes of OUI, 2 bytes of protocol ID */ if (tree) proto_item_set_len(ti, llc_header_len); if (is_snap) { dissect_snap(tvb, 2+XDLC_CONTROL_LEN(control, TRUE), pinfo, tree, llc_tree, control, hf_llc_oui, hf_llc_type, hf_llc_pid, 2); } else { col_append_fstr(pinfo->cinfo, COL_INFO, "; DSAP %s %s, SSAP %s %s", val_to_str(dsap & SAP_MASK, sap_vals, "0x%02x"), dsap & DSAP_GI_BIT ? "Group" : "Individual", val_to_str(ssap & SAP_MASK, sap_vals, "0x%02x"), ssap & SSAP_CR_BIT ? "Response" : "Command" ); if (tvb_length_remaining(tvb, llc_header_len) > 0) { next_tvb = tvb_new_subset_remaining(tvb, llc_header_len); if (XDLC_IS_INFORMATION(control)) { /* * Non-SNAP I or UI frame. * Try the regular LLC subdissector table * with the DSAP. */ if (!dissector_try_uint(dsap_subdissector_table, dsap, next_tvb, pinfo, tree)) { call_dissector(data_handle, next_tvb, pinfo, tree); } } else if ((control & (XDLC_U_MODIFIER_MASK|XDLC_U)) == (XDLC_XID|XDLC_U)) { /* * Non-SNAP XID frame. * Test for LLC basic format first */ format = tvb_get_guint8(next_tvb, 0); if (format == 0x81) { dissect_basicxid(next_tvb, pinfo, tree); } else { /* * Try the XID LLC subdissector table * with the DSAP. */ if (!dissector_try_uint( xid_subdissector_table, dsap, next_tvb, pinfo, tree)) { call_dissector(data_handle, next_tvb, pinfo, tree); } } } else { call_dissector(data_handle, next_tvb, pinfo, tree); } } } }