static int dissect_netmon_802_11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ieee_802_11_phdr *phdr = (struct ieee_802_11_phdr *)data; proto_tree *wlan_tree = NULL, *opmode_tree; proto_item *ti; tvbuff_t *next_tvb; int offset; guint8 version; guint16 length; guint32 phy_type; guint32 flags; guint32 channel; gint calc_channel; gint32 rssi; guint8 rate; col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN"); col_clear(pinfo->cinfo, COL_INFO); offset = 0; version = tvb_get_guint8(tvb, offset); length = tvb_get_letohs(tvb, offset+1); col_add_fstr(pinfo->cinfo, COL_INFO, "NetMon WLAN Capture v%u, Length %u", version, length); if (version != 2) { /* XXX - complain */ goto skip; } if (length < MIN_HEADER_LEN) { /* XXX - complain */ goto skip; } /* Dissect the packet */ ti = proto_tree_add_item(tree, proto_netmon_802_11, tvb, 0, length, ENC_NA); wlan_tree = proto_item_add_subtree(ti, ett_netmon_802_11); /* * XXX - is this the NDIS_OBJECT_HEADER structure: * * https://msdn.microsoft.com/en-us/library/windows/hardware/ff566588(v=vs.85).aspx * * at the beginning of a DOT11_EXTSTA_RECV_CONTEXT structure: * * https://msdn.microsoft.com/en-us/library/windows/hardware/ff548626(v=vs.85).aspx * * If so, the byte at an offset of 0 would be the appropriate type for the * structure following it, i.e. NDIS_OBJECT_TYPE_DEFAULT. */ proto_tree_add_item(wlan_tree, hf_netmon_802_11_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(wlan_tree, hf_netmon_802_11_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* * This isn't in the DOT11_EXTSTA_RECV_CONTEXT structure. */ ti = proto_tree_add_item(wlan_tree, hf_netmon_802_11_op_mode, tvb, offset, 4, ENC_LITTLE_ENDIAN); opmode_tree = proto_item_add_subtree(ti, ett_netmon_802_11_op_mode); proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_ap, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_sta_ext, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(opmode_tree, hf_netmon_802_11_op_mode_mon, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* * uReceiveFlags? */ flags = tvb_get_letohl(tvb, offset); offset += 4; if (flags != 0xffffffff) { /* * uPhyId? */ phy_type = tvb_get_letohl(tvb, offset); memset(&phdr->phy_info, 0, sizeof(phdr->phy_info)); switch (phy_type) { case PHY_TYPE_UNKNOWN: phdr->phy = PHDR_802_11_PHY_UNKNOWN; break; case PHY_TYPE_FHSS: phdr->phy = PHDR_802_11_PHY_11_FHSS; break; case PHY_TYPE_IR_BASEBAND: phdr->phy = PHDR_802_11_PHY_11_IR; break; case PHY_TYPE_DSSS: phdr->phy = PHDR_802_11_PHY_11_DSSS; break; case PHY_TYPE_HR_DSSS: phdr->phy = PHDR_802_11_PHY_11B; break; case PHY_TYPE_OFDM: phdr->phy = PHDR_802_11_PHY_11A; break; case PHY_TYPE_ERP: phdr->phy = PHDR_802_11_PHY_11G; break; case PHY_TYPE_HT: phdr->phy = PHDR_802_11_PHY_11N; break; case PHY_TYPE_VHT: phdr->phy = PHDR_802_11_PHY_11AC; break; default: phdr->phy = PHDR_802_11_PHY_UNKNOWN; break; } proto_tree_add_item(wlan_tree, hf_netmon_802_11_phy_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* * uChCenterFrequency? */ channel = tvb_get_letohl(tvb, offset); if (channel < 1000) { if (channel == 0) { proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_channel, tvb, offset, 4, channel, "Unknown"); } else { guint frequency; phdr->has_channel = TRUE; phdr->channel = channel; proto_tree_add_uint(wlan_tree, hf_netmon_802_11_channel, tvb, offset, 4, channel); switch (phdr->phy) { case PHDR_802_11_PHY_11B: case PHDR_802_11_PHY_11G: /* 2.4 GHz channel */ frequency = ieee80211_chan_to_mhz(channel, TRUE); break; case PHDR_802_11_PHY_11A: /* 5 GHz channel */ frequency = ieee80211_chan_to_mhz(channel, FALSE); break; default: frequency = 0; break; } if (frequency != 0) { phdr->has_frequency = TRUE; phdr->frequency = frequency; } } } else { phdr->has_frequency = TRUE; phdr->frequency = channel; proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_frequency, tvb, offset, 4, channel, "%u Mhz", channel); calc_channel = ieee80211_mhz_to_chan(channel); if (calc_channel != -1) { phdr->has_channel = TRUE; phdr->channel = calc_channel; } } offset += 4; /* * usNumberOfMPDUsReceived is missing. */ /* * lRSSI? */ rssi = tvb_get_letohl(tvb, offset); if (rssi == 0) { proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi, tvb, offset, 4, rssi, "Unknown"); } else { phdr->has_signal_dbm = TRUE; phdr->signal_dbm = rssi; proto_tree_add_int_format_value(wlan_tree, hf_netmon_802_11_rssi, tvb, offset, 4, rssi, "%d dBm", rssi); } offset += 4; /* * ucDataRate? */ rate = tvb_get_guint8(tvb, offset); if (rate == 0) { proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate, tvb, offset, 1, rate, "Unknown"); } else { phdr->has_data_rate = TRUE; phdr->data_rate = rate; proto_tree_add_uint_format_value(wlan_tree, hf_netmon_802_11_datarate, tvb, offset, 1, rate, "%f Mb/s", rate*.5); } offset += 1; } else offset += 13; /* * ullTimestamp? * * If so, should this check the presense flag in flags? */ phdr->has_tsf_timestamp = TRUE; phdr->tsf_timestamp = tvb_get_letoh64(tvb, offset); proto_tree_add_item(wlan_tree, hf_netmon_802_11_timestamp, tvb, offset, 8, ENC_LITTLE_ENDIAN); /*offset += 8;*/ skip: offset = length; /* dissect the 802.11 packet next */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector_with_data(ieee80211_radio_handle, next_tvb, pinfo, tree, phdr); return offset; }
static void dissect_rtacser_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *rtacser_item, *ts_item, *cl_item, *data_payload; proto_tree *rtacser_tree, *cl_tree; int offset = 0, len; guint event_type; guint32 timestamp1, timestamp2; gboolean cts, dcd, dsr, rts, dtr, ring, mbok; tvbuff_t *payload_tvb; len = RTACSER_HEADER_LEN; /* Make entries in Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTAC Serial"); col_clear(pinfo->cinfo, COL_INFO); rtacser_item = proto_tree_add_protocol_format(tree, proto_rtacser, tvb, 0, len, "RTAC Serial Line"); rtacser_tree = proto_item_add_subtree(rtacser_item, ett_rtacser); /* Time-stamp is stored as 2 x 32-bit unsigned integers, the left and right-hand side of the decimal point respectively */ /* The format mirrors the timeval struct - absolute Epoch time (seconds since 1/1/1970) with an added microsecond component */ timestamp1 = tvb_get_ntohl(tvb, offset); timestamp2 = tvb_get_ntohl(tvb, offset+4); ts_item = proto_tree_add_item(rtacser_tree, hf_rtacser_timestamp, tvb, offset, 8, ENC_BIG_ENDIAN); proto_item_set_text(ts_item, "Arrived At Time: %u.%u" , timestamp1, timestamp2); offset += 8; /* Set INFO column with RTAC Serial Event Type */ event_type = tvb_get_guint8(tvb, offset); col_add_fstr(pinfo->cinfo, COL_INFO, "%-21s", val_to_str_const(event_type, rtacser_eventtype_vals, "Unknown Type")); /* Add event type to tree */ proto_tree_add_item(rtacser_tree, hf_rtacser_event_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* Retrieve EIA-232 serial control line states */ cts = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_CTS; dcd = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_DCD; dsr = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_DSR; rts = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_RTS; dtr = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_DTR; ring = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_RING; mbok = tvb_get_guint8(tvb, offset) & RTACSER_CTRL_MBOK; cl_tree = proto_tree_add_subtree(rtacser_tree, tvb, offset, 1, ett_rtacser_cl, &cl_item, "Control Lines"); /* Add UART Control Line information to INFO column */ col_append_str(pinfo->cinfo, COL_INFO, " ( "); (cts) ? col_append_str(pinfo->cinfo, COL_INFO, "CTS") : col_append_str(pinfo->cinfo, COL_INFO, "/CTS"); (dcd) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "DCD") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/DCD"); (dsr) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "DSR") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/DSR"); (rts) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "RTS") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/RTS"); (dtr) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "DTR") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/DTR"); (ring) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "RING") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/RING"); (mbok) ? col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "MBOK") : col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "/MBOK"); col_append_str(pinfo->cinfo, COL_INFO, " )"); /* Add UART Control Line information to tree */ proto_item_append_text(cl_item, " ("); (cts) ? proto_item_append_text(cl_item, "CTS, ") : proto_item_append_text(cl_item, "/CTS, "); (dcd) ? proto_item_append_text(cl_item, "DCD, ") : proto_item_append_text(cl_item, "/DCD, "); (dsr) ? proto_item_append_text(cl_item, "DSR, ") : proto_item_append_text(cl_item, "/DSR, "); (rts) ? proto_item_append_text(cl_item, "RTS, ") : proto_item_append_text(cl_item, "/RTS, "); (dtr) ? proto_item_append_text(cl_item, "DTR, ") : proto_item_append_text(cl_item, "/DTR, "); (ring) ? proto_item_append_text(cl_item, "RING, ") : proto_item_append_text(cl_item, "/RING, "); (mbok) ? proto_item_append_text(cl_item, "MBOK") : proto_item_append_text(cl_item, "/MBOK"); proto_item_append_text(cl_item, ")"); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_cts, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_dcd, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_dsr, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_rts, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_dtr, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_ring, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(cl_tree, hf_rtacser_ctrl_mbok, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* 2-byte footer */ proto_tree_add_item(rtacser_tree, hf_rtacser_footer, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* If no payload dissector has been selected, indicate to the user the preferences options */ if ((tvb_reported_length_remaining(tvb, offset) > 0) && (global_rtacser_payload_proto == RTACSER_PAYLOAD_NONE)) { data_payload = proto_tree_add_item(tree, hf_rtacser_data, tvb, offset, -1, ENC_NA); proto_item_set_text(data_payload,"Payload Protocol not selected. Check 'Preferences-> Protocols-> RTAC Serial' for options"); return; } /* Determine correct message type and call appropriate dissector */ if (tvb_reported_length_remaining(tvb, RTACSER_HEADER_LEN) > 0) { switch (global_rtacser_payload_proto) { case RTACSER_PAYLOAD_SELFM: payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN); call_dissector(selfm_handle, payload_tvb, pinfo, tree); break; case RTACSER_PAYLOAD_DNP3: payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN); call_dissector(dnp3_handle, payload_tvb, pinfo, tree); break; case RTACSER_PAYLOAD_MODBUS: payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN); call_dissector(modbus_handle, payload_tvb, pinfo, tree); break; case RTACSER_PAYLOAD_SYNPHASOR: payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN); call_dissector(synphasor_handle, payload_tvb, pinfo, tree); break; case RTACSER_PAYLOAD_LG8979: payload_tvb = tvb_new_subset_remaining(tvb, RTACSER_HEADER_LEN); call_dissector(lg8979_handle, payload_tvb, pinfo, tree); break; default: break; } } }
static int dissect_json(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { proto_tree *json_tree = NULL; proto_item *ti = NULL; json_parser_data_t parser_data; tvbparse_t *tt; http_message_info_t *message_info; const char *data_name; int offset; /* JSON dissector can be called in a JSON native file or when transported * by another protocol. We set the column values only if they've not been * already set by someone else. */ wmem_list_frame_t *proto = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); if (proto) { const char *name = proto_get_protocol_filter_name(GPOINTER_TO_INT(wmem_list_frame_data(proto))); if (!strcmp(name, "frame")) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "JSON"); col_set_str(pinfo->cinfo, COL_INFO, "JavaScript Object Notation"); } } data_name = pinfo->match_string; if (! (data_name && data_name[0])) { /* * No information from "match_string" */ message_info = (http_message_info_t *)data; if (message_info == NULL) { /* * No information from dissector data */ data_name = NULL; } else { data_name = message_info->media_str; if (! (data_name && data_name[0])) { /* * No information from dissector data */ data_name = NULL; } } } if (tree) { ti = proto_tree_add_item(tree, hfi_json, tvb, 0, -1, ENC_NA); json_tree = proto_item_add_subtree(ti, ett_json); if (data_name) proto_item_append_text(ti, ": %s", data_name); } offset = 0; parser_data.stack = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.stack, json_tree); if (json_compact) { proto_tree *json_tree_compact = NULL; json_tree_compact = proto_tree_add_subtree(json_tree, tvb, 0, -1, ett_json_compact, NULL, "JSON compact form:"); parser_data.stack_compact = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.stack_compact, json_tree_compact); parser_data.array_idx = wmem_stack_new(wmem_packet_scope()); wmem_stack_push(parser_data.array_idx, GINT_TO_POINTER(JSON_COMPACT_TOP_ITEM)); /* top element */ } tt = tvbparse_init(tvb, offset, -1, &parser_data, want_ignore); /* XXX, only one json in packet? */ while ((tvbparse_get(tt, want))) ; offset = tvbparse_curr_offset(tt); proto_item_set_len(ti, offset); /* if we have some unparsed data, pass to data-text-lines dissector (?) */ if (tvb_reported_length_remaining(tvb, offset) > 0) { tvbuff_t *next_tvb; next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector_with_data(text_lines_handle, next_tvb, pinfo, tree, data); } else if (data_name) { col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name); } return tvb_captured_length(tvb); }
static int dissect_packetlogger(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_tree *packetlogger_tree = NULL; tvbuff_t *next_tvb; proto_item *ti = NULL; guint8 pl_type; gint len; bluetooth_data_t *bluetooth_data; struct bthci_phdr bthci; bluetooth_data = (bluetooth_data_t *) data; col_set_str (pinfo->cinfo, COL_PROTOCOL, PSNAME); col_clear (pinfo->cinfo, COL_INFO); ti = proto_tree_add_item (tree, proto_packetlogger, tvb, 0, -1, ENC_NA); packetlogger_tree = proto_item_add_subtree (ti, ett_packetlogger); pl_type = tvb_get_guint8 (tvb, 0); proto_tree_add_item (packetlogger_tree, hf_type, tvb, 0, 1, ENC_BIG_ENDIAN); proto_item_append_text (ti, " %s", val_to_str (pl_type, type_vals, "Unknown 0x%02x")); len = tvb_reported_length_remaining (tvb, 1); next_tvb = tvb_new_subset_remaining (tvb, 1); if (pl_type <= PKT_RECV_ACL_DATA) { /* HCI H1 packages */ switch (pl_type) { case PKT_HCI_COMMAND: bthci.channel = BTHCI_CHANNEL_COMMAND; bthci.sent = P2P_DIR_SENT; pinfo->p2p_dir = P2P_DIR_SENT; break; case PKT_HCI_EVENT: bthci.channel = BTHCI_CHANNEL_EVENT; bthci.sent = P2P_DIR_RECV; pinfo->p2p_dir = P2P_DIR_RECV; break; case PKT_SENT_ACL_DATA: bthci.channel = BTHCI_CHANNEL_ACL; bthci.sent = P2P_DIR_SENT; pinfo->p2p_dir = P2P_DIR_SENT; break; case PKT_RECV_ACL_DATA: bthci.channel = BTHCI_CHANNEL_ACL; bthci.sent = P2P_DIR_RECV; pinfo->p2p_dir = P2P_DIR_RECV; break; default: bthci.channel = pl_type; bthci.sent = P2P_DIR_UNKNOWN; pinfo->p2p_dir = P2P_DIR_UNKNOWN; break; } bluetooth_data->previous_protocol_data.bthci = &bthci; proto_item_set_len (ti, 1); col_add_fstr (pinfo->cinfo, COL_INFO, "%s", val_to_str(pl_type, type_vals, "Unknown 0x%02x")); if (!dissector_try_uint_new(hci_h1_table, bthci.channel, next_tvb, pinfo, tree, TRUE, bluetooth_data)) { call_dissector (data_handle, next_tvb, pinfo, tree); } } else { /* PacketLogger data */ switch (pl_type) { case PKT_POWER: case PKT_NOTE: case PKT_NEW_CONTROLLER: proto_tree_add_item (packetlogger_tree, hf_info, next_tvb, 0, len, ENC_ASCII|ENC_NA); col_add_fstr (pinfo->cinfo, COL_INFO, "%s", tvb_format_stringzpad_wsp (next_tvb, 0, len)); break; default: call_dissector (data_handle, next_tvb, pinfo, tree); col_add_fstr (pinfo->cinfo, COL_INFO, "Unknown 0x%02x", pl_type); break; } } return tvb_captured_length(tvb); }
static void dissect_wlancap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *wlan_tree = NULL; proto_item *ti; tvbuff_t *next_tvb; int offset; guint32 version; guint32 length; guint32 channel; guint32 datarate; guint32 ssi_type; guint32 antnoise; col_set_str(pinfo->cinfo, COL_PROTOCOL, "WLAN"); col_clear(pinfo->cinfo, COL_INFO); offset = 0; version = tvb_get_ntohl(tvb, offset) - WLANCAP_MAGIC_COOKIE_BASE; length = tvb_get_ntohl(tvb, offset+4); col_add_fstr(pinfo->cinfo, COL_INFO, "AVS WLAN Capture v%x, Length %d",version, length); if (version > 2) { goto skip; } /* Dissect the AVS header */ if (tree) { ti = proto_tree_add_item(tree, proto_wlancap, tvb, 0, length, ENC_NA); wlan_tree = proto_item_add_subtree(ti, ett_radio); proto_tree_add_item(wlan_tree, hf_wlan_magic, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(wlan_tree, hf_wlan_version, tvb, offset, 4, ENC_BIG_ENDIAN); } offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_mactime, tvb, offset, 8, ENC_BIG_ENDIAN); offset+=8; if (tree) proto_tree_add_item(wlan_tree, hf_hosttime, tvb, offset, 8, ENC_BIG_ENDIAN); offset+=8; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_phytype, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; /* XXX cook channel (fh uses different numbers) */ channel = tvb_get_ntohl(tvb, offset); if (channel < 256) { col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%u", channel); if (tree) proto_tree_add_uint(wlan_tree, hf_channel, tvb, offset, 4, channel); } else if (channel < 10000) { col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%u MHz", channel); if (tree) proto_tree_add_uint_format(wlan_tree, hf_channel_frequency, tvb, offset, 4, channel, "Frequency: %u MHz", channel); } else { col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%u KHz", channel); if (tree) proto_tree_add_uint_format(wlan_tree, hf_channel_frequency, tvb, offset, 4, channel, "Frequency: %u KHz", channel); } offset+=4; datarate = tvb_get_ntohl(tvb, offset); if (datarate < 100000) { /* In units of 100 Kb/s; convert to b/s */ datarate *= 100000; } col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%u.%u", datarate / 1000000, ((datarate % 1000000) > 500000) ? 5 : 0); if (tree) { proto_tree_add_uint64_format(wlan_tree, hf_data_rate, tvb, offset, 4, datarate, "Data Rate: %u.%u Mb/s", datarate/1000000, ((datarate % 1000000) > 500000) ? 5 : 0); } offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_antenna, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_priority, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; ssi_type = tvb_get_ntohl(tvb, offset); if (tree) proto_tree_add_uint(wlan_tree, hf_wlan_ssi_type, tvb, offset, 4, ssi_type); offset+=4; switch (ssi_type) { case SSI_NONE: default: /* either there is no SSI information, or we don't know what type it is */ break; case SSI_NORM_RSSI: /* Normalized RSSI */ col_add_fstr(pinfo->cinfo, COL_RSSI, "%u (norm)", tvb_get_ntohl(tvb, offset)); if (tree) proto_tree_add_item(wlan_tree, hf_normrssi_antsignal, tvb, offset, 4, ENC_BIG_ENDIAN); break; case SSI_DBM: /* dBm */ col_add_fstr(pinfo->cinfo, COL_RSSI, "%d dBm", tvb_get_ntohl(tvb, offset)); if (tree) proto_tree_add_item(wlan_tree, hf_dbm_antsignal, tvb, offset, 4, ENC_BIG_ENDIAN); break; case SSI_RAW_RSSI: /* Raw RSSI */ col_add_fstr(pinfo->cinfo, COL_RSSI, "%u (raw)", tvb_get_ntohl(tvb, offset)); if (tree) proto_tree_add_item(wlan_tree, hf_rawrssi_antsignal, tvb, offset, 4, ENC_BIG_ENDIAN); break; } offset+=4; antnoise = tvb_get_ntohl(tvb, offset); /* 0xffffffff means "hardware does not provide noise data" */ if (antnoise != 0xffffffff) { switch (ssi_type) { case SSI_NONE: default: /* either there is no SSI information, or we don't know what type it is */ break; case SSI_NORM_RSSI: /* Normalized RSSI */ if (tree) proto_tree_add_uint(wlan_tree, hf_normrssi_antnoise, tvb, offset, 4, antnoise); break; case SSI_DBM: /* dBm */ if (tree) proto_tree_add_int(wlan_tree, hf_dbm_antnoise, tvb, offset, 4, antnoise); break; case SSI_RAW_RSSI: /* Raw RSSI */ if (tree) proto_tree_add_uint(wlan_tree, hf_rawrssi_antnoise, tvb, offset, 4, antnoise); break; } } offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_preamble, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_encoding, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (version > 1) { if (tree) proto_tree_add_item(wlan_tree, hf_wlan_sequence, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_drops, tvb, offset, 4, ENC_BIG_ENDIAN); offset+=4; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_receiver_addr, tvb, offset, 6, ENC_NA); offset+=6; if (tree) proto_tree_add_item(wlan_tree, hf_wlan_padding, tvb, offset, 2, ENC_NA); offset+=2; } skip: offset = length; /* dissect the 802.11 header next */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(ieee80211_handle, next_tvb, pinfo, tree); }
void dissect_802_3(volatile int length, gboolean is_802_2, tvbuff_t *tvb, int offset_after_length, packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, int length_id, int trailer_id, expert_field* ei_len, int fcs_len) { proto_item *length_it; tvbuff_t *volatile next_tvb = NULL; tvbuff_t *trailer_tvb = NULL; const char *saved_proto; gint captured_length, reported_length; length_it = proto_tree_add_uint(fh_tree, length_id, tvb, offset_after_length - 2, 2, length); /* Get the length of the payload. If the FCS length is positive, remove the FCS. (If it's zero, there's no FCS; if it's negative, we don't know whether there's an FCS, so we'll guess based on the length of the trailer.) */ reported_length = tvb_reported_length_remaining(tvb, offset_after_length); if (fcs_len > 0) { if (reported_length >= fcs_len) reported_length -= fcs_len; } /* Make sure the length in the 802.3 header doesn't go past the end of the payload. */ if (length > reported_length) { length = reported_length; expert_add_info(pinfo, length_it, ei_len); } /* Give the next dissector only 'length' number of bytes. */ captured_length = tvb_captured_length_remaining(tvb, offset_after_length); if (captured_length > length) captured_length = length; next_tvb = tvb_new_subset(tvb, offset_after_length, captured_length, length); /* Dissect the payload either as IPX or as an LLC frame. Catch non-fatal exceptions, so that if the reported length of "next_tvb" was reduced by some dissector before an exception was thrown, we can still put in an item for the trailer. */ saved_proto = pinfo->current_proto; TRY { if (is_802_2) call_dissector(llc_handle, next_tvb, pinfo, tree); else { /* Check if first three bits of payload are 0x7. If so, then payload is IPX. If not, then it's CCSDS. Refer to packet-eth.c for setting of is_802_2 variable. */ if (tvb_get_bits8(next_tvb, 0, 3) == 7) call_dissector(ipx_handle, next_tvb, pinfo, tree); else call_dissector(ccsds_handle, next_tvb, pinfo, tree); } } CATCH_NONFATAL_ERRORS { /* Somebody threw an exception that means that there was a problem dissecting the payload; that means that a dissector was found, so we don't need to dissect the payload as data or update the protocol or info columns. Just show the exception and then drive on to show the trailer, after noting that a dissector was found and restoring the protocol value that was in effect before we called the subdissector. */ show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; /* Restore the protocol value, so that any exception thrown by tvb_new_subset_remaining() refers to the protocol for which this is a trailer. */ pinfo->current_proto = saved_proto; /* Construct a tvbuff for the trailer; if the trailer is past the end of the captured data, this will throw a BoundsError, which is what we want, as it'll report that the packet was cut short. */ trailer_tvb = tvb_new_subset_remaining(tvb, offset_after_length + length); add_ethernet_trailer(pinfo, tree, fh_tree, trailer_id, tvb, trailer_tvb, fcs_len); }
static void dissect_interlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_tree *il_tree = NULL; proto_tree *ilh_tree = NULL; proto_tree *ilb_tree = NULL; guint8 ilb_type; guint8 ilb_version; guint16 type_version = 0; dissector_handle_t handle; tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "INTERLINK"); col_clear(pinfo->cinfo, COL_INFO); if (tree) { proto_item *il_item; il_item = proto_tree_add_item(tree, proto_interlink, tvb, 0, 16, FALSE); if (il_item) il_tree = proto_item_add_subtree(il_item, ett_interlink); } if (il_tree) { proto_item *ilh_item = NULL; ilh_item = proto_tree_add_text(il_tree, tvb, 0, 12, "Interlink Header"); if (ilh_item) ilh_tree = proto_item_add_subtree(ilh_item, ett_interlink_header); } if (ilh_tree) { proto_tree_add_item(ilh_tree, hf_interlink_id, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_item(ilh_tree, hf_interlink_version, tvb, offset, 2, TRUE); offset += 2; proto_tree_add_item(ilh_tree, hf_interlink_cmd, tvb, offset, 2, TRUE); offset += 2; proto_tree_add_item(ilh_tree, hf_interlink_seq, tvb, offset, 2, TRUE); offset += 2; } if (ilh_tree) { proto_item *flags_item; proto_tree *flags_tree = NULL; flags_item = proto_tree_add_item(ilh_tree, hf_interlink_flags, tvb, offset, 2, TRUE); if (flags_item) { flags_tree = proto_item_add_subtree(flags_item, ett_interlink_flags); } if (flags_tree) { guint16 il_flags; il_flags = tvb_get_letohs(tvb, offset); proto_tree_add_boolean(flags_tree, hf_interlink_flags_req_ack, tvb, offset, 2, il_flags); proto_tree_add_boolean(flags_tree, hf_interlink_flags_inc_ack_port, tvb, offset, 2, il_flags); } } offset += 2; if (tree) { proto_item *ilb_item; ilb_item = proto_tree_add_text(il_tree, tvb, offset, 4, "Block Header"); if (ilb_item) ilb_tree = proto_item_add_subtree(ilb_item, ett_interlink_block); } ilb_type = tvb_get_guint8(tvb, offset); ilb_version = tvb_get_guint8(tvb, offset + 1); type_version = ilb_type << 8 | ilb_version; col_append_fstr(pinfo->cinfo, COL_INFO, "Type: 0x%02x, Version: %d", ilb_type, ilb_version); if (ilb_tree) { proto_tree_add_item(ilb_tree, hf_interlink_block_type, tvb, offset, 1, FALSE); offset += 1; proto_tree_add_item(ilb_tree, hf_interlink_block_version, tvb, offset, 1, FALSE); offset += 1; proto_tree_add_item(ilb_tree, hf_interlink_block_length, tvb, offset, 2, TRUE); offset += 2; } /* Generate a new tvb for the rest. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* Probably a sub-dissector exists for this type/version combination. */ handle = dissector_get_port_handle(subdissector_table, type_version); /* Without a proper sub-dissector, we use "data". */ if (handle == NULL) handle = data_handle; /* Call the sub-dissector. */ call_dissector(handle, next_tvb, pinfo, tree); }
/* * Main dissection routine which dissects a DDP segment and interprets the * header field rsvdULP according to RDMAP. */ void dissect_iwarp_ddp_rdmap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *ddp_rdma_tree = NULL; proto_tree *ddp_tree = NULL; proto_tree *ddp_ctrl_field_tree = NULL; proto_tree *ddp_buffer_model_tree = NULL; proto_tree *rdma_tree = NULL; proto_tree *rdma_ctrl_field_tree = NULL; proto_item *ddp_rdma_item = NULL; proto_item *ddp_item = NULL; proto_item *ddp_ctrl_field_item = NULL; proto_item *ddp_buffer_model_item = NULL; proto_item *rdma_item = NULL; proto_item *rdma_ctrl_field_item = NULL; tvbuff_t *next_tvb = NULL; gboolean is_tagged_buffer_model; guint8 ddp_ctrl_field, rdma_ctrl_field, rdma_msg_opcode; guint32 header_end; guint32 offset = 0; ddp_ctrl_field = tvb_get_guint8(tvb, 0); rdma_ctrl_field = tvb_get_guint8(tvb, 1); rdma_msg_opcode = rdma_ctrl_field & RDMA_OPCODE; is_tagged_buffer_model = ddp_ctrl_field & DDP_TAGGED_FLAG; ddp_rdma_packetlist(pinfo, ddp_ctrl_field & DDP_LAST_FLAG, rdma_msg_opcode); if (tree) { offset = 0; /* determine header length */ if (is_tagged_buffer_model) { header_end = DDP_TAGGED_HEADER_LEN; } else { header_end = DDP_UNTAGGED_HEADER_LEN; } if (rdma_msg_opcode == RDMA_READ_REQUEST || rdma_msg_opcode == RDMA_TERMINATE) { header_end = -1; } /* DDP/RDMA protocol tree */ ddp_rdma_item = proto_tree_add_item(tree, proto_iwarp_ddp_rdmap, tvb, offset, header_end, FALSE); ddp_rdma_tree = proto_item_add_subtree(ddp_rdma_item, ett_iwarp_ddp_rdmap); /* DDP protocol header subtree */ ddp_item = proto_tree_add_item(ddp_rdma_tree, hf_iwarp_ddp, tvb, offset, header_end, FALSE); ddp_tree = proto_item_add_subtree(ddp_item, ett_iwarp_ddp); /* DDP control field */ ddp_ctrl_field_item = proto_tree_add_item(ddp_tree, hf_iwarp_ddp_control_field, tvb, offset, DDP_CONTROL_FIELD_LEN, FALSE); ddp_ctrl_field_tree = proto_item_add_subtree(ddp_ctrl_field_item, ett_iwarp_ddp); proto_tree_add_item(ddp_ctrl_field_tree, hf_iwarp_ddp_t_flag, tvb, offset, DDP_CONTROL_FIELD_LEN, FALSE); proto_tree_add_item(ddp_ctrl_field_tree, hf_iwarp_ddp_l_flag, tvb, offset, DDP_CONTROL_FIELD_LEN, FALSE); proto_tree_add_item(ddp_ctrl_field_tree, hf_iwarp_ddp_rsvd, tvb, offset, DDP_CONTROL_FIELD_LEN, FALSE); proto_tree_add_item(ddp_ctrl_field_tree, hf_iwarp_ddp_dv, tvb, offset, DDP_CONTROL_FIELD_LEN, FALSE); offset += DDP_CONTROL_FIELD_LEN; /* DDP header field RsvdULP */ if (!is_tagged_buffer_model) { proto_tree_add_item(ddp_tree, hf_iwarp_ddp_rsvdulp, tvb, offset, DDP_UNTAGGED_RSVDULP_LEN, FALSE); } /* RDMA protocol header subtree */ if (is_tagged_buffer_model) { header_end = RDMA_CONTROL_FIELD_LEN; } else { header_end = RDMA_CONTROL_FIELD_LEN + RDMA_RESERVED_FIELD_LEN; } rdma_item = proto_tree_add_item(ddp_rdma_tree, hf_iwarp_rdma, tvb, offset, header_end, FALSE); rdma_tree = proto_item_add_subtree(rdma_item, ett_iwarp_rdma); /* RDMA Control Field */ rdma_ctrl_field_item = proto_tree_add_item(rdma_tree, hf_iwarp_rdma_control_field, tvb, offset, RDMA_CONTROL_FIELD_LEN, FALSE); rdma_ctrl_field_tree = proto_item_add_subtree(rdma_ctrl_field_item, ett_iwarp_rdma); proto_tree_add_item(rdma_ctrl_field_tree, hf_iwarp_rdma_version, tvb, offset, RDMA_CONTROL_FIELD_LEN, FALSE); proto_tree_add_item(rdma_ctrl_field_tree, hf_iwarp_rdma_rsvd, tvb, offset, RDMA_CONTROL_FIELD_LEN, FALSE); proto_tree_add_item(rdma_ctrl_field_tree, hf_iwarp_rdma_opcode, tvb, offset, RDMA_CONTROL_FIELD_LEN, FALSE); offset += RDMA_CONTROL_FIELD_LEN; /* dissection of DDP rsvdULP[8:39] with respect to RDMAP */ if (rdma_msg_opcode == RDMA_READ_REQUEST || rdma_msg_opcode == RDMA_SEND || rdma_msg_opcode == RDMA_SEND_SE || rdma_msg_opcode == RDMA_TERMINATE) { proto_tree_add_item(rdma_tree, hf_iwarp_rdma_reserved, tvb, offset, RDMA_RESERVED_FIELD_LEN, FALSE); } if (rdma_msg_opcode == RDMA_SEND_INVALIDATE || rdma_msg_opcode == RDMA_SEND_SE_INVALIDATE) { proto_tree_add_item(rdma_tree, hf_iwarp_rdma_inval_stag, tvb, offset, RDMA_INVAL_STAG_LEN, FALSE); } if (!is_tagged_buffer_model) { offset += RDMA_RESERVED_FIELD_LEN; } /* DDP Buffer Model dissection */ if (is_tagged_buffer_model) { /* Tagged Buffer Model Case */ ddp_buffer_model_item = proto_tree_add_item(ddp_tree, hf_iwarp_ddp_tagged_header, tvb, offset, DDP_BUFFER_MODEL_LEN, FALSE); ddp_buffer_model_tree = proto_item_add_subtree(ddp_buffer_model_item, ett_iwarp_ddp); proto_tree_add_item(ddp_buffer_model_tree, hf_iwarp_ddp_stag, tvb, offset, DDP_STAG_LEN, FALSE); offset += DDP_STAG_LEN; proto_tree_add_item(ddp_buffer_model_tree, hf_iwarp_ddp_to, tvb, offset, DDP_TO_LEN, FALSE); offset += DDP_TO_LEN; if( rdma_msg_opcode == RDMA_READ_RESPONSE || rdma_msg_opcode == RDMA_WRITE) { /* display the payload */ next_tvb = tvb_new_subset_remaining(tvb, DDP_TAGGED_HEADER_LEN); call_dissector(data_handle, next_tvb, pinfo, tree); } } else { /* Untagged Buffer Model Case */ ddp_buffer_model_item = proto_tree_add_item(ddp_tree, hf_iwarp_ddp_untagged_header, tvb, offset, DDP_BUFFER_MODEL_LEN, FALSE); ddp_buffer_model_tree = proto_item_add_subtree(ddp_buffer_model_item, ett_iwarp_ddp); proto_tree_add_item(ddp_buffer_model_tree, hf_iwarp_ddp_qn, tvb, offset, DDP_QN_LEN, FALSE); offset += DDP_QN_LEN; proto_tree_add_item(ddp_buffer_model_tree, hf_iwarp_ddp_msn, tvb, offset, DDP_MSN_LEN, FALSE); offset += DDP_MSN_LEN; proto_tree_add_item(ddp_buffer_model_tree, hf_iwarp_ddp_mo, tvb, offset, DDP_MO_LEN, FALSE); offset += DDP_MO_LEN; if (rdma_msg_opcode == RDMA_SEND || rdma_msg_opcode == RDMA_SEND_INVALIDATE || rdma_msg_opcode == RDMA_SEND_SE || rdma_msg_opcode == RDMA_SEND_SE_INVALIDATE) { /* display the payload */ next_tvb = tvb_new_subset_remaining(tvb, DDP_UNTAGGED_HEADER_LEN); call_dissector(data_handle, next_tvb, pinfo, tree); } } } /* do further dissection for RDMA messages RDMA Read Request & Terminate */ if (rdma_msg_opcode == RDMA_READ_REQUEST || rdma_msg_opcode == RDMA_TERMINATE) { dissect_iwarp_rdmap(tvb, rdma_tree, offset, rdma_msg_opcode); } }
static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *clnp_tree = NULL; proto_item *ti, *ti_len = NULL, *ti_pdu_len = NULL, *ti_tot_len = NULL; guint8 cnf_proto_id; guint8 cnf_hdr_len; guint8 cnf_vers; guint8 cnf_ttl; guint8 cnf_type; char flag_string[6+1]; const char *pdu_type_string; proto_tree *type_tree; guint16 segment_length; guint16 du_id = 0; guint16 segment_offset = 0; guint16 total_length; guint16 cnf_cksum; cksum_status_t cksum_status; int offset; guchar src_len, dst_len, nsel, opt_len = 0; const guint8 *dst_addr, *src_addr; guint next_length; proto_tree *discpdu_tree; gboolean save_in_error_pkt; fragment_data *fd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; gboolean save_fragmented; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP"); col_clear(pinfo->cinfo, COL_INFO); cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID); if (cnf_proto_id == NLPID_NULL) { col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset"); if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id, "Inactive subset"); } next_tvb = tvb_new_subset_remaining(tvb, 1); if (call_dissector(ositp_inactive_handle, next_tvb, pinfo, tree) == 0) call_dissector(data_handle,tvb, pinfo, tree); return; } /* return if version not known */ cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS); if (cnf_vers != ISO8473_V1) { call_dissector(data_handle,tvb, pinfo, tree); return; } /* fixed part decoding */ cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN); if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id); ti_len = proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, cnf_hdr_len); } if (cnf_hdr_len < FIXED_PART_LEN) { /* Header length is less than the length of the fixed part of the header. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < minimum length %u", FIXED_PART_LEN); return; } if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1, cnf_vers); cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL); proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1, cnf_ttl, "Holding Time : %u (%u.%u secs)", cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5); } cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE); pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals, "Unknown (0x%02x)"); flag_string[0] = '\0'; if (cnf_type & CNF_SEG_OK) g_strlcat(flag_string, "S ", 7); if (cnf_type & CNF_MORE_SEGS) g_strlcat(flag_string, "M ", 7); if (cnf_type & CNF_ERR_OK) g_strlcat(flag_string, "E ", 7); if (tree) { ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1, cnf_type, "PDU Type : 0x%02x (%s%s)", cnf_type, flag_string, pdu_type_string); type_tree = proto_item_add_subtree(ti, ett_clnp_type); proto_tree_add_item(type_tree, hf_clnp_cnf_segmentation, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_more_segments, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_report_error, tvb, P_CLNP_TYPE, 1, ENC_NA); proto_tree_add_item(type_tree, hf_clnp_cnf_type, tvb, P_CLNP_TYPE, 1, ENC_NA); } /* If we don't have the full header - i.e., not enough to see the segmentation part and determine whether this datagram is segmented or not - set the Info column now; we'll get an exception before we set it otherwise. */ if (tvb_length(tvb) < cnf_hdr_len) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); } segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN); if (tree) { ti_pdu_len = proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); } if (segment_length < cnf_hdr_len) { /* Segment length is less than the header length. */ expert_add_info_format(pinfo, ti_pdu_len, PI_MALFORMED, PI_ERROR, "PDU length < header length %u", cnf_hdr_len); return; } cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); if (tree) { switch (cksum_status) { default: /* * No checksum present, or not enough of the header present to * checksum it. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x", cnf_cksum); break; case CKSUM_OK: /* * Checksum is correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (correct)", cnf_cksum); break; case CKSUM_NOT_OK: /* * Checksum is not correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (incorrect)", cnf_cksum); break; } } /* tree */ opt_len = cnf_hdr_len; opt_len -= FIXED_PART_LEN; /* Fixed part of Header */ /* address part */ offset = P_CLNP_ADDRESS_PART; if (opt_len < 1) { /* Header length is less than the minimum value in CLNP, including the destination address length. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < %u", FIXED_PART_LEN + 1); return; } dst_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, dst_len); } offset += 1; opt_len -= 1; if (opt_len < dst_len) { /* Header length is less than the minimum value, including the destination address length and the destination address. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len); return; } dst_addr = tvb_get_ptr(tvb, offset, dst_len); nsel = tvb_get_guint8(tvb, offset + dst_len - 1); SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr); SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr); if (tree) { proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset, dst_len, dst_addr, " DA : %s", print_nsap_net(dst_addr, dst_len)); } offset += dst_len; opt_len -= dst_len; if (opt_len < 1) { /* Header length is less than the minimum value, including the destination address length, the destination address, and the source address length. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1); return; } src_len = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, offset, 1, src_len); } offset += 1; opt_len -= 1; if (opt_len < src_len) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, and the source address. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + src_len); return; } src_addr = tvb_get_ptr(tvb, offset, src_len); SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr); if (tree) { proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb, offset, src_len, src_addr, " SA : %s", print_nsap_net(src_addr, src_len)); } offset += src_len; opt_len -= src_len; /* Segmentation Part */ if (cnf_type & CNF_SEG_OK) { if (opt_len < SEGMENTATION_PART_LEN) { /* Header length is less than the minimum value, including the destination address length, the destination address, the source address length, the source address, and the segmentation part. */ expert_add_info_format(pinfo, ti_len, PI_MALFORMED, PI_ERROR, "Header length value < %u", FIXED_PART_LEN + 1 + dst_len + 1 + SEGMENTATION_PART_LEN); return; } du_id = tvb_get_ntohs(tvb, offset); if (tree) { proto_tree_add_text(clnp_tree, tvb, offset, 2, "Data unit identifier: %06u", du_id); } segment_offset = tvb_get_ntohs(tvb, offset + 2); if (tree) { proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2, "Segment offset : %6u", segment_offset); } total_length = tvb_get_ntohs(tvb, offset + 4); if (tree) { ti_tot_len = proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2, "Total length : %6u", total_length); } if (total_length < segment_length) { /* Reassembled length is less than the length of this segment. */ expert_add_info_format(pinfo, ti_tot_len, PI_MALFORMED, PI_ERROR, "Total length < segment length %u", segment_length); return; } offset += SEGMENTATION_PART_LEN; opt_len -= SEGMENTATION_PART_LEN; } if (tree) { dissect_osi_options(opt_len, tvb, offset, clnp_tree); } offset += opt_len; /* If clnp_reassemble is on, this is a segment, we have all the * data in the segment, and the checksum is valid, then just add the * segment to the hashtable. */ save_fragmented = pinfo->fragmented; if (clnp_reassemble && (cnf_type & CNF_SEG_OK) && ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) && tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) && segment_length > cnf_hdr_len && cksum_status != CKSUM_NOT_OK) { fd_head = fragment_add_check(&clnp_reassembly_table, tvb, offset, pinfo, du_id, NULL, segment_offset, segment_length - cnf_hdr_len, cnf_type & CNF_MORE_SEGS); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP", fd_head, &clnp_frag_items, &update_col_info, clnp_tree); } else { /* If this is the first segment, dissect its contents, otherwise just show it as a segment. XXX - if we eventually don't save the reassembled contents of all segmented datagrams, we may want to always reassemble. */ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { /* Not the first segment - don't dissect it. */ next_tvb = NULL; } else { /* First segment, or not segmented. Dissect what we have here. */ /* Get a tvbuff for the payload. Set its length to the segment length, and flag it as a fragment, so going past the end reports FragmentBoundsError, i.e. "there's data missing because this isn't reassembled", not ReportedBoundsError, i.e. "the dissector ran past the end of the packet, so the packet must not have been constructed properly". */ next_tvb = tvb_new_subset_length(tvb, offset, segment_length - cnf_hdr_len); tvb_set_fragment(next_tvb); /* * If this is the first segment, but not the only segment, * tell the next protocol that. */ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS)) pinfo->fragmented = TRUE; else pinfo->fragmented = FALSE; } } if (next_tvb == NULL) { /* Just show this as a segment. */ col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)", pdu_type_string, flag_string, segment_offset); /* As we haven't reassembled anything, we haven't changed "pi", so we don't have to restore it. */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); pinfo->fragmented = save_fragmented; return; } if (tvb_offset_exists(tvb, offset)) { switch (cnf_type & CNF_TYPE) { case DT_NPDU: case MD_NPDU: /* Continue with COTP if any data. XXX - if this isn't the first Derived PDU of a segmented Initial PDU, skip that? */ if (nsel == (guchar)tp_nsap_selector || always_decode_transport) { if (call_dissector(ositp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be COTP or CLTP */ } } if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb, pinfo, tree, NULL)) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be one of the protocols in the heuristic list */ } break; case ER_NPDU: /* The payload is the header and "none, some, or all of the data part of the discarded PDU", i.e. it's like an ICMP error; dissect it as a CLNP PDU. */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); next_length = tvb_length_remaining(tvb, offset); if (next_length != 0) { /* We have payload; dissect it. */ ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length, "Discarded PDU"); discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu); /* Save the current value of the "we're inside an error packet" flag, and set that flag; subdissectors may treat packets that are the payload of error packets differently from "real" packets. */ save_in_error_pkt = pinfo->flags.in_error_pkt; pinfo->flags.in_error_pkt = TRUE; call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree); /* Restore the "we're inside an error packet" flag. */ pinfo->flags.in_error_pkt = save_in_error_pkt; } pinfo->fragmented = save_fragmented; return; /* we're done with this PDU */ case ERQ_NPDU: case ERP_NPDU: /* XXX - dissect this */ break; } } col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); call_dissector(data_handle,next_tvb, pinfo, tree); pinfo->fragmented = save_fragmented; } /* dissect_clnp */
/* Code to actually dissect the packets */ static void dissect_mip( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures we will need to add the protocol subtree and manage it */ proto_item *ti; proto_tree *mip_tree=NULL; proto_item *tf; proto_tree *flags_tree; guint8 type; guint16 flags; gint offset=0; const guint8 *reftime; tvbuff_t *next_tvb; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MobileIP"); col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, offset); switch (type) { case MIP_REGISTRATION_REQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Request: HoA=%s HA=%s CoA=%s", ip_to_str(tvb_get_ptr(tvb,4,4)), ip_to_str(tvb_get_ptr(tvb,8,4)), ip_to_str(tvb_get_ptr(tvb,12,4))); if (tree) { ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE); mip_tree = proto_item_add_subtree(ti, ett_mip); /* type */ proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type); offset++; /* flags */ flags = tvb_get_guint8(tvb, offset); tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb, offset, 1, flags); flags_tree = proto_item_add_subtree(tf, ett_mip_flags); proto_tree_add_boolean(flags_tree, hf_mip_s, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_b, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_d, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_m, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_g, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_v, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_t, tvb, offset, 1, flags); proto_tree_add_boolean(flags_tree, hf_mip_x, tvb, offset, 1, flags); offset++; /* lifetime */ proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE); offset += 2; /* home address */ proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE); offset += 4; /* home agent address */ proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE); offset += 4; /* Care of Address */ proto_tree_add_item(mip_tree, hf_mip_coa, tvb, offset, 4, FALSE); offset += 4; /* Identifier - assumed to be an NTP time here */ reftime = tvb_get_ptr(tvb, offset, 8); proto_tree_add_bytes_format(mip_tree, hf_mip_ident, tvb, offset, 8, reftime, "Identification: %s", ntp_fmt_ts(reftime)); offset += 8; } /* if tree */ break; case MIP_REGISTRATION_REPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Reply: HoA=%s HA=%s, Code=%u", ip_to_str(tvb_get_ptr(tvb,4,4)), ip_to_str(tvb_get_ptr(tvb,8,4)), tvb_get_guint8(tvb,1)); if (tree) { /* Add Subtree */ ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE); mip_tree = proto_item_add_subtree(ti, ett_mip); /* Type */ proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type); offset++; /* Reply Code */ proto_tree_add_item(mip_tree, hf_mip_code, tvb, offset, 1, FALSE); offset++; /* Registration Lifetime */ proto_tree_add_item(mip_tree, hf_mip_life, tvb, offset, 2, FALSE); offset += 2; /* Home address */ proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE); offset += 4; /* Home Agent Address */ proto_tree_add_item(mip_tree, hf_mip_haaddr, tvb, offset, 4, FALSE); offset += 4; /* Identifier - assumed to be an NTP time here */ reftime = tvb_get_ptr(tvb, offset, 8); proto_tree_add_bytes_format(mip_tree, hf_mip_ident, tvb, offset, 8, reftime, "Identification: %s", ntp_fmt_ts(reftime)); offset += 8; } /* if tree */ break; case MIP_NATT_TUNNEL_DATA: col_add_fstr(pinfo->cinfo, COL_INFO, "Tunnel Data: Next Header=%u", tvb_get_guint8(tvb,1)); if (tree) { /* Add Subtree */ ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE); mip_tree = proto_item_add_subtree(ti, ett_mip); /* Type */ proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type); offset++; /* Next Header */ proto_tree_add_item(mip_tree, hf_mip_nattt_nexthdr, tvb, offset, 1, FALSE); offset++; /* reserved */ proto_tree_add_item(mip_tree, hf_mip_nattt_reserved, tvb, offset, 2, FALSE); offset += 2; } /* if tree */ else { offset += 4; } /* encapsulated payload */ next_tvb = tvb_new_subset_remaining(tvb, 4); call_dissector(ip_handle, next_tvb, pinfo, mip_tree); offset += tvb_reported_length_remaining(tvb, offset); break; case MIP_REGISTRATION_REVOCATION: col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Revocation: HoA=%s HDA=%s FDA=%s", ip_to_str(tvb_get_ptr(tvb,4,4)), ip_to_str(tvb_get_ptr(tvb,8,4)), ip_to_str(tvb_get_ptr(tvb,12,4))); if (tree) { ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE); mip_tree = proto_item_add_subtree(ti, ett_mip); /* type */ proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type); offset++; /* reserved */ proto_tree_add_item(mip_tree, hf_mip_rev_reserved, tvb, offset, 1, FALSE); offset++; /* flags */ flags = tvb_get_ntohs(tvb, offset); tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb, offset, 2, flags); flags_tree = proto_item_add_subtree(tf, ett_mip_flags); proto_tree_add_boolean(flags_tree, hf_mip_rev_a, tvb, offset, 2, flags); proto_tree_add_boolean(flags_tree, hf_mip_rev_i, tvb, offset, 2, flags); /* reserved */ proto_tree_add_uint(flags_tree, hf_mip_rev_reserved, tvb, offset, 2, flags); offset += 2; /* home address */ proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE); offset += 4; /* home domain address */ proto_tree_add_item(mip_tree, hf_mip_hda, tvb, offset, 4, FALSE); offset += 4; /* foreign domain address */ proto_tree_add_item(mip_tree, hf_mip_fda, tvb, offset, 4, FALSE); offset += 4; /* revocation identifier */ proto_tree_add_item(mip_tree, hf_mip_revid, tvb, offset, 4, FALSE); offset += 4; } /* if tree */ break; case MIP_REGISTRATION_REVOCATION_ACK: col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Revocation Ack: HoA=%s", ip_to_str(tvb_get_ptr(tvb,4,4))); if (tree) { ti = proto_tree_add_item(tree, proto_mip, tvb, offset, -1, FALSE); mip_tree = proto_item_add_subtree(ti, ett_mip); /* type */ proto_tree_add_uint(mip_tree, hf_mip_type, tvb, offset, 1, type); offset++; /* reserved */ proto_tree_add_item(mip_tree, hf_mip_ack_reserved, tvb, offset, 1, FALSE); offset++; /* flags */ flags = tvb_get_ntohs(tvb, offset); tf = proto_tree_add_uint(mip_tree, hf_mip_flags, tvb, offset, 2, flags); flags_tree = proto_item_add_subtree(tf, ett_mip_flags); proto_tree_add_boolean(flags_tree, hf_mip_ack_i, tvb, offset, 2, flags); /* reserved */ proto_tree_add_uint(flags_tree, hf_mip_ack_reserved, tvb, offset, 2, flags); offset += 2; /* home address */ proto_tree_add_item(mip_tree, hf_mip_homeaddr, tvb, offset, 4, FALSE); offset += 4; /* revocation identifier */ proto_tree_add_item(mip_tree, hf_mip_revid, tvb, offset, 4, FALSE); offset += 4; } /* if tree */ break; } /* End switch */ if (tree) { if (tvb_reported_length_remaining(tvb, offset) > 0) dissect_mip_extensions(tvb, offset, mip_tree); } } /* dissect_mip */
static void dissect_bacnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_item *ct; proto_tree *bacnet_tree; proto_tree *control_tree; gint offset; guint8 bacnet_version; guint8 bacnet_control; guint8 bacnet_dlen; guint8 bacnet_slen; guint8 bacnet_mesgtyp; guint8 bacnet_rejectreason; guint8 bacnet_rportnum; guint8 bacnet_pinfolen; guint8 i; tvbuff_t *next_tvb; guint32 vendor_id; col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-NPDU"); col_set_str(pinfo->cinfo, COL_INFO, "Building Automation and Control Network NPDU"); offset = 0; bacnet_version = tvb_get_guint8(tvb, offset); bacnet_control = tvb_get_guint8(tvb, offset+1); /* I don't know the length of the NPDU yet; Setting the length after dissection */ ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, -1, ENC_NA); bacnet_tree = proto_item_add_subtree(ti, ett_bacnet); proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_version, tvb, offset, 1, bacnet_version,"0x%02x (%s)",bacnet_version, (bacnet_version == 0x01)?"ASHRAE 135-1995":"unknown"); offset ++; ct = proto_tree_add_uint(bacnet_tree, hf_bacnet_control, tvb, offset, 1, bacnet_control); control_tree = proto_item_add_subtree(ct, ett_bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_net, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_res1, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_dest, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_res2, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_src, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_expect, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_high, tvb, offset, 1, bacnet_control); proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_low, tvb, offset, 1, bacnet_control); offset ++; if (bacnet_control & BAC_CONTROL_DEST) { /* DNET, DLEN, DADR */ proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; bacnet_dlen = tvb_get_guint8(tvb, offset); /* DLEN = 0 is broadcast on dest.network */ if( bacnet_dlen == 0) { /* append to hf_bacnet_dlen: broadcast */ proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen, "%d indicates Broadcast on Destination Network", bacnet_dlen); offset ++; /* going to SNET */ } else if (bacnet_dlen==6) { proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen); offset ++; /* Ethernet MAC */ proto_tree_add_item(bacnet_tree, hf_bacnet_dadr_eth, tvb, offset, bacnet_dlen, ENC_NA); offset += bacnet_dlen; } else if (bacnet_dlen==1) { proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen); offset ++; /* MS/TP or ARCNET MAC */ proto_tree_add_item(bacnet_tree, hf_bacnet_dadr_mstp, tvb, offset, bacnet_dlen, ENC_BIG_ENDIAN); offset += bacnet_dlen; } else if (bacnet_dlen<7) { proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen); offset ++; /* Other MAC formats should be included here */ proto_tree_add_item(bacnet_tree, hf_bacnet_dadr_tmp, tvb, offset, bacnet_dlen, ENC_NA); offset += bacnet_dlen; } else { proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen, "%d invalid!", bacnet_dlen); } } if (bacnet_control & BAC_CONTROL_SRC) { /* SNET, SLEN, SADR */ /* SNET */ proto_tree_add_uint(bacnet_tree, hf_bacnet_snet, tvb, offset, 2, tvb_get_ntohs(tvb, offset)); offset += 2; bacnet_slen = tvb_get_guint8(tvb, offset); if( bacnet_slen == 0) { /* SLEN = 0 invalid */ proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_slen, tvb, offset, 1, bacnet_slen, "%d invalid!", bacnet_slen); offset ++; } else if (bacnet_slen==6) { /* SLEN */ proto_tree_add_uint(bacnet_tree, hf_bacnet_slen, tvb, offset, 1, bacnet_slen); offset ++; /* Ethernet MAC */ proto_tree_add_item(bacnet_tree, hf_bacnet_sadr_eth, tvb, offset, bacnet_slen, ENC_NA); offset += bacnet_slen; } else if (bacnet_slen==1) { /* SLEN */ proto_tree_add_uint(bacnet_tree, hf_bacnet_slen, tvb, offset, 1, bacnet_slen); offset ++; /* MS/TP or ARCNET MAC */ proto_tree_add_item(bacnet_tree, hf_bacnet_sadr_mstp, tvb, offset, bacnet_slen, ENC_BIG_ENDIAN); offset += bacnet_slen; } else if (bacnet_slen<6) { /* LON MAC */ /* SLEN */ proto_tree_add_uint(bacnet_tree, hf_bacnet_slen, tvb, offset, 1, bacnet_slen); offset ++; /* Other MAC formats should be included here */ proto_tree_add_item(bacnet_tree, hf_bacnet_sadr_tmp, tvb, offset, bacnet_slen, ENC_NA); offset += bacnet_slen; } else { proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_slen, tvb, offset, 1, bacnet_slen, "%d invalid!", bacnet_slen); offset ++; } } if (bacnet_control & BAC_CONTROL_DEST) { /* Hopcount */ proto_tree_add_item(bacnet_tree, hf_bacnet_hopc, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; } /* Network Layer Message Type */ if (bacnet_control & BAC_CONTROL_NET) { bacnet_mesgtyp = tvb_get_guint8(tvb, offset); proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_mesgtyp, tvb, offset, 1, bacnet_mesgtyp, "%02x (%s)", bacnet_mesgtyp, bacnet_mesgtyp_name(bacnet_mesgtyp)); /* Put the NPDU Type in the info column */ col_add_str(pinfo->cinfo, COL_INFO, bacnet_mesgtyp_name(bacnet_mesgtyp)); offset ++; /* Vendor ID * The standard says: "If Bit 7 of the control octet is 1 and * the Message Type field contains a value in the range * X'80' - X'FF', then a Vendor ID field shall be present (...)." * We should not go any further in dissecting the packet if it's * not present, but we don't know about that: No length field... */ if (bacnet_mesgtyp > 0x7f) { /* Note: our next_tvb includes message type and vendor id! */ next_tvb = tvb_new_subset_remaining(tvb, offset-1); vendor_id = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(bacnet_tree, hf_bacnet_vendor, tvb, offset, 2, vendor_id); offset += 2; /* vendor_id */ if (dissector_try_uint(bacnet_dissector_table, vendor_id, next_tvb, pinfo, bacnet_tree)) { /* we parsed it so skip over length and we are done */ /* Note: offset has now been bumped for message type and vendor id so we take that out of our next_tvb size */ offset += tvb_length(next_tvb) -3; } } /* Performance Index (in I-Could-Be-Router-To-Network) */ if (bacnet_mesgtyp == BAC_NET_ICB_R) { proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(bacnet_tree, hf_bacnet_perf, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; } /* Reason, DNET (in Reject-Message-To-Network) */ if (bacnet_mesgtyp == BAC_NET_REJ) { bacnet_rejectreason = tvb_get_guint8(tvb, offset); proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_rejectreason, tvb, offset, 1, bacnet_rejectreason, "%d (%s)", bacnet_rejectreason, bacnet_rejectreason_name(bacnet_rejectreason)); offset ++; proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */ if ((bacnet_mesgtyp == BAC_NET_R_BUSY) || (bacnet_mesgtyp == BAC_NET_WHO_R) || (bacnet_mesgtyp == BAC_NET_R_AVA) || (bacnet_mesgtyp == BAC_NET_IAM_R) ) { while(tvb_reported_length_remaining(tvb, offset) > 1 ) { proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } } /* Initialize-Routing-Table */ if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) || (bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) { bacnet_rportnum = tvb_get_guint8(tvb, offset); /* number of ports */ proto_tree_add_uint(bacnet_tree, hf_bacnet_rportnum, tvb, offset, 1, bacnet_rportnum); offset ++; for(i=0; i<bacnet_rportnum; i++) { /* Connected DNET */ proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Port ID */ proto_tree_add_item(bacnet_tree, hf_bacnet_portid, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; /* Port Info Length */ bacnet_pinfolen = tvb_get_guint8(tvb, offset); proto_tree_add_uint(bacnet_tree, hf_bacnet_pinfolen, tvb, offset, 1, bacnet_pinfolen); offset ++; proto_tree_add_item(bacnet_tree, hf_bacnet_pinfo, tvb, offset, bacnet_pinfolen, ENC_NA); offset += bacnet_pinfolen; } } /* Establish-Connection-To-Network */ if (bacnet_mesgtyp == BAC_NET_EST_CON) { proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(bacnet_tree, hf_bacnet_term_time_value, tvb, offset, 1, ENC_BIG_ENDIAN); offset ++; } /* Disconnect-Connection-To-Network */ if (bacnet_mesgtyp == BAC_NET_DISC_CON) { proto_tree_add_item(bacnet_tree, hf_bacnet_dnet, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } } /* Now set NPDU length */ proto_item_set_len(ti, offset); /* dissect BACnet APDU */ next_tvb = tvb_new_subset_remaining(tvb,offset); if (bacnet_control & BAC_CONTROL_NET) { /* Unknown function - dissect the payload as data */ call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* APDU - call the APDU dissector */ call_dissector(bacapp_handle, next_tvb, pinfo, tree); } }
/* Code to actually dissect the packets */ static void dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { char *szInfo; int offCur = 0; /* current offset from start of WTP data */ gint returned_length, str_index = 0; unsigned char b0; /* continuation flag */ unsigned char fCon; /* Continue flag */ unsigned char fRID; /* Re-transmission indicator*/ unsigned char fTTR = '\0'; /* Transmission trailer */ guint cbHeader = 0; /* Fixed header length */ guint vHeader = 0; /* Variable header length*/ int abortType = 0; /* Set up structures we'll need to add the protocol subtree and manage it */ proto_item *ti = NULL; proto_tree *wtp_tree = NULL; char pdut; char clsTransaction = 3; int numMissing = 0; /* Number of missing packets in a negative ack */ int i; tvbuff_t *wsp_tvb = NULL; guint8 psn = 0; /* Packet sequence number*/ guint16 TID = 0; /* Transaction-Id */ int dataOffset; gint dataLen; #define SZINFO_SIZE 256 szInfo=(char *)wmem_alloc(wmem_packet_scope(), SZINFO_SIZE); b0 = tvb_get_guint8 (tvb, offCur + 0); /* Discover Concatenated PDUs */ if (b0 == 0) { guint c_fieldlen = 0; /* Length of length-field */ guint c_pdulen = 0; /* Length of conc. PDU */ if (tree) { ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 1, ENC_NA); wtp_tree = proto_item_add_subtree(ti, ett_wtp_sub_pdu_tree); proto_item_append_text(ti, ", PDU concatenation"); } offCur = 1; i = 1; while (offCur < (int) tvb_reported_length(tvb)) { tvbuff_t *wtp_tvb; /* The length of an embedded WTP PDU is coded as either: * - a 7-bit value contained in one octet with highest bit == 0. * - a 15-bit value contained in two octets (little endian) * if the 1st octet has its highest bit == 1. * This means that this is NOT encoded as an uintvar-integer!!! */ b0 = tvb_get_guint8(tvb, offCur + 0); if (b0 & 0x80) { c_fieldlen = 2; c_pdulen = ((b0 & 0x7f) << 8) | tvb_get_guint8(tvb, offCur + 1); } else { c_fieldlen = 1; c_pdulen = b0; } if (tree) { proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size, tvb, offCur, c_fieldlen, c_pdulen); } if (i > 1) { col_append_str(pinfo->cinfo, COL_INFO, ", "); } /* Skip the length field for the WTP sub-tvb */ wtp_tvb = tvb_new_subset_length(tvb, offCur + c_fieldlen, c_pdulen); dissect_wtp_common(wtp_tvb, pinfo, wtp_tree); offCur += c_fieldlen + c_pdulen; i++; } if (tree) { proto_item_append_text(ti, ", PDU count: %u", i); } return; } /* No concatenation */ fCon = b0 & 0x80; fRID = retransmission_indicator(b0); pdut = pdu_type(b0); #ifdef DEBUG printf("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n", pinfo->fd->num, tree, val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x"), pdut, tvb_captured_length(tvb)); #endif /* Develop the string to put in the Info column */ returned_length = g_snprintf(szInfo, SZINFO_SIZE, "WTP %s", val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x")); str_index += MIN(returned_length, SZINFO_SIZE-str_index); switch (pdut) { case INVOKE: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = 0; clsTransaction = transaction_class(tvb_get_guint8(tvb, offCur + 3)); returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " Class %d", clsTransaction); str_index += MIN(returned_length, SZINFO_SIZE-str_index); cbHeader = 4; break; case SEGMENTED_INVOKE: case SEGMENTED_RESULT: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = tvb_get_guint8(tvb, offCur + 3); if (psn != 0) { returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " (%u)", psn); str_index += MIN(returned_length, SZINFO_SIZE-str_index); } cbHeader = 4; break; case ABORT: cbHeader = 4; break; case RESULT: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = 0; cbHeader = 3; break; case ACK: cbHeader = 3; break; case NEGATIVE_ACK: /* Variable number of missing packets */ numMissing = tvb_get_guint8(tvb, offCur + 3); cbHeader = numMissing + 4; break; default: break; }; if (fRID) { /*returned_length =*/ g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " R" ); /*str_index += MIN(returned_length, SZINFO_SIZE-str_index);*/ }; /* In the interest of speed, if "tree" is NULL, don't do any work not necessary to generate protocol tree items. */ if (tree) { #ifdef DEBUG fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader); #endif /* NOTE - Length will be set when we process the TPI */ ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 0, ENC_NA); #ifdef DEBUG fprintf(stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n"); #endif wtp_tree = proto_item_add_subtree(ti, ett_wtp); /* Code to process the packet goes here */ #ifdef DEBUG fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader); fprintf(stderr, "dissect_wtp: offCur = %d\n", offCur); #endif /* Add common items: only CON and PDU Type */ proto_tree_add_item( wtp_tree, /* tree */ hf_wtp_header_flag_continue, /* id */ tvb, offCur, /* start of highlight */ 1, /* length of highlight*/ b0 /* value */ ); proto_tree_add_item(wtp_tree, hf_wtp_header_pdu_type, tvb, offCur, 1, ENC_LITTLE_ENDIAN); switch(pdut) { case INVOKE: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_version , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_TIDNew, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Invoke (%u)" ", Transaction Class: %s (%u)", INVOKE, val_to_str_const(clsTransaction, vals_transaction_classes, "Undefined"), clsTransaction); break; case RESULT: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", PDU: Result (%u)", RESULT); break; case ACK: proto_tree_add_item(wtp_tree, hf_wtp_header_Ack_flag_TVETOK, tvb, offCur, 1, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", PDU: ACK (%u)", ACK); break; case ABORT: abortType = tvb_get_guint8 (tvb, offCur) & 0x07; proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_type , tvb, offCur , 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); if (abortType == PROVIDER) { guint8 reason = tvb_get_guint8(tvb, offCur + 3); proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Abort (%u)" ", Type: Provider (%u)" ", Reason: %s (%u)", ABORT, PROVIDER, val_to_str_const(reason, vals_abort_reason_provider, "Undefined"), reason); } else if (abortType == USER) { guint8 reason = tvb_get_guint8(tvb, offCur + 3); proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Abort (%u)" ", Type: User (%u)" ", Reason: %s (%u)", ABORT, PROVIDER, val_to_str_ext_const(reason, &vals_wsp_reason_codes_ext, "Undefined"), reason); } break; case SEGMENTED_INVOKE: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Segmented Invoke (%u)" ", Packet Sequence Number: %u", SEGMENTED_INVOKE, psn); break; case SEGMENTED_RESULT: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Segmented Result (%u)" ", Packet Sequence Number: %u", SEGMENTED_RESULT, psn); break; case NEGATIVE_ACK: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_missing_packets , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); /* Iterate through missing packets */ for (i = 0; i < numMissing; i++) { proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + 4 + i, 1, ENC_LITTLE_ENDIAN); } proto_item_append_text(ti, ", PDU: Negative Ack (%u)" ", Missing Packets: %u", NEGATIVE_ACK, numMissing); break; default: break; }; if (fRID) { proto_item_append_text(ti, ", Retransmission"); } } else { /* tree is NULL */ #ifdef DEBUG fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree); #endif } /* Process the variable part */ if (fCon) { /* Now, analyze variable part */ guint8 tCon; guint8 tByte; guint tpiLen; tvbuff_t *tmp_tvb; vHeader = 0; /* Start scan all over */ do { tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader); tCon = tByte & 0x80; if (tByte & 0x04) /* Long TPI */ tpiLen = 2 + tvb_get_guint8(tvb, offCur + cbHeader + vHeader + 1); else tpiLen = 1 + (tByte & 0x03); if (tree) { tmp_tvb = tvb_new_subset_length(tvb, offCur + cbHeader + vHeader, tpiLen); wtp_handle_tpi(wtp_tree, tmp_tvb); } vHeader += tpiLen; } while (tCon); } else { /* There is no variable part */ } /* End of variable part of header */ /* Set the length of the WTP protocol part now we know the length of the * fixed and variable WTP headers */ if (tree) proto_item_set_len(ti, cbHeader + vHeader); #ifdef DEBUG fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader ); #endif /* * Any remaining data ought to be WSP data (if not WTP ACK, NACK * or ABORT pdu), so, if we have any remaining data, and it's * not an ACK, NACK, or ABORT PDU, hand it off (defragmented) to the * WSP dissector. * Note that the last packet of a fragmented WTP message needn't * contain any data, so we allow payloadless packets to be * reassembled. (XXX - does the reassembly code handle this * for packets other than the last packet?) * * Try calling a subdissector only if: * - The WTP payload is ressembled in this very packet, * - The WTP payload is not fragmented across packets. */ dataOffset = offCur + cbHeader + vHeader; dataLen = tvb_reported_length_remaining(tvb, dataOffset); if ((dataLen >= 0) && ! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT))) { /* Try to reassemble if needed, and hand over to WSP * A fragmented WTP packet is either: * - An INVOKE with fTTR (transmission trailer) not set, * - a SEGMENTED_INVOKE, * - A RESULT with fTTR (transmission trailer) not set, * - a SEGMENTED_RESULT. */ if ( ( (pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) || ( ((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR) ) ) && tvb_bytes_exist(tvb, dataOffset, dataLen) ) { /* Try reassembling fragments */ fragment_head *fd_wtp = NULL; guint32 reassembled_in = 0; gboolean save_fragmented = pinfo->fragmented; pinfo->fragmented = TRUE; fd_wtp = fragment_add_seq(&wtp_reassembly_table, tvb, dataOffset, pinfo, TID, NULL, psn, dataLen, !fTTR, 0); /* XXX - fragment_add_seq() yields NULL unless Wireshark knows * that the packet is part of a reassembled whole. This means * that fd_wtp will be NULL as long as Wireshark did not encounter * (and process) the packet containing the last fragment. * This implies that Wireshark needs two passes over the data for * correct reassembly. At the first pass, a capture containing * three fragments plus a retransmssion of the last fragment * will progressively show: * * Packet 1: (Unreassembled fragment 1) * Packet 2: (Unreassembled fragment 2) * Packet 3: (Reassembled WTP) * Packet 4: (WTP payload reassembled in packet 3) * * However at subsequent evaluation (e.g., by applying a display * filter) the packet summary will show: * * Packet 1: (WTP payload reassembled in packet 3) * Packet 2: (WTP payload reassembled in packet 3) * Packet 3: (Reassembled WTP) * Packet 4: (WTP payload reassembled in packet 3) * * This is important to know, and also affects read filters! */ wsp_tvb = process_reassembled_data(tvb, dataOffset, pinfo, "Reassembled WTP", fd_wtp, &wtp_frag_items, NULL, wtp_tree); #ifdef DEBUG printf("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p, frame = %u\n", pinfo->fd->num, fd_wtp ? "Reassembled" : "Not reassembled", fd_wtp ? fd_wtp->reassembled_in : -1, wsp_tvb, fd_wtp ); #endif if (fd_wtp) { /* Reassembled */ reassembled_in = fd_wtp->reassembled_in; if (pinfo->fd->num == reassembled_in) { /* Reassembled in this very packet: * We can safely hand the tvb to the WSP dissector */ call_dissector(wsp_handle, wsp_tvb, pinfo, tree); } else { /* Not reassembled in this packet */ col_append_fstr(pinfo->cinfo, COL_INFO, "%s (WTP payload reassembled in packet %u)", szInfo, fd_wtp->reassembled_in); proto_tree_add_text(wtp_tree, tvb, dataOffset, -1, "Payload"); } } else { /* Not reassembled yet, or not reassembled at all */ col_append_fstr(pinfo->cinfo, COL_INFO, "%s (Unreassembled fragment %u)", szInfo, psn); proto_tree_add_text(wtp_tree, tvb, dataOffset, -1, "Payload"); } /* Now reset fragmentation information in pinfo */ pinfo->fragmented = save_fragmented; } else if ( ((pdut == INVOKE) || (pdut == RESULT)) && (fTTR) ) { /* Non-fragmented payload */ wsp_tvb = tvb_new_subset_remaining(tvb, dataOffset); /* We can safely hand the tvb to the WSP dissector */ call_dissector(wsp_handle, wsp_tvb, pinfo, tree); } else { /* Nothing to hand to subdissector */ col_append_str(pinfo->cinfo, COL_INFO, szInfo); } } else { /* Nothing to hand to subdissector */ col_append_str(pinfo->cinfo, COL_INFO, szInfo); } }
static void dissect_nmpi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *nmpi_tree = NULL; proto_item *ti; int offset = 0; guint8 opcode; guint8 nmpi_name_type; char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; int name_type; char node_name[(NETBIOS_NAME_LEN - 1)*4 + 1]; /*int node_name_type = 0;*/ tvbuff_t *next_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMPI"); col_clear(pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_nmpi, tvb, offset, 68, ENC_NA); nmpi_tree = proto_item_add_subtree(ti, ett_nmpi); add_routers(nmpi_tree, tvb, offset); } offset += 32; /* * XXX - we don't use "node_name" or "node_name_type". */ opcode = tvb_get_guint8(tvb, offset); nmpi_name_type = tvb_get_guint8(tvb, offset+1); name_type = get_netbios_name(tvb, offset+4, name, (NETBIOS_NAME_LEN - 1)*4 + 1); /*node_name_type = */get_netbios_name(tvb, offset+20, node_name, (NETBIOS_NAME_LEN - 1)*4 + 1); switch (opcode) { case INAME_CLAIM: col_add_fstr(pinfo->cinfo, COL_INFO, "Claim name %s<%02x>", name, name_type); break; case INAME_DELETE: col_add_fstr(pinfo->cinfo, COL_INFO, "Delete name %s<%02x>", name, name_type); break; case INAME_QUERY: col_add_fstr(pinfo->cinfo, COL_INFO, "Query name %s<%02x>", name, name_type); break; case INAME_FOUND: col_add_fstr(pinfo->cinfo, COL_INFO, "Name %s<%02x> found", name, name_type); break; case IMSG_HANGUP: col_add_fstr(pinfo->cinfo, COL_INFO, "Messenger hangup on %s<%02x>", name, name_type); break; case IMSLOT_SEND: col_add_fstr(pinfo->cinfo, COL_INFO, "Mailslot write to %s<%02x>", name, name_type); break; case IMSLOT_FIND: col_add_fstr(pinfo->cinfo, COL_INFO, "Find mailslot name %s<%02x>", name, name_type); break; case IMSLOT_NAME: col_add_fstr(pinfo->cinfo, COL_INFO, "Mailslot name %s<%02x> found", name, name_type); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown NMPI op 0x%02x: name %s<%02x>", opcode, name, name_type); break; } if (tree) { proto_tree_add_text(nmpi_tree, tvb, offset, 1, "Opcode: %s (0x%02x)", val_to_str_const(opcode, nmpi_opcode_vals, "Unknown"), opcode); proto_tree_add_text(nmpi_tree, tvb, offset+1, 1, "Name Type: %s (0x%02x)", val_to_str_const(nmpi_name_type, nmpi_name_type_vals, "Unknown"), nmpi_name_type); proto_tree_add_text(nmpi_tree, tvb, offset+2, 2, "Message ID: 0x%04x", tvb_get_letohs(tvb, offset+2)); netbios_add_name("Requested name", tvb, offset+4, nmpi_tree); netbios_add_name("Source name", tvb, offset+20, nmpi_tree); } offset += 1 + 1 + 2 + NETBIOS_NAME_LEN + NETBIOS_NAME_LEN; if (opcode == IMSLOT_SEND && tvb_offset_exists(tvb, offset)) { next_tvb = tvb_new_subset_remaining(tvb, offset); dissect_netbios_payload(next_tvb, pinfo, tree); } }
static int dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { gboolean has_routes; proto_tree *nbipx_tree = NULL; proto_item *ti = NULL; int offset = 0; guint8 packet_type; proto_tree *name_type_flag_tree; proto_item *tf; char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; int name_type; gboolean has_payload; tvbuff_t *next_tvb; ipxhdr_t *ipxh; /* Reject the packet if data is NULL */ if (data == NULL) return 0; ipxh = (ipxhdr_t*)data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBIPX"); col_clear(pinfo->cinfo, COL_INFO); if (ipxh->ipx_type == IPX_PACKET_TYPE_WANBCAST) { /* * This is a WAN Broadcast packet; we assume it will have * 8 IPX addresses at the beginning. */ has_routes = TRUE; } else { /* * This isn't a WAN Broadcast packet, but it still might * have the 8 addresses. * * If it's the right length for a name operation, * and, if we assume it has routes, the packet type * is a name operation, assume it has routes. * * NOTE: this will throw an exception if the byte that * would be the packet type byte if this has the 8 * addresses isn't present; if that's the case, we don't * know how to interpret this packet, so we can't dissect * it anyway. */ has_routes = FALSE; /* start out assuming it doesn't */ if (tvb_reported_length(tvb) == 50) { packet_type = tvb_get_guint8(tvb, offset + 32 + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: has_routes = TRUE; break; } } } if (tree) { ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0, -1, ENC_NA); nbipx_tree = proto_item_add_subtree(ti, ett_nbipx); } if (has_routes) { if (tree) add_routers(nbipx_tree, tvb, 0); offset += 32; } packet_type = tvb_get_guint8(tvb, offset + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: name_type = get_netbios_name(tvb, offset+2, name, (NETBIOS_NAME_LEN - 1)*4 + 1); col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s<%02x>", val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"), name, name_type); if (nbipx_tree) { tf = proto_tree_add_item(nbipx_tree, hf_nbipx_name_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); name_type_flag_tree = proto_item_add_subtree(tf, ett_nbipx_name_type_flags); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_group, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_in_use, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_registered, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_duplicated, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_deregistered, tvb, offset, 1, ENC_LITTLE_ENDIAN); } offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; if (nbipx_tree) netbios_add_name("Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * No payload to be interpreted by another protocol. */ has_payload = FALSE; break; case NBIPX_SESSION_DATA: case NBIPX_SESSION_END: case NBIPX_SESSION_END_ACK: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; proto_tree_add_item(nbipx_tree, hf_nbipx_session_src_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_dest_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_send_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_total_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_recv_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_bytes_received, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* * We may have payload to dissect. */ has_payload = TRUE; break; case NBIPX_DIRECTED_DATAGRAM: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; if (nbipx_tree) netbios_add_name("Receiver's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; if (nbipx_tree) netbios_add_name("Sender's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * We may have payload to dissect. */ has_payload = TRUE; break; default: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); /* * We don't know what the first byte is. */ offset += 1; /* * The second byte is a data stream type byte. */ proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; /* * We don't know what the rest of the packet is. */ has_payload = FALSE; } /* * Set the length of the NBIPX tree item. */ if (ti != NULL) proto_item_set_len(ti, offset); if (has_payload && tvb_offset_exists(tvb, offset)) { next_tvb = tvb_new_subset_remaining(tvb, offset); dissect_netbios_payload(next_tvb, pinfo, tree); } return tvb_length(tvb); }
static void dissect_wai_data(tvbuff_t *tvb, proto_tree *tree, guint8 subtype, guint16 lenx) { proto_item *data_item; proto_tree *data_tree; const gchar *type_name; data_item = proto_tree_add_item(tree, hf_wai_data, tvb, 0, lenx, ENC_NA); data_tree = proto_item_add_subtree (data_item, ett_wai_data); type_name = val_to_str_ext_const(subtype, &wai_subtype_names_ext, "Unknown type"); proto_item_set_text(data_item, "%s data (%d bytes)", type_name, lenx); switch (subtype) { case WAI_SUB_PRE_AUTHENTICATION: { /* Chapter 8.1.4.6 Preauthentication [ref: 1] */ dissect_flag(tvb, 0, data_tree); dissect_uskid(tvb, 1, data_tree); dissect_addid(tvb, 2, data_tree); dissect_counter(tvb, 14, data_tree); dissect_message_auth_code(tvb, 30, data_tree); break; } case WAI_SUB_STAKEY_REQ: { /* Chapter 8.1.4.5 STAKey Establishment procedure [ref: 1] */ dissect_flag(tvb, 0, data_tree); proto_tree_add_item(data_tree, hf_wai_sta_key_id, tvb, 1, 1, ENC_BIG_ENDIAN); dissect_uskid(tvb, 2, data_tree); dissect_addid(tvb, 3, data_tree); dissect_counter(tvb, 15, data_tree); dissect_message_auth_code(tvb, 31, data_tree); break; } case WAI_SUB_AUTH_ACTIVATION: { /* Chapter 8.1.4.2.1 WAI Authentication Activation [ref: 1] */ guint16 offset = 0; dissect_flag(tvb, offset, data_tree); offset += 1; dissect_authentication_id(tvb, offset, data_tree); offset += 32; offset += dissect_identity(tvb, offset, data_tree, "Local ASU "); offset += dissect_certificate(tvb, offset, data_tree, "STE AE "); dissect_ecdh_parameter(tvb, offset, data_tree); break; } case WAI_SUB_ACCESS_AUTH_REQ: { /* Chapter 8.1.4.2.2 Access WAI Authentication Request [ref: 1] */ guint16 offset = 0; guint8 optional_field; optional_field = tvb_get_guint8(tvb, 0) & FLAG_BIT3; dissect_flag(tvb, offset, data_tree); offset += 1; dissect_authentication_id(tvb, offset, data_tree); offset += 32; offset += dissect_challenge(tvb, offset, data_tree, "ASUE "); offset += dissect_key_data(tvb, offset, data_tree, "ASUE "); offset += dissect_identity(tvb, offset, data_tree, "STA AE "); offset += dissect_certificate(tvb, offset, data_tree, "STA ASUE "); offset += dissect_ecdh_parameter(tvb, offset, data_tree); if (optional_field) { offset += dissect_identity_list(tvb, offset, data_tree); } dissect_signature(tvb, offset, data_tree, "ASUE Signature"); break; } case WAI_SUB_ACCESS_AUTH_RESP: { /* Chapter 8.1.4.2.5 Access WAI Authentication Response [ref: 1] */ guint16 offset = 0; guint8 optional_field; optional_field = tvb_get_guint8(tvb, 0) & FLAG_BIT3; dissect_flag(tvb, offset, data_tree); offset += 1; offset += dissect_challenge(tvb, offset, data_tree, "ASUE "); offset += dissect_challenge(tvb, offset, data_tree, "AE "); proto_tree_add_item(data_tree, hf_wai_access_res, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; offset += dissect_key_data(tvb, offset, data_tree, "ASUE "); offset += dissect_key_data(tvb, offset, data_tree, "AE "); offset += dissect_identity(tvb, offset, data_tree, "STA AE "); offset += dissect_identity(tvb, offset, data_tree, "STA ASUE "); if (optional_field) { offset += dissect_multiple_certificate(tvb, offset, data_tree); } offset += dissect_signature(tvb, offset, data_tree, "AE Signature"); break; } case WAI_SUB_CERT_AUTH_REQ: { /* Chapter 8.1.4.2.3 Certificate Authentication Request [ref: 1] */ guint16 offset = 0; dissect_addid(tvb, offset, data_tree); offset += 12; offset += dissect_challenge(tvb, offset, data_tree, "AE "); offset += dissect_challenge(tvb, offset, data_tree, "ASUE "); offset += dissect_certificate(tvb, offset, data_tree, "STE ASUE "); offset += dissect_certificate(tvb, offset, data_tree, "STE AE "); offset += dissect_multiple_certificate(tvb, offset, data_tree); break; } case WAI_SUB_CERT_AUTH_RESP: { /* Chapter 8.1.4.2.4 Certificate Authentication Response [ref: 1] */ guint16 offset = 0; dissect_addid(tvb, offset, data_tree); offset += 12; offset += dissect_multiple_certificate(tvb, offset, data_tree); offset += dissect_signature(tvb, offset, data_tree, "Server Signature trusted by ASUE"); offset += dissect_signature(tvb, offset, data_tree, "Server Signature trusted by AE"); break; } case WAI_SUB_UNICAST_KEY_REQ: { /* Chapter 8.1.4.3.1 Unicast Key Negotiation Request [ref: 1] */ dissect_flag(tvb, 0, data_tree); dissect_bkid(tvb, 1, data_tree); dissect_uskid(tvb, 17, data_tree); dissect_addid(tvb, 18, data_tree); dissect_challenge(tvb, 30, data_tree , "AE "); break; } case WAI_SUB_UNICAST_KEY_RESP: { /* Chapter 8.1.4.3.2 Unicast Key Negotiation Response [ref: 1] */ tvbuff_t *next_tvb; guint length = 0; dissect_flag(tvb, 0, data_tree); dissect_bkid(tvb, 1, data_tree); dissect_uskid(tvb, 17, data_tree); dissect_addid(tvb, 18, data_tree); dissect_challenge(tvb, 30, data_tree, "ASUE "); dissect_challenge(tvb, 62, data_tree, "AE "); next_tvb = tvb_new_subset_remaining(tvb, 96); length = tvb_reported_length(next_tvb); dissect_wie(next_tvb, 0, length-20, data_tree); dissect_message_auth_code(next_tvb, length-20, data_tree); break; } case WAI_SUB_UNICAST_KEY_CONFIRM: { /* Chapter 8.1.4.3.3 Unicast Key Negotiation Confirmation [ref: 1] */ tvbuff_t *next_tvb; guint length = 0; dissect_flag(tvb, 0, data_tree); dissect_bkid(tvb, 1, data_tree); dissect_uskid(tvb, 17, data_tree); dissect_addid(tvb, 18, data_tree); dissect_challenge(tvb, 30, data_tree, "ASUE "); next_tvb = tvb_new_subset_remaining(tvb, 62); length = tvb_reported_length(next_tvb); dissect_wie(next_tvb, 0, length-20, data_tree); dissect_message_auth_code(next_tvb, length-20, data_tree); break; } case WAI_SUB_MULTICAST_ANNOUNCE: { /* Chapter 8.1.4.4.1 Multicast Key/STAKey Announcement [ref: 1] */ guint16 offset = 0; dissect_flag(tvb, offset, data_tree); offset += 1; dissect_mskid(tvb, offset, data_tree); offset += 1; dissect_uskid(tvb, offset, data_tree); offset += 1; dissect_addid(tvb, offset, data_tree); offset += 12; proto_tree_add_item(data_tree, hf_wai_data_pack_num, tvb, offset, 16, ENC_NA); offset += 16; dissect_key_announcement_identifier(tvb, offset, data_tree); offset += 16; offset += dissect_key_data(tvb, offset, data_tree, NULL); dissect_message_auth_code(tvb, offset, data_tree); break; } case WAI_SUB_MULTICAST_ANNOUNCE_RESP: { /* Chapter 8.1.4.4.2 Multicast Key/STAKey Announcement Response [ref: 1] */ dissect_flag(tvb, 0, data_tree); dissect_mskid(tvb, 1, data_tree); dissect_uskid(tvb, 2, data_tree); dissect_addid(tvb, 3, data_tree); dissect_key_announcement_identifier(tvb, 15, data_tree); dissect_message_auth_code(tvb, 31, data_tree); break; } default: break; } }
static void dissect_prism(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *prism_tree = NULL, *prism_did_tree = NULL; proto_item *ti = NULL, *ti_did = NULL; tvbuff_t *next_tvb; int offset; guint32 msgcode, msglen, did; guint16 status; guint8 *devname_p; offset = 0; did = 0; /* handle the AVS header */ msgcode = tvb_get_ntohl(tvb, offset); if ((msgcode == WLANCAP_MAGIC_COOKIE_V1) || (msgcode == WLANCAP_MAGIC_COOKIE_V2)) { call_dissector(wlancap_handle, tvb, pinfo, tree); return; } /* * If we don't see a valid message type, assume the Prism or AVS * header was omitted and just hand off to the 802.11 dissector; * at least one capture has AVS headers on some packets and no * radio headers on others (incoming vs. outgoing?). * * XXX - check for both byte orders and use that to determine * the byte order of the fields in the Prism header? */ msgcode = tvb_get_letohl(tvb, offset); if ((msgcode != PRISM_TYPE1_MSGCODE) && (msgcode != PRISM_TYPE2_MSGCODE)) { call_dissector(ieee80211_handle, tvb, pinfo, tree); return; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "Prism"); col_clear(pinfo->cinfo, COL_INFO); if(tree) { ti = proto_tree_add_item(tree, proto_prism, tvb, 0, 144, ENC_NA); prism_tree = proto_item_add_subtree(ti, ett_prism); } /* Message Code */ if(tree) { proto_tree_add_item(prism_tree, hf_ieee80211_prism_msgcode, tvb, offset, 4, ENC_LITTLE_ENDIAN); } msgcode = tvb_get_letohl(tvb, offset); offset += 4; /* Message Length */ if(tree) { proto_tree_add_item(prism_tree, hf_ieee80211_prism_msglen, tvb, offset, 4, ENC_LITTLE_ENDIAN); } msglen = tvb_get_letohl(tvb, offset); offset += 4; /* Device Name */ if(tree) { proto_tree_add_item(prism_tree, hf_ieee80211_prism_devname, tvb, offset, 16, ENC_ASCII|ENC_NA); } devname_p = tvb_get_ephemeral_string(tvb, offset, 16); offset += 16; col_add_fstr(pinfo->cinfo, COL_INFO, "Device: %s, Message 0x%x, Length %d", devname_p, msgcode, msglen); while(offset < PRISM_HEADER_LENGTH) { /* DID */ if(tree) { ti_did = proto_tree_add_item(prism_tree, hf_ieee80211_prism_did, tvb, offset, 12, ENC_NA); prism_did_tree = proto_item_add_subtree(ti_did, ett_prism_did); proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); did = tvb_get_letohl(tvb, offset); proto_item_append_text(ti_did, " %s", val_to_str(did, prism_did_vals, "Unknown %x") ); } offset += 4; /* Status */ status = tvb_get_letohs(tvb, offset); if(tree) { proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_status, tvb, offset, 2, ENC_LITTLE_ENDIAN); } offset += 2; /* Length */ if(tree) { proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); } offset += 2; /* Data, if present... */ if (status == 0) { switch(did){ case PRISM_TYPE1_HOSTTIME: case PRISM_TYPE2_HOSTTIME: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_hosttime, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " %d", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_MACTIME: case PRISM_TYPE2_MACTIME: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_mactime, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " %d", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_CHANNEL: case PRISM_TYPE2_CHANNEL: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_channel, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " %d", tvb_get_letohl(tvb, offset) ); } col_add_fstr(pinfo->cinfo, COL_FREQ_CHAN, "%u", tvb_get_letohl(tvb, offset)); break; case PRISM_TYPE1_RSSI: case PRISM_TYPE2_RSSI: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_rssi, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset) ); } col_add_fstr(pinfo->cinfo, COL_RSSI, "%d", tvb_get_letohl(tvb, offset)); break; case PRISM_TYPE1_SQ: case PRISM_TYPE2_SQ: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_sq, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_SIGNAL: case PRISM_TYPE2_SIGNAL: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_signal, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_NOISE: case PRISM_TYPE2_NOISE: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_noise, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_RATE: case PRISM_TYPE2_RATE: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_rate, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " %s Mb/s", prism_rate_return(tvb_get_letohl(tvb, offset)) ); } col_add_fstr(pinfo->cinfo, COL_TX_RATE, "%s", prism_rate_return(tvb_get_letohl(tvb, offset)) ); break; case PRISM_TYPE1_ISTX: case PRISM_TYPE2_ISTX: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_istx, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " 0x%x", tvb_get_letohl(tvb, offset) ); } break; case PRISM_TYPE1_FRMLEN: case PRISM_TYPE2_FRMLEN: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_frmlen, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_item_append_text(ti_did, " %d", tvb_get_letohl(tvb, offset) ); } break; default: if(tree){ proto_tree_add_item(prism_did_tree, hf_ieee80211_prism_did_unknown, tvb, offset, 4, ENC_LITTLE_ENDIAN); } break; } } offset += 4; } /* dissect the 802.11 header next */ next_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector(ieee80211_handle, next_tvb, pinfo, tree); }
static void dissect_wai(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Format of WAPI protocol packet in WAI authentication system 0 2 3 4 6 8 10 11 12 ------------------------------------------------------------------------------- | Ver. | Type | Subtype | Reserved | Length | packet | fragm. | flag | data | | | seq. no | seq. no | | |-----------------------------------------------------------------------------| Figure 18 from [ref:1] */ #define WAI_MESSAGE_LENGTH 12 /*Length of all fields without 'Data' field*/ #define WAI_DATA_OFFSET WAI_MESSAGE_LENGTH guint16 version; guint8 subtype; guint16 length; guint16 packet_num; guint8 fragment_num; guint8 flags; fragment_data *frag_msg; proto_tree *wai_tree = NULL; tvbuff_t *next_tvb; tvbuff_t *new_tvb; const gchar *subtype_name = "Unknown type"; length = tvb_get_ntohs(tvb, 6)-WAI_MESSAGE_LENGTH; subtype = tvb_get_guint8(tvb, 3); /* quick sanity check */ if ((length != tvb_reported_length (tvb)-WAI_MESSAGE_LENGTH) || (subtype > WAI_SUB_MULTICAST_ANNOUNCE_RESP)) { return; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "WAI"); col_clear(pinfo->cinfo, COL_INFO); version = tvb_get_ntohs(tvb, 0); if (version == 1) { subtype_name = val_to_str_ext_const(subtype, &wai_subtype_names_ext, "Unknown type"); } col_append_fstr(pinfo->cinfo, COL_INFO, "%s", subtype_name); /* Field lengths and offsets in WAI protocol described above */ packet_num = tvb_get_ntohs(tvb, 8); fragment_num = tvb_get_guint8(tvb, 10); flags = tvb_get_guint8(tvb, 11); if (tree) { proto_item *wai_item; wai_item = proto_tree_add_item(tree, proto_wai, tvb, 0, -1, ENC_NA); proto_item_set_text (wai_item, "WAI Protocol (%s)", val_to_str_ext_const(subtype, &wai_subtype_names_ext, "Unknown type")); wai_tree = proto_item_add_subtree(wai_item, ett_wai); /* Field lengths and offsets in WAI protocol described above */ proto_tree_add_item(wai_tree, hf_wai_version, tvb, 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_type, tvb, 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_subtype, tvb, 3, 1, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_reserved, tvb, 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_length, tvb, 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_seq, tvb, 8, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_fragm_seq, tvb, 10, 1, ENC_BIG_ENDIAN); proto_tree_add_item(wai_tree, hf_wai_flag, tvb, 11, 1, ENC_BIG_ENDIAN); } frag_msg = fragment_add_seq_check (tvb, WAI_DATA_OFFSET, pinfo, packet_num, wai_fragment_table, wai_reassembled_table, fragment_num, length, flags); next_tvb = tvb_new_subset_remaining(tvb, WAI_DATA_OFFSET); /* Replace INFO column if message is fragmented and call data_handle */ if (flags) { col_add_fstr(pinfo->cinfo, COL_INFO, "Fragment (%d) of message, data not dissected", fragment_num); process_reassembled_data(tvb, WAI_DATA_OFFSET, pinfo, "Reassembled WAI", frag_msg, &wai_frag_items, NULL, wai_tree); call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* If this is the last fragment of fragmented message, then reassamble and dissect otherwise only dissect */ if (fragment_num > 0) { new_tvb = process_reassembled_data(tvb, WAI_DATA_OFFSET, pinfo, "Reassembled WAI", frag_msg, &wai_frag_items, NULL, wai_tree); if (new_tvb) { col_add_str(pinfo->cinfo, COL_INFO, "Last fragment of message, data dissected"); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", subtype_name); next_tvb=new_tvb; length = tvb_reported_length (next_tvb); } } /* dissect Data field of WAI packet */ if (tree) { dissect_wai_data(next_tvb, wai_tree, subtype, length); } } }
static void dissect_ax25_nol3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree ) { proto_item *ti; proto_tree *ax25_nol3_tree; char *info_buffer; int offset; tvbuff_t *next_tvb = NULL; guint8 dti = 0; gboolean dissected; info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN ); info_buffer[0] = '\0'; col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25-NoL3"); col_clear( pinfo->cinfo, COL_INFO); offset = 0; g_snprintf( info_buffer, STRLEN, "Text" ); if ( gPREF_APRS ) { dti = tvb_get_guint8( tvb, offset ); if ( isaprs( dti ) ) g_snprintf( info_buffer, STRLEN, "APRS" ); } if ( gPREF_DX ) { if ( tvb_get_guint8( tvb, offset ) == 'D' && tvb_get_guint8( tvb, offset + 1 ) == 'X' ) g_snprintf( info_buffer, STRLEN, "DX cluster" ); } col_add_str( pinfo->cinfo, COL_INFO, info_buffer ); /* Call sub-dissectors here */ if ( parent_tree ) { /* create display subtree for the protocol */ ti = proto_tree_add_protocol_format( parent_tree, proto_ax25_nol3, tvb, 0, -1, "AX.25 No Layer 3 - (%s)", info_buffer ); ax25_nol3_tree = proto_item_add_subtree( ti, ett_ax25_nol3 ); next_tvb = tvb_new_subset_remaining(tvb, offset); dissected = FALSE; if ( gPREF_APRS ) { if ( isaprs( dti ) ) { dissected = TRUE; call_dissector( aprs_handle , next_tvb, pinfo, ax25_nol3_tree ); } } if ( gPREF_DX ) { if ( tvb_get_guint8( tvb, offset ) == 'D' && tvb_get_guint8( tvb, offset + 1 ) == 'X' ) { dissected = TRUE; dissect_dx( next_tvb, pinfo, ax25_nol3_tree ); } } if ( ! dissected ) call_dissector( default_handle , next_tvb, pinfo, ax25_nol3_tree ); } }
/* * Dissect an SPDU. */ static int dissect_spdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean tokens, gboolean connectionless) { gboolean has_user_information = FALSE; guint8 type; proto_item *ti = NULL; proto_tree *ses_tree = NULL; int len_len; guint16 parameters_len; tvbuff_t *next_tvb; void *save_private_data; guint32 *pres_ctx_id = NULL; struct SESSION_DATA_STRUCTURE session; /* * Get SPDU type. */ type = tvb_get_guint8(tvb, offset); session.spdu_type = type; session.abort_type = SESSION_NO_ABORT; session.ros_op = 0; session.rtse_reassemble = FALSE; if(connectionless) { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_clses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } has_user_information = TRUE; } else if (tokens) { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_category0_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type_0, tvb, offset, 1, type); } } else { if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, FALSE); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } /* * Might this SPDU have a User Information field? */ switch (type) { case SES_DATA_TRANSFER: case SES_EXPEDITED: case SES_TYPED_DATA: has_user_information = TRUE; break; case SES_MAJOR_SYNC_POINT: pres_ctx_id = p_get_proto_data (pinfo->fd, proto_ses); if (ses_rtse_reassemble != 0 && !pres_ctx_id) { /* First time visited - save pres_ctx_id */ pres_ctx_id = se_alloc (sizeof (guint32)); *pres_ctx_id = ses_pres_ctx_id; p_add_proto_data (pinfo->fd, proto_ses, pres_ctx_id); } if (pres_ctx_id) { session.pres_ctx_id = *pres_ctx_id; session.rtse_reassemble = TRUE; has_user_information = TRUE; } ses_rtse_reassemble = FALSE; break; } } offset++; /* get length of SPDU parameter field */ parameters_len = get_item_len(tvb, offset, &len_len); if (tree) proto_tree_add_uint(ses_tree, hf_ses_length, tvb, offset, len_len, parameters_len); offset += len_len; /* Dissect parameters. */ if (!dissect_parameters(tvb, offset, parameters_len, tree, ses_tree, pinfo, &session)) has_user_information = FALSE; offset += parameters_len; proto_item_set_end(ti, tvb, offset); /* Dissect user information, if present */ if (has_user_information) { if (tvb_reported_length_remaining(tvb, offset) > 0 || type == SES_MAJOR_SYNC_POINT) { next_tvb = tvb_new_subset_remaining(tvb, offset); if(!pres_handle) { call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* save type of session pdu. We'll need it in the presentation dissector */ save_private_data = pinfo->private_data; pinfo->private_data = &session; call_dissector(pres_handle, next_tvb, pinfo, tree); pinfo->private_data = save_private_data; } /* * No more SPDUs to dissect. Set the offset to the * end of the tvbuff. */ offset = tvb_length(tvb); if (session.rtse_reassemble && type == SES_DATA_TRANSFER) { ses_pres_ctx_id = session.pres_ctx_id; ses_rtse_reassemble = TRUE; } } } return offset; }
static void dissect_rmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *rmi_tree; tvbuff_t *next_tvb; gint offset; gint next_offset; int datalen; guint16 version, len, port; guint8 message, proto; rmi_type rmitype; const char *epid_hostname; guint epid_len; offset = 0; rmitype = 0; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RMI"); datalen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); rmitype = get_rmi_type(tvb, offset, datalen); if (check_col(pinfo->cinfo, COL_INFO)) { switch(rmitype) { case RMI_OUTPUTSTREAM: version = tvb_get_ntohs(tvb,4); col_add_fstr(pinfo->cinfo, COL_INFO, "JRMI, Version: %d, ", version); proto = tvb_get_guint8(tvb, 6); col_append_str(pinfo->cinfo, COL_INFO, val_to_str(proto, rmi_protocol_str, "Unknown protocol")); break; case RMI_OUTPUTMESSAGE: message = tvb_get_guint8(tvb,0); col_set_str(pinfo->cinfo, COL_INFO, "JRMI, "); col_append_str(pinfo->cinfo, COL_INFO, val_to_str(message, rmi_output_message_str, "Unknown message")); break; case RMI_INPUTSTREAM: message = tvb_get_guint8(tvb,0); col_set_str(pinfo->cinfo, COL_INFO, "JRMI, "); col_append_str(pinfo->cinfo, COL_INFO, val_to_str(message, rmi_input_message_str, "Unknown message")); break; case SERIALIZATION_DATA: version = tvb_get_ntohs(tvb,2); col_add_fstr(pinfo->cinfo, COL_INFO, "Serialization data, Version: %d", version); break; default: col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); break; } } if (tree) { ti = proto_tree_add_item(tree, proto_rmi, tvb, 0, -1, ENC_NA); rmi_tree = proto_item_add_subtree(ti, ett_rmi); switch(rmitype) { case RMI_OUTPUTSTREAM: /* XXX - uint, or string? */ proto_tree_add_uint(rmi_tree, hf_rmi_magic, tvb, offset, 4, tvb_get_ntohl(tvb,0)); proto_tree_add_item(rmi_tree, hf_rmi_version, tvb, offset + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(rmi_tree, hf_rmi_protocol, tvb, offset + 6, 1, ENC_BIG_ENDIAN); break; case RMI_INPUTSTREAM: message = tvb_get_guint8(tvb, 0); proto_tree_add_uint(rmi_tree, hf_rmi_inputmessage, tvb, offset, 1, message); if(message == RMI_INPUTSTREAM_MESSAGE_ACK) { proto_tree_add_text(rmi_tree, tvb, offset + 1, -1, "EndPointIdentifier"); /* MESSAGE_ACK should include EndpointIdentifier */ len = tvb_get_ntohs(tvb, 1); proto_tree_add_uint(rmi_tree, hf_rmi_epid_length, tvb, offset + 1, 2, len); epid_len = len < ITEM_LABEL_LENGTH ? len : ITEM_LABEL_LENGTH; if (epid_len > 0) { epid_hostname = tvb_format_text(tvb, offset + 3, epid_len); } else { epid_hostname = "[Empty]"; } proto_tree_add_string(rmi_tree, hf_rmi_epid_hostname, tvb, offset + 3, len, epid_hostname); port = tvb_get_ntohs(tvb, offset + len + 5); proto_tree_add_uint(rmi_tree, hf_rmi_epid_port, tvb, offset + len + 5, 2, port); } if(message == RMI_INPUTSTREAM_MESSAGE_RETURNDATA) { proto_tree_add_text(rmi_tree, tvb, offset + 1, -1, "Serialization Data"); next_tvb = tvb_new_subset_remaining(tvb, offset + 1); dissect_ser(next_tvb, tree); } break; case RMI_OUTPUTMESSAGE: message = tvb_get_guint8(tvb, 0); proto_tree_add_uint(rmi_tree, hf_rmi_outputmessage, tvb, offset, 1, message); if(message == RMI_OUTPUTSTREAM_MESSAGE_CALL) { proto_tree_add_text(rmi_tree, tvb, offset + 1, -1, "Serialization Data"); /* XXX */ next_tvb = tvb_new_subset_remaining(tvb, offset + 1); dissect_ser(next_tvb, tree); } if(message == RMI_OUTPUTSTREAM_MESSAGE_DGCACK) { proto_tree_add_text(rmi_tree, tvb, offset + 1, -1, "UniqueIdentifier"); } break; case SERIALIZATION_DATA: dissect_ser(tvb, tree); break; default: break; } } }
static void dissect_icap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *icap_tree = NULL; proto_item *ti = NULL; proto_item *hidden_item; gint offset = 0; const guchar *line; gint next_offset; const guchar *linep, *lineend; int linelen; guchar c; icap_type_t icap_type; int datalen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICAP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary * if it's an ICAP header (but leave out the * line terminator). * Otherwise, just call it a continuation. * * Note that "tvb_find_line_end()" will return a value that * is not longer than what's in the buffer, so the * "tvb_get_ptr()" call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); icap_type = ICAP_OTHER; /* type not known yet */ if (is_icap_message(line, linelen, &icap_type)) col_add_str(pinfo->cinfo, COL_INFO, format_text(line, linelen)); else col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); } if (tree) { ti = proto_tree_add_item(tree, proto_icap, tvb, offset, -1, ENC_NA); icap_tree = proto_item_add_subtree(ti, ett_icap); } /* * Process the packet data, a line at a time. */ icap_type = ICAP_OTHER; /* type not known yet */ while (tvb_offset_exists(tvb, offset)) { gboolean is_icap = FALSE; gboolean loop_done = FALSE; /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Get a buffer that refers to the line. */ line = tvb_get_ptr(tvb, offset, linelen); lineend = line + linelen; /* * find header format */ if (is_icap_message(line, linelen, &icap_type)) { goto is_icap_header; } /* * if it looks like a blank line, end of header perhaps? */ if (linelen == 0) { goto is_icap_header; } /* * No. Does it look like a header? */ linep = line; loop_done = FALSE; while (linep < lineend && (!loop_done)) { c = *linep++; /* * This must be a CHAR to be part of a token; that * means it must be ASCII. */ if (!isascii(c)) { is_icap = FALSE; break; /* not ASCII, thus not a CHAR */ } /* * This mustn't be a CTL to be part of a token. * * XXX - what about leading LWS on continuation * lines of a header? */ if (iscntrl(c)) { is_icap = FALSE; break; /* CTL, not part of a header */ } switch (c) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': case '{': case '}': /* * It's a separator, so it's not part of a * token, so it's not a field name for the * beginning of a header. * * (We don't have to check for HT; that's * already been ruled out by "iscntrl()".) * * XXX - what about ' '? HTTP's checks * check for that. */ is_icap = FALSE; loop_done = TRUE; break; case ':': /* * This ends the token; we consider this * to be a header. */ goto is_icap_header; } } /* * We don't consider this part of an ICAP message, * so we don't display it. * (Yeah, that means we don't display, say, a text/icap * page, but you can get that from the data pane.) */ if (!is_icap) break; is_icap_header: if (tree) { proto_tree_add_text(icap_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset) ); } offset = next_offset; } if (tree) { switch (icap_type) { case ICAP_OPTIONS: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_options, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_REQMOD: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_reqmod, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_RESPMOD: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_respmod, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_RESPONSE: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_response, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_OTHER: default: break; } } datalen = tvb_length_remaining(tvb, offset); if (datalen > 0) { call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, icap_tree); } }
static void dissect_tzsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *tzsp_tree = NULL; proto_item *ti = NULL; int pos = 0; tvbuff_t *next_tvb; guint16 encapsulation = 0; int wtap_encap; dissector_handle_t encap_dissector; const char *encap_name; const char *info; guint8 type; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TZSP"); col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, 1); /* Find the dissector. */ encapsulation = tvb_get_ntohs(tvb, 2); if (encapsulation != 0) { wtap_encap = tzsp_encap_to_wtap_encap(encapsulation); if (wtap_encap != -1 && (encap_dissector = dissector_get_uint_handle(encap_dissector_table, wtap_encap))) { encap_name = dissector_handle_get_short_name(encap_dissector); } else { encap_name = "Unknown"; } info = encap_name; } else { wtap_encap = -1; encap_name = "Nothing"; info = val_to_str(type, tzsp_type, "Unknown (%u)"); } col_add_str(pinfo->cinfo, COL_INFO, info); if (tree) { /* Adding TZSP item and subtree */ ti = proto_tree_add_protocol_format(tree, proto_tzsp, tvb, 0, -1, "TZSP: %s: ", info); tzsp_tree = proto_item_add_subtree(ti, ett_tzsp); proto_tree_add_item (tzsp_tree, hf_tzsp_version, tvb, 0, 1, FALSE); proto_tree_add_uint (tzsp_tree, hf_tzsp_type, tvb, 1, 1, type); proto_tree_add_uint_format (tzsp_tree, hf_tzsp_encap, tvb, 2, 2, encapsulation, "Encapsulates: %s (%d)", encap_name, encapsulation); } if (type != 4 && type != 5) { pos = add_option_info(tvb, 4, tzsp_tree, ti); if (tree) proto_item_set_end(ti, tvb, pos); next_tvb = tvb_new_subset_remaining(tvb, pos); if (encapsulation != 0 && (wtap_encap == -1 || !dissector_try_uint(encap_dissector_table, wtap_encap, next_tvb, pinfo, tree))) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "UNKNOWN"); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "TZSP_ENCAP = %u", encapsulation); call_dissector(data_handle, next_tvb, pinfo, tree); } } }