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_item = proto_tree_add_text(rtacser_tree, tvb, offset, 1, "Control Lines"); cl_tree = proto_item_add_subtree(cl_item, ett_rtacser_cl); /* 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 void dissect_srv_records(tvbuff_t* tvb, proto_tree* tree,guint32 nrec,int offset) { guint32 i, curr; guint16 /*len, namelen,*/ priority, weight, port, dlen; const guchar *dname; proto_item* srv_rec_item, *rec_item; proto_item* srv_rec_tree, *rec_tree; if(tree) { srv_rec_item = proto_tree_add_text(tree, tvb, offset, offset, "SRV records"); srv_rec_tree = proto_item_add_subtree(srv_rec_item, ett_srv_rec); proto_item_set_text(srv_rec_item, "SRV records (%d)", nrec); } else return; curr = offset; for(i=0; i < nrec; i++) { /*len = tvb_get_ntohs(tvb, curr);*/ priority = tvb_get_ntohs(tvb, curr + 2); weight = tvb_get_ntohs(tvb, curr + 4); port = tvb_get_ntohs(tvb, curr + 6); /*namelen = len - 8;*/ dlen = get_dns_name(tvb, curr + 8, 0, curr + 8, &dname); if(srv_rec_tree) { rec_item = proto_tree_add_text(srv_rec_tree, tvb, curr, 6," "); rec_tree = proto_item_add_subtree(rec_item, ett_srv_rec_item); proto_item_set_text(rec_item, "SRV record:pri=%d,w=%d,port=%d,dname=%s", priority, weight, port, dname); } else return; proto_tree_add_uint(rec_tree, hf_srv_prio, tvb, curr + 2, 2, priority); proto_tree_add_uint(rec_tree, hf_srv_weight, tvb, curr + 4, 2, weight); proto_tree_add_uint(rec_tree, hf_srv_port, tvb, curr + 6, 2, port); proto_tree_add_text(rec_tree, tvb, curr + 8, dlen, "DNAME: %s", dname); curr+=(int)((sizeof(short)*4) + dlen); } }
static void dissect_hpsw_tlv(tvbuff_t *tvb, packet_info *pinfo, int offset, int length, proto_tree *tree, proto_item *ti, guint8 type) { switch (type) { case HPFOO_DEVICE_NAME: if (length > 0) { proto_tree_add_item(tree, hf_hpsw_device_name, tvb, offset, length, ENC_NA|ENC_ASCII); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Device Name: Bad length %u", length); } break; case HPFOO_DEVICE_VERSION: if (length > 0) { proto_tree_add_item(tree, hf_hpsw_device_version, tvb, offset, length, ENC_NA|ENC_ASCII); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Version: Bad length %u", length); } break; case HPFOO_CONFIG_NAME: if (length > 0) { proto_tree_add_item(tree, hf_hpsw_config_name, tvb, offset, length, ENC_NA|ENC_ASCII); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Config Name: Bad length %u", length); } break; case HPFOO_ROOT_MAC_ADDR: if (length == 6) { proto_tree_add_item(tree, hf_hpsw_root_mac_addr, tvb, offset, length, ENC_NA); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Root MAC Addr: Bad length %u", length); } break; case HPFOO_IP_ADDR: if (length == 4) { proto_tree_add_item(tree, hf_hpsw_ip_addr, tvb, offset, length, ENC_BIG_ENDIAN); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "IP Addr: Bad length %u", length); } break; case HPFOO_FIELD_6: if (length == 2) { proto_tree_add_item(tree, hf_hpsw_field_6, tvb, offset, length, ENC_BIG_ENDIAN); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Field 6: Bad length %u", length); } break; case HPFOO_DOMAIN: if (length > 0) { proto_tree_add_item(tree, hf_hpsw_domain, tvb, offset, length, ENC_NA|ENC_ASCII); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Domain: Bad length %u", length); } break; case HPFOO_FIELD_8: if (length == 2) { proto_tree_add_item(tree, hf_hpsw_field_8, tvb, offset, length, ENC_BIG_ENDIAN); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Field 8: Bad length %u", length); } break; case HPFOO_FIELD_9: if (length == 2) { proto_tree_add_item(tree, hf_hpsw_field_9, tvb, offset, length, ENC_BIG_ENDIAN); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Field 9: Bad length %u", length); } break; case HPFOO_FIELD_10: if (length == 4) { proto_tree_add_item(tree, hf_hpsw_field_10, tvb, offset, length, ENC_BIG_ENDIAN); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Field 10: Bad length %u", length); } break; case HPFOO_NEIGHBORS: if (!(length % 6)) { int i = length/6; proto_item_set_text(ti, "Number of neighbor MAC Addresses: %u", i); for ( ; i; i--) { proto_tree_add_item(tree, hf_hpsw_neighbor_mac_addr, tvb, offset, length, ENC_NA); offset += 6; } } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Neighbors: Bad length %u", length); } break; case HPFOO_FIELD_12: if (length == 1) { proto_tree_add_item(tree, hf_hpsw_field_12, tvb, offset, length, ENC_NA); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Field 12: Bad length %u", length); } break; case HPFOO_DEVICE_ID: if (length > 6) { proto_tree_add_item(tree, hf_hpsw_device_id, tvb, offset, 6, ENC_NA); proto_tree_add_item(tree, hf_hpsw_device_id_data, tvb, offset+6, length-6, ENC_NA); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Device ID: Bad length %u", length); } break; case HPFOO_OWN_MAC_ADDR: if (length == 6) { proto_tree_add_item(tree, hf_hpsw_own_mac_addr, tvb, offset, length, ENC_NA); } else { expert_add_info_format(pinfo, ti, &ei_hpsw_tlvlength_bad, "Own MAC Addr: Bad length %u", length); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Data"); break; } }
/* * Dissect ASCII TPKT-encapsulated data in a TCP stream. */ void dissect_asciitpkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, dissector_handle_t subdissector_handle) { proto_item *ti = NULL; proto_tree *tpkt_tree = NULL; volatile int offset = 0; int length_remaining; int data_len; volatile int mgcp_packet_len = 0; int mgcp_version = 0; int mgcp_reserved = 0; volatile int length; tvbuff_t *volatile next_tvb; const char *saved_proto; guint8 string[4]; /* * If we're reassembling segmented TPKT PDUs, empty the COL_INFO * column, so subdissectors can append information * without having to worry about emptying the column. * * We use "col_add_str()" because the subdissector * might be appending information to the column, in * which case we'd have to zero the buffer out explicitly * anyway. */ if (tpkt_desegment) col_set_str(pinfo->cinfo, COL_INFO, ""); while (tvb_reported_length_remaining(tvb, offset) != 0) { /* * Is the first byte of this putative TPKT header * a valid TPKT version number, i.e. 3? */ if (tvb_get_guint8(tvb, offset) != 48) { /* * No, so don't assume this is a TPKT header; * we might be in the middle of TPKT data, * so don't get the length and don't try to * do reassembly. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPKT"); col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); if (tree) { ti = proto_tree_add_item(tree, proto_tpkt, tvb, offset, -1, ENC_NA); tpkt_tree = proto_item_add_subtree(ti, ett_tpkt); proto_tree_add_item(tpkt_tree, hf_tpkt_continuation_data, tvb, offset, -1, ENC_NA); } return; } length_remaining = tvb_captured_length_remaining(tvb, offset); /* * Get the length from the TPKT header. */ tvb_memcpy(tvb, (guint8 *)string, offset, 2); mgcp_version = parseVersionText(string); tvb_memcpy(tvb, (guint8 *)string, offset +2, 2); mgcp_reserved = parseReservedText(string); tvb_memcpy(tvb, (guint8 *)string, offset + 4, 4); mgcp_packet_len = parseLengthText(string); data_len = mgcp_packet_len; /* * Dissect the TPKT header. * Save and restore "pinfo->current_proto". */ saved_proto = pinfo->current_proto; pinfo->current_proto = "TPKT"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPKT"); /* * Don't add the TPKT header information if we're * reassembling segmented TPKT PDUs or if this * PDU isn't reassembled. * * XXX - the first is so that subdissectors can append * information without getting TPKT stuff in the middle; * why the second? */ if (!tpkt_desegment && !pinfo->fragmented) { col_add_fstr(pinfo->cinfo, COL_INFO, "TPKT Data length = %u", data_len); } if (tree) { ti = proto_tree_add_item(tree, proto_tpkt, tvb, offset, 8, ENC_NA); tpkt_tree = proto_item_add_subtree(ti, ett_tpkt); proto_item_set_text(ti, "TPKT"); /* Version */ proto_tree_add_uint(tpkt_tree, hf_tpkt_version, tvb, offset, 2, mgcp_version); /* Reserved octet*/ proto_tree_add_uint(tpkt_tree, hf_tpkt_reserved, tvb, offset + 2, 2, mgcp_reserved); /* Length */ proto_tree_add_uint(tpkt_tree, hf_tpkt_length, tvb, offset + 4, 4, mgcp_packet_len); } pinfo->current_proto = saved_proto; /* Skip the TPKT header. */ offset += TEXT_LAYER_LENGTH; length = length_remaining - TEXT_LAYER_LENGTH; if (length > data_len) length = data_len; next_tvb = tvb_new_subset(tvb, offset,length, data_len); /* * Call the subdissector. * * If it gets an error that means there's no point in * dissecting any more TPKT messages, rethrow the * exception in question. * * If it gets any other error, report it and continue, as that * means that TPKT message got an error, but that doesn't mean * we should stop dissecting TPKT messages within this frame * or chunk of reassembled data. */ TRY { call_dissector(subdissector_handle, next_tvb, pinfo, tree); } CATCH_NONFATAL_ERRORS { show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; /* * Skip the payload. */ offset += data_len; } }
/* * Dissect TPKT-encapsulated data in a TCP stream. */ void dissect_tpkt_encap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean desegment, dissector_handle_t subdissector_handle) { proto_item *ti = NULL; proto_tree *tpkt_tree = NULL; volatile int offset = 0; int length_remaining; int data_len; volatile int length; tvbuff_t *volatile next_tvb; const char *saved_proto; /* * If we're reassembling segmented TPKT PDUs, empty the COL_INFO * column, so subdissectors can append information * without having to worry about emptying the column. * * We use "col_add_str()" because the subdissector * might be appending information to the column, in * which case we'd have to zero the buffer out explicitly * anyway. */ if (desegment) col_set_str(pinfo->cinfo, COL_INFO, ""); while (tvb_reported_length_remaining(tvb, offset) != 0) { /* * Is the first byte of this putative TPKT header * a valid TPKT version number, i.e. 3? */ if (tvb_get_guint8(tvb, offset) != 3) { /* * No, so don't assume this is a TPKT header; * we might be in the middle of TPKT data, * so don't get the length and don't try to * do reassembly. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPKT"); col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); if (tree) { ti = proto_tree_add_item(tree, proto_tpkt, tvb, offset, -1, ENC_NA); tpkt_tree = proto_item_add_subtree(ti, ett_tpkt); proto_tree_add_item(tpkt_tree, hf_tpkt_continuation_data, tvb, offset, -1, ENC_NA); } return; } length_remaining = tvb_captured_length_remaining(tvb, offset); /* * Can we do reassembly? */ if (desegment && pinfo->can_desegment) { /* * Yes - is the TPKT header split across segment * boundaries? */ if (length_remaining < 4) { /* * Yes. Tell the TCP dissector where the data * for this message starts in the data it * handed us and that we need "some more data." * Don't tell it exactly how many bytes we need * because if/when we ask for even more (after * the header) that will break reassembly. */ pinfo->desegment_offset = offset; pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return; } } /* * Get the length from the TPKT header. */ data_len = tvb_get_ntohs(tvb, offset + 2); /* * Can we do reassembly? */ if (desegment && pinfo->can_desegment) { /* * Yes - is the payload split across segment * boundaries? */ if (length_remaining < data_len) { /* * Yes. Tell the TCP dissector where * the data for this message starts in * the data it handed us, and how many * more bytes we need, and return. */ pinfo->desegment_offset = offset; pinfo->desegment_len = data_len - length_remaining; return; } } /* * Dissect the TPKT header. * Save and restore "pinfo->current_proto". */ saved_proto = pinfo->current_proto; pinfo->current_proto = "TPKT"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TPKT"); /* * Don't add the TPKT header information if we're * reassembling segmented TPKT PDUs or if this * PDU isn't reassembled. * * XXX - the first is so that subdissectors can append * information without getting TPKT stuff in the middle; * why the second? */ if (!desegment && !pinfo->fragmented) { col_add_fstr(pinfo->cinfo, COL_INFO, "TPKT Data length = %u", data_len); } if (tree) { ti = proto_tree_add_item(tree, proto_tpkt, tvb, offset, 4, ENC_NA); tpkt_tree = proto_item_add_subtree(ti, ett_tpkt); proto_item_set_text(ti, "TPKT"); /* Version */ proto_tree_add_item(tpkt_tree, hf_tpkt_version, tvb, offset, 1, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", Version: 3"); /* Reserved octet*/ proto_tree_add_item(tpkt_tree, hf_tpkt_reserved, tvb, offset + 1, 1, ENC_BIG_ENDIAN); /* Length */ proto_tree_add_uint(tpkt_tree, hf_tpkt_length, tvb, offset + 2, 2, data_len); proto_item_append_text(ti, ", Length: %u", data_len); } pinfo->current_proto = saved_proto; /* Skip the TPKT header. */ offset += 4; data_len -= 4; /* * Construct a tvbuff containing the amount of the payload * we have available. Make its reported length the * amount of data in this TPKT packet. * * XXX - if reassembly isn't enabled. the subdissector * will throw a BoundsError exception, rather than a * ReportedBoundsError exception. We really want * a tvbuff where the length is "length", the reported * length is "plen + 2", and the "if the snapshot length * were infinite" length were the minimum of the * reported length of the tvbuff handed to us and "plen+2", * with a new type of exception thrown if the offset is * within the reported length but beyond that third length, * with that exception getting the "Unreassembled Packet" * error. */ length = length_remaining - 4; if (length > data_len) length = data_len; next_tvb = tvb_new_subset(tvb, offset, length, data_len); /* * Call the subdissector. * * If it gets an error that means there's no point in * dissecting any more TPKT messages, rethrow the * exception in question. * * If it gets any other error, report it and continue, * as that means that TPKT message got an error, but * that doesn't mean we should stop dissecting TPKT * messages within this frame or chunk of reassembled * data. */ TRY { call_dissector(subdissector_handle, next_tvb, pinfo, tree); } CATCH_NONFATAL_ERRORS { show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; /* * Skip the payload. */ offset += length; } }
static int dissect_dvmrp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset) { guint8 code; guint8 af=2; /* default */ /* version */ proto_tree_add_uint(parent_tree, hf_version, tvb, 0, 0, 1); /* type of command */ proto_tree_add_uint(parent_tree, hf_type, tvb, offset, 1, 0x13); offset += 1; /* code */ code = tvb_get_guint8(tvb, offset); proto_tree_add_uint(parent_tree, hf_code_v1, tvb, offset, 1, code); offset += 1; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "V%d %s",1 ,val_to_str(code, code_v1, "Unknown Type:0x%02x")); } /* checksum */ igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0); offset += 2; /* decode all the v1 commands */ while (tvb_reported_length_remaining(tvb, offset) > 0) { proto_tree *tree; proto_item *item; guint8 cmd,count; int old_offset = offset; item = proto_tree_add_item(parent_tree, hf_commands, tvb, offset, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_commands); cmd = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_command, tvb, offset, 1, cmd); offset += 1; switch (cmd){ case V1_COMMAND_NULL: offset += 1; /* skip ignored/pad byte*/ if (item) { proto_item_set_text(item, "Command: NULL"); } break; case V1_COMMAND_AFI: af = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_afi, tvb, offset, 1, af); offset += 1; if (item) { proto_item_set_text(item, "%s: %s", val_to_str(cmd, command, "Unknown Command:0x%02x"), val_to_str(af, afi, "Unknown Family:0x%02x") ); } break; case V1_COMMAND_SUBNETMASK: count = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_count, tvb, offset, 1, count); offset += 1; if (count) { /* must be 0 or 1 */ proto_tree_add_item(tree, hf_netmask, tvb, offset, 4, ENC_BIG_ENDIAN); if (item) { proto_item_set_text(item, "%s: %d.%d.%d.%d", val_to_str(cmd, command, "Unknown Command:0x%02x"), tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset+1), tvb_get_guint8(tvb, offset+2), tvb_get_guint8(tvb, offset+3)); } offset += 4; } else { if (item) { proto_item_set_text(item, "%s: <no mask supplied>", val_to_str(cmd, command, "Unknown Command:0x%02x")); } } break; case V1_COMMAND_METRIC: proto_tree_add_item(tree, hf_metric, tvb, offset, 1, ENC_BIG_ENDIAN); if (item) { proto_item_set_text(item, "%s: %d", val_to_str(cmd, command, "Unknown Command:0x%02x"), tvb_get_guint8(tvb, offset)); } offset += 1; break; case V1_COMMAND_FLAGS0: count = tvb_get_guint8(tvb, offset); proto_tree_add_boolean(tree, hf_dest_unr, tvb, offset, 1, count); proto_tree_add_boolean(tree, hf_split_horiz, tvb, offset, 1, count); if (item) { proto_item_set_text(item, "%s: 0x%02x", val_to_str(cmd, command, "Unknown Command:0x%02x"), count); } offset += 1; break; case V1_COMMAND_INFINITY: proto_tree_add_item(tree, hf_infinity, tvb, offset, 1, ENC_BIG_ENDIAN); if (item) { proto_item_set_text(item, "%s: %d", val_to_str(cmd, command, "Unknown Command:0x%02x"), tvb_get_guint8(tvb, offset)); } offset += 1; break; case V1_COMMAND_DA: case V1_COMMAND_RDA: /* same as DA */ count = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_count, tvb, offset, 1, count); offset += 1; while (count--) { proto_tree_add_item(tree, hf_daddr, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (item) { proto_item_set_text(item, "%s", val_to_str(cmd, command, "Unknown Command:0x%02x")); } break; case V1_COMMAND_NMR: count = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_count, tvb, offset, 1, count); offset += 1; while (count--) { proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(tree, hf_hold, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (item) { proto_item_set_text(item, "%s", val_to_str(cmd, command, "Unknown Command:0x%02x")); } break; case V1_COMMAND_NMR_CANCEL: count = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_count, tvb, offset, 1, count); offset += 1; while (count--) { proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (item) { proto_item_set_text(item, "%s", val_to_str(cmd, command, "Unknown Command:0x%02x")); } break; } proto_item_set_len(item, offset-old_offset); } return offset; }
static int dissect_adwin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti, *ti2; proto_tree *adwin_tree, *adwin_debug_tree; gchar *info_string; guint32 length; length = tvb_reported_length(tvb); /* First do some heuristics to see if this packet belongs to us */ if(! (length == UDPH1_OLD_LENGTH || length == UDPH1_NEW_LENGTH || length == UDPR1_LENGTH || length == UDPH2_LENGTH || length == UDPR2_LENGTH || length == UDPR3_LENGTH || length == UDPR4_LENGTH || length == GetDataSHPacket_LENGTH || length == GetDataSHRequest_LENGTH)) return(0); col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADwin"); col_clear(pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_adwin, tvb, 0, -1, ENC_NA); adwin_tree = proto_item_add_subtree(ti, ett_adwin); ti2 = proto_tree_add_item(adwin_tree, proto_adwin, tvb, 0, -1, ENC_NA); adwin_debug_tree = proto_item_add_subtree(ti2, ett_adwin_debug); proto_item_set_text(ti2, "ADwin Debug information"); } else { adwin_tree = NULL; adwin_debug_tree = NULL; } switch (length) { case UDPH1_OLD_LENGTH: dissect_UDPH1_old(tvb, pinfo, adwin_tree, adwin_debug_tree, &info_string); break; case UDPH1_NEW_LENGTH: dissect_UDPH1_new(tvb, pinfo, adwin_tree, adwin_debug_tree, &info_string); break; case UDPR1_LENGTH: dissect_UDPR1(tvb, pinfo, adwin_tree, adwin_debug_tree, &info_string); break; case UDPH2_LENGTH: /* to the best of my knowledge, this struct * has never been used publically! */ /* dissect_UDPH2(tvb, pinfo, adwin_tree, adwin_debug_tree); */ info_string = ep_strdup("UDPH2 - UNUSED"); break; case UDPR2_LENGTH: dissect_UDPR2(tvb, pinfo, adwin_tree, adwin_debug_tree, &info_string); break; case UDPR3_LENGTH: dissect_UDPR3(tvb, pinfo, adwin_tree, adwin_debug_tree); info_string = ep_strdup("UDPR3"); break; case UDPR4_LENGTH: dissect_UDPR4(tvb, pinfo, adwin_tree, adwin_debug_tree, &info_string); break; case GetDataSHPacket_LENGTH: dissect_GDSHP(tvb, pinfo, adwin_tree, adwin_debug_tree); info_string = ep_strdup("GDSHP"); break; case GetDataSHRequest_LENGTH: dissect_GDSHR(tvb, pinfo, adwin_tree, adwin_debug_tree); info_string = ep_strdup("GDSHR"); break; default: info_string = ep_strdup_printf("Unknown ADwin packet, length: %d", length); break; } col_add_str(pinfo->cinfo, COL_INFO, info_string); return (tvb_reported_length(tvb)); }
static void dissect_hpsw_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree, proto_item *ti, guint8 type) { switch (type) { case HPFOO_DEVICE_NAME: if (length > 0) { proto_item_set_text(ti, "Device Name: %s", tvb_format_text(tvb, offset, length - 1)); proto_tree_add_text(tree, tvb, offset, length, "Device Name: %s", tvb_format_text(tvb, offset, length - 1)); } else { proto_item_set_text(ti, "Device Name: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Device Name: Bad length %u", length); } break; case HPFOO_DEVICE_VERSION: if (length > 0) { proto_item_set_text(ti, "Version: %s", tvb_format_text(tvb, offset, length - 1)); proto_tree_add_text(tree, tvb, offset, length, "Version: %s", tvb_format_text(tvb, offset, length - 1)); } else { proto_item_set_text(ti, "Version: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Version: Bad length %u", length); } break; case HPFOO_CONFIG_NAME: if (length > 0) { proto_item_set_text(ti, "Config: %s", tvb_format_text(tvb, offset, length - 1)); proto_tree_add_text(tree, tvb, offset, length, "Config: %s", tvb_format_text(tvb, offset, length - 1)); } else { proto_item_set_text(ti, "Config: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Config: Bad length %u", length); } break; case HPFOO_IP_ADDR: if (length == 4) { const char *ipstr = tvb_ip_to_str(tvb, offset); proto_item_set_text(ti, "IP Addr: %s", ipstr); proto_tree_add_text(tree, tvb, offset, length, "IP Addr: %s", ipstr); } else { proto_item_set_text(ti, "IP Addr: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "IP Addr: Bad length %u", length); } break; case HPFOO_FIELD_7: if (length == 1) { proto_item_set_text(ti, "Field 7: 0x%02x", tvb_get_guint8(tvb,offset)); proto_tree_add_text(tree, tvb, offset, length, "Field 7: 0x%02x", tvb_get_guint8(tvb,offset)); } else { proto_item_set_text(ti, "Field 7: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Field 7: Bad length %u", length); } break; case HPFOO_FIELD_8: if (length == 2) { proto_item_set_text(ti, "Field 8: 0x%04x", tvb_get_ntohs(tvb,offset)); proto_tree_add_text(tree, tvb, offset, length, "Field 8: 0x%04x", tvb_get_ntohs(tvb,offset)); } else { proto_item_set_text(ti, "Field 8: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Field 8: Bad length %u", length); } break; case HPFOO_FIELD_9: if (length == 2) { proto_item_set_text(ti, "Field 9: 0x%04x", tvb_get_ntohs(tvb,offset)); proto_tree_add_text(tree, tvb, offset, length, "Field 9: 0x%04x", tvb_get_ntohs(tvb,offset)); } else { proto_item_set_text(ti, "Field 9: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Field 9: Bad length %u", length); } break; case HPFOO_FIELD_10: if (length == 4) { proto_item_set_text(ti, "Field 10: 0x%08x", tvb_get_ntohl(tvb,offset)); proto_tree_add_text(tree, tvb, offset, length, "Field 10: 0x%08x", tvb_get_ntohl(tvb,offset)); } else { proto_item_set_text(ti, "Field 10: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Field 10: Bad length %u", length); } break; case HPFOO_FIELD_12: if (length == 1) { proto_item_set_text(ti, "Field 12: 0x%02x", tvb_get_guint8(tvb,offset)); proto_tree_add_text(tree, tvb, offset, length, "Field 12: 0x%02x", tvb_get_guint8(tvb,offset)); } else { proto_item_set_text(ti, "Field 12: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Field 12: Bad length %u", length); } break; case HPFOO_DEVICE_ID: if (length == 10) { const gchar *macstr = tvb_ether_to_str(tvb, offset); guint32 id=tvb_get_ntohl(tvb, offset+6); proto_item_set_text(ti, "Device ID: %s / %u", macstr, id); proto_tree_add_text(tree, tvb, offset, 10, "Device ID: %s / %u", macstr, id); } else { proto_item_set_text(ti, "Device ID: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Device ID: Bad length %u", length); } break; case HPFOO_MAC_ADDR: if (length == 6) { const gchar *macstr = tvb_ether_to_str(tvb, offset); proto_item_set_text(ti, "MAC Addr: %s", macstr); proto_tree_add_text(tree, tvb, offset, length, "MAC Addr: %s", macstr); } else { proto_item_set_text(ti, "MAC Addr: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "MAC Addr: Bad length %u", length); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Data"); break; } }
static void dissect_nv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *nv_tree, *nv_header_tree, *nv_var_tree,*nv_varheader_tree; gint offset = 0; char szText[200]; int nMax = (int)sizeof(szText)-1; gint i; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TC-NV"); col_clear(pinfo->cinfo, COL_INFO); NvSummaryFormater(tvb, offset, szText, nMax); col_append_str(pinfo->cinfo, COL_INFO, szText); if (tree) { guint16 nv_count; ti = proto_tree_add_item(tree, proto_nv, tvb, 0, -1, ENC_NA); nv_tree = proto_item_add_subtree(ti, ett_nv); proto_item_append_text(ti,": %s",szText); ti = proto_tree_add_item(nv_tree, hf_nv_header, tvb, offset, NvParserHDR_Len, ENC_NA); nv_header_tree = proto_item_add_subtree(ti, ett_nv_header); ti= proto_tree_add_item(nv_header_tree, hf_nv_publisher, tvb, offset, (int)sizeof(guint8)*6, ENC_NA); NvPublisherFormater(tvb, offset, szText, nMax); proto_item_set_text(ti, "%s", szText); offset+=((int)sizeof(guint8)*6); proto_tree_add_item(nv_header_tree, hf_nv_count, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); nv_count = tvb_get_letohs(tvb, offset); offset+=(int)sizeof(guint16); proto_tree_add_item(nv_header_tree, hf_nv_cycleindex, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); offset = NvParserHDR_Len; for ( i=0; i < nv_count; i++ ) { guint16 var_length = tvb_get_letohs(tvb, offset+4); ti = proto_tree_add_item(nv_tree, hf_nv_variable, tvb, offset, ETYPE_88A4_NV_DATA_HEADER_Len+var_length, ENC_NA); NvVarHeaderFormater(tvb, offset, szText, nMax); proto_item_set_text(ti, "%s", szText); nv_var_tree = proto_item_add_subtree(ti, ett_nv_var); ti = proto_tree_add_item(nv_var_tree, hf_nv_varheader, tvb, offset, ETYPE_88A4_NV_DATA_HEADER_Len, ENC_NA); nv_varheader_tree = proto_item_add_subtree(ti, ett_nv_varheader); proto_tree_add_item(nv_varheader_tree, hf_nv_id, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); offset+=(int)sizeof(guint16); proto_tree_add_item(nv_varheader_tree, hf_nv_hash, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); offset+=(int)sizeof(guint16); proto_tree_add_item(nv_varheader_tree, hf_nv_length, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); offset+=(int)sizeof(guint16); proto_tree_add_item(nv_varheader_tree, hf_nv_quality, tvb, offset, (int)sizeof(guint16), ENC_LITTLE_ENDIAN); offset+=(int)sizeof(guint16); proto_tree_add_item(nv_var_tree, hf_nv_data, tvb, offset, var_length, ENC_NA); offset+=var_length; } } }
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_head *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 (&wai_reassembly_table, tvb, WAI_DATA_OFFSET, pinfo, packet_num, NULL, 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_dtp_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree, proto_item *ti, guint8 type) { switch (type) { case TYPE_DOMAIN: if (length > 0) { proto_item_set_text(ti, "Domain: %s", tvb_format_text(tvb, offset, length - 1)); proto_tree_add_text(tree, tvb, offset, length, "Domain: %s", tvb_format_text(tvb, offset, length - 1)); } else { proto_item_set_text(ti, "Domain: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Domain: Bad length %u", length); } break; case TYPE_STATUS: if (length > 0) { proto_item_set_text(ti, "Status: 0x%02x", tvb_get_guint8(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 1, "Status: 0x%02x", tvb_get_guint8(tvb, offset)); } else { proto_item_set_text(ti, "Status: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Status: Bad length %u", length); } break; case TYPE_DTPTYPE: if (length > 0) { proto_item_set_text(ti, "Dtptype: 0x%02x", tvb_get_guint8(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 1, "Dtptype: 0x%02x", tvb_get_guint8(tvb, offset)); } else { proto_item_set_text(ti, "Dtptype: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Dtptype: Bad length %u", length); } break; case TYPE_NEIGHBOR: if (length == 6) { proto_item_set_text(ti, "Neighbor: %s", tvb_ether_to_str(tvb, offset)); /* XXX - resolve? */ proto_tree_add_item(tree, hf_dtp_some_mac, tvb, offset, length, ENC_NA); } else { proto_item_set_text(ti, "Neighbor: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Neighbor: Bad length %u", length); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Data"); break; } }
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); } 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 "); 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"); 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 int dissect_bencoded_dict_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset ) { proto_item *ti; proto_tree *sub_tree; gboolean tohex; const char *key; const char *val; guint orig_offset = offset; key = NULL; val = NULL; ti = proto_tree_add_item( tree, hf_bencoded_dict_entry, tvb, offset, 0, ENC_NA ); sub_tree = proto_item_add_subtree( ti, ett_bencoded_dict_entry); /* dissect the key, it must be a string */ offset = dissect_bencoded_string( tvb, pinfo, sub_tree, offset, &key, FALSE, "Key" ); /* If it is a dict, then just do recursion */ switch( tvb_get_guint8(tvb,offset) ) { case 'd': offset = dissect_bencoded_dict( tvb, pinfo, sub_tree, offset, "Value" ); val = dict_str; break; case 'l': if( strcmp(key,"e")==0 ) offset = dissect_bt_dht_error( tvb, pinfo, sub_tree, offset, &val, "Value" ); else if( strcmp(key,"values")==0 ) offset = dissect_bt_dht_values( tvb, pinfo, sub_tree, offset, &val, "Value" ); /* other unfamiliar lists */ else { offset = dissect_bencoded_list( tvb, pinfo, sub_tree, offset, "Value" ); val = list_str; } break; case 'i': offset = dissect_bencoded_int( tvb, pinfo, sub_tree, offset, &val, "Value" ); break; /* it's a string */ default: /* special process */ if( strcmp(key,"nodes")==0 ) { offset = dissect_bt_dht_nodes( tvb, pinfo, sub_tree, offset, &val, "Value" ); } else if( strcmp(key,"ip")==0 ) { /* * Not found in BEP 0005 but explained by * http://www.rasterbar.com/products/libtorrent/dht_sec.html */ int len, old_offset; old_offset = offset; len = bencoded_string_length(tvb, &offset); if(len == 4) { proto_tree_add_item(sub_tree, hf_ip, tvb, offset, len, ENC_BIG_ENDIAN); val = tvb_ip_to_str(tvb, offset); offset += len; } else { offset = dissect_bencoded_string( tvb, pinfo, sub_tree, old_offset, &val, TRUE, "Value" ); } } else { /* some need to return hex string */ tohex = strcmp(key,"id")==0 || strcmp(key,"target")==0 || strcmp(key,"info_hash")==0 || strcmp(key,"t")==0 || strcmp(key,"v")==0 || strcmp(key,"token")==0; offset = dissect_bencoded_string( tvb, pinfo, sub_tree, offset, &val, tohex, "Value" ); } } if( strlen(key)==1 ) key = val_to_str_const( key[0], short_key_name_value_string, key ); if( strlen(val)==1 ) val = val_to_str_const( val[0], short_val_name_value_string, val ); proto_item_set_text( ti, "%s: %s", key, val ); proto_item_set_len( ti, offset-orig_offset ); if( strcmp(key,"message_type")==0 || strcmp(key,"request_type")==0 ) col_append_fstr(pinfo->cinfo, COL_INFO, "%s=%s ", key, val); return offset; }
static void dissect_vlan_info_tlv(tvbuff_t *tvb, int offset, int length, proto_tree *tree, proto_item *ti, guint8 type) { switch (type) { case SR_RING_NUM: if (length == 2) { proto_item_set_text(ti, "Source-Routing Ring Number: 0x%04x", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Source-Routing Ring Number: 0x%04x", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Source-Routing Ring Number: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Source-Routing Ring Number: Bad length %u", length); } break; case SR_BRIDGE_NUM: if (length == 2) { proto_item_set_text(ti, "Source-Routing Bridge Number: 0x%04x", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Source-Routing Bridge Number: 0x%04x", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Source-Routing Bridge Number: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Source-Routing Bridge Number: Bad length %u", length); } break; case STP_TYPE: if (length == 2) { proto_item_set_text(ti, "Spanning-Tree Protocol Type: %s", val_to_str(tvb_get_ntohs(tvb, offset), stp_type_vals, "Unknown (0x%04x)")); proto_tree_add_text(tree, tvb, offset, 2, "Spanning-Tree Protocol Type: %s", val_to_str(tvb_get_ntohs(tvb, offset), stp_type_vals, "Unknown (0x%04x)")); } else { proto_item_set_text(ti, "Spanning-Tree Protocol Type: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Spanning-Tree Protocol Type: Bad length %u", length); } break; case PARENT_VLAN: if (length == 2) { proto_item_set_text(ti, "Parent VLAN: 0x%04x", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Parent VLAN: 0x%04x", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Parent VLAN: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Parent VLAN: Bad length %u", length); } break; case TR_BRIDGED_VLANS: if (length == 2) { proto_item_set_text(ti, "Translationally Bridged VLANs: 0x%04x", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Translationally Bridged VLANs: 0x%04x", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Translationally Bridged VLANs: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Translationally Bridged VLANs: Bad length %u", length); } break; case PRUNING: if (length == 2) { proto_item_set_text(ti, "Pruning: %s", val_to_str(tvb_get_ntohs(tvb, offset), pruning_vals, "Unknown (0x%04x)")); proto_tree_add_text(tree, tvb, offset, 2, "Pruning: %s", val_to_str(tvb_get_ntohs(tvb, offset), pruning_vals, "Unknown (0x%04x)")); } else { proto_item_set_text(ti, "Pruning: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Pruning: Bad length %u", length); } break; case BRIDGE_TYPE: if (length == 2) { proto_item_set_text(ti, "Bridge Type: %s", val_to_str(tvb_get_ntohs(tvb, offset), bridge_type_vals, "Unknown (0x%04x)")); proto_tree_add_text(tree, tvb, offset, 2, "Bridge Type: %s", val_to_str(tvb_get_ntohs(tvb, offset), bridge_type_vals, "Unknown (0x%04x)")); } else { proto_item_set_text(ti, "Bridge Type: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Bridge Type: Bad length %u", length); } break; case MAX_ARE_HOP_CNT: if (length == 2) { proto_item_set_text(ti, "Max ARE Hop Count: %u", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Max ARE Hop Count: %u", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Max ARE Hop Count: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Max ARE Hop Count: Bad length %u", length); } break; case MAX_STE_HOP_CNT: if (length == 2) { proto_item_set_text(ti, "Max STE Hop Count: %u", tvb_get_ntohs(tvb, offset)); proto_tree_add_text(tree, tvb, offset, 2, "Max STE Hop Count: %u", tvb_get_ntohs(tvb, offset)); } else { proto_item_set_text(ti, "Max STE Hop Count: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Max STE Hop Count: Bad length %u", length); } break; case BACKUP_CRF_MODE: if (length == 2) { proto_item_set_text(ti, "Backup CRF Mode: %s", val_to_str(tvb_get_ntohs(tvb, offset), backup_crf_mode_vals, "Unknown (0x%04x)")); proto_tree_add_text(tree, tvb, offset, 2, "Backup CRF Mode: %s", val_to_str(tvb_get_ntohs(tvb, offset), backup_crf_mode_vals, "Unknown (0x%04x)")); } else { proto_item_set_text(ti, "Backup CRF Mode: Bad length %u", length); proto_tree_add_text(tree, tvb, offset, length, "Backup CRF Mode: Bad length %u", length); } break; default: proto_tree_add_text(tree, tvb, offset, length, "Data"); break; } }
static int dissect_mrdisc_mra(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset) { guint16 num; /* Advertising Interval */ proto_tree_add_item(parent_tree, hf_advint, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* checksum */ igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0); offset += 2; /* skip unused bytes */ offset += 2; /* number of options */ num = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(parent_tree, hf_numopts, tvb, offset, 2, num); offset += 2; /* process any options */ while (num--) { proto_tree *tree; proto_item *item; guint8 type,len; int old_offset = offset; item = proto_tree_add_item(parent_tree, hf_options, tvb, offset, -1, ENC_NA); tree = proto_item_add_subtree(item, ett_options); type = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_option, tvb, offset, 1, type); offset += 1; len = tvb_get_guint8(tvb, offset); proto_tree_add_uint(tree, hf_option_len, tvb, offset, 1, len); offset += 1; switch (type) { case MRDISC_QI: proto_item_set_text(item,"Option: %s == %d", val_to_str(type, mrdisc_options, "unknown %x"), tvb_get_ntohs(tvb, offset)); proto_tree_add_item(tree, hf_qi, tvb, offset, len, ENC_BIG_ENDIAN); offset += len; break; case MRDISC_RV: proto_item_set_text(item,"Option: %s == %d", val_to_str(type, mrdisc_options, "unknown %x"), tvb_get_ntohs(tvb, offset)); proto_tree_add_item(tree, hf_rv, tvb, offset, len, ENC_BIG_ENDIAN); offset += len; break; default: proto_item_set_text(item,"Option: unknown"); proto_tree_add_item(tree, hf_option_bytes, tvb, offset, len, ENC_NA); offset += len; } proto_item_set_len(item, offset-old_offset); } return offset; }
/* Code to actually dissect the packets */ static int dissect_mbtcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ mbtcp_hdr mh; proto_item *mi, *mf; proto_tree *mbtcp_tree, *modbus_tree, *group_tree; int offset, group_offset, packet_type; guint i; gint packet_len, payload_start, payload_len; const char *func_string = ""; const char *pkt_type_str = ""; const char *err_str = ""; guint32 byte_cnt, group_byte_cnt, group_word_cnt; guint32 packet_num; /* num to uniquely identify different mbtcp * packets in one packet */ guint8 exception_code; gboolean exception_returned; guint8 fc; mh.transaction_id = tvb_get_ntohs(tvb, 0); mh.protocol_id = tvb_get_ntohs(tvb, 2); mh.len = tvb_get_ntohs(tvb, 4); mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, 6); mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, 7); /* check that it actually looks like Modbus/TCP */ /* protocol id == 0 */ if( mh.protocol_id != 0 ){ return 0; } /* length is at least 2 (unit_id + function_code) */ if( mh.len < 2 ){ return 0; } /* function code is in the set 1-24, 40, 125-127. * Note that function code is only 7 bits. */ fc=mh.mdbs_hdr.function_code&0x7f; if(!match_strval(fc, function_code_vals)) return 0; /* Make entries in Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Modbus/TCP"); col_clear(pinfo->cinfo, COL_INFO); /* Make entries in Info column on summary display */ offset = 0; if ( mh.mdbs_hdr.function_code & 0x80 ) { exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr)); mh.mdbs_hdr.function_code ^= 0x80; exception_returned = TRUE; } else { exception_code = 0; exception_returned = FALSE; } func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals, "Unknown function (%u)"); if (check_col(pinfo->cinfo, COL_INFO)) { packet_type = classify_packet(pinfo); switch ( packet_type ) { case QUERY_PACKET : pkt_type_str="query"; break; case RESPONSE_PACKET : pkt_type_str="response"; break; case CANNOT_CLASSIFY : err_str="Unable to classify as query or response."; pkt_type_str="unknown"; break; default : break; } if ( exception_returned ) err_str="Exception returned "; col_add_fstr(pinfo->cinfo, COL_INFO, "%8s [%2u pkt(s)]: trans: %5u; unit: %3u, func: %3u: %s. %s", pkt_type_str, 1, mh.transaction_id, (unsigned char) mh.mdbs_hdr.unit_id, (unsigned char) mh.mdbs_hdr.function_code, func_string, err_str); } /* build up protocol tree and iterate over multiple packets */ packet_num = 0; while (1) { packet_type = classify_packet(pinfo); packet_len = sizeof(mbtcp_hdr) - sizeof(modbus_hdr) + mh.len; /* if a tree exists, perform operations to add fields to it */ if (tree) { mi = proto_tree_add_protocol_format(tree, proto_mbtcp, tvb, offset, packet_len, "Modbus/TCP"); mbtcp_tree = proto_item_add_subtree(mi, ett_mbtcp); /* Add items to protocol tree specific to Modbus/TCP */ proto_tree_add_uint(mbtcp_tree, hf_mbtcp_transid, tvb, offset, 2, mh.transaction_id); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_protid, tvb, offset + 2, 2, mh.protocol_id); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_len, tvb, offset + 4, 2, mh.len); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_unitid, tvb, offset + 6, 1, mh.mdbs_hdr.unit_id); /* Add items to protocol tree specific to Modbus generic */ mf = proto_tree_add_text(mbtcp_tree, tvb, offset + 7, mh.len - 1, "Modbus"); modbus_tree = proto_item_add_subtree(mf, ett_modbus_hdr); mi = proto_tree_add_uint(modbus_tree, hf_mbtcp_functioncode, tvb, offset + 7, 1, mh.mdbs_hdr.function_code); /** detail payload as a function of exception/function code */ func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals, "Unknown function"); payload_start = offset + 8; payload_len = mh.len - sizeof(modbus_hdr); if (exception_returned) { proto_item_set_text(mi, "function %u: %s. Exception: %s", mh.mdbs_hdr.function_code, func_string, val_to_str(exception_code, exception_code_vals, "Unknown exception code (%u)")); proto_tree_add_uint(modbus_tree, hf_modbus_exceptioncode, tvb, payload_start, 1, exception_code); } else { proto_item_set_text(mi, "function %u: %s", mh.mdbs_hdr.function_code, func_string); switch (mh.mdbs_hdr.function_code) { case READ_COILS: case READ_INPUT_DISCRETES: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case READ_MULT_REGS: case READ_INPUT_REGS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case WRITE_COIL: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data"); proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data"); proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding"); } break; case WRITE_SINGLE_REG: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data"); } break; case READ_EXCEPT_STAT: if (packet_type == RESPONSE_PACKET) proto_tree_add_text(modbus_tree, tvb, payload_start, 1, "Data"); break; case FORCE_MULT_COILS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); } break; case WRITE_MULT_REGS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); } break; case READ_GENL_REF: if (packet_type == QUERY_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; for (i = 0; i < byte_cnt / 7; i++) { mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 7, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE); proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE); proto_tree_add_item(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, FALSE); group_offset += 7; } } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; i = 0; while (byte_cnt > 0) { group_byte_cnt = (guint32)tvb_get_guint8(tvb, group_offset); mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt + 1, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_uint(group_tree, hf_modbus_bytecnt, tvb, group_offset, 1, group_byte_cnt); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset + 1, 1, FALSE); proto_tree_add_text(group_tree, tvb, group_offset + 2, group_byte_cnt - 1, "Data"); group_offset += (group_byte_cnt + 1); byte_cnt -= (group_byte_cnt + 1); i++; } } break; case WRITE_GENL_REF: if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; i = 0; while (byte_cnt > 0) { group_word_cnt = tvb_get_ntohs(tvb, group_offset + 5); group_byte_cnt = (2 * group_word_cnt) + 7; mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE); proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE); proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, group_word_cnt); proto_tree_add_text(group_tree, tvb, group_offset + 7, group_byte_cnt - 7, "Data"); group_offset += group_byte_cnt; byte_cnt -= group_byte_cnt; i++; } } break; case MASK_WRITE_REG: if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_andmask, tvb, payload_start + 2, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_ormask, tvb, payload_start + 4, 2, FALSE); } break; case READ_WRITE_REG: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_readref, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_readwordcnt, tvb, payload_start + 2, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_writeref, tvb, payload_start + 4, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_writewordcnt, tvb, payload_start + 6, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 8); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 8, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 9, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case READ_FIFO_QUEUE: if (packet_type == QUERY_PACKET) proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_ntohs(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_lbytecnt, tvb, payload_start, 2, byte_cnt); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 4, byte_cnt - 2, "Data"); } break; case DIAGNOSTICS: case PROGRAM_484: case POLL_484: case GET_COMM_EVENT_CTRS: case GET_COMM_EVENT_LOG: case PROGRAM_584_984: case POLL_584_984: case REPORT_SLAVE_ID: case PROGRAM_884_U84: case RESET_COMM_LINK: case PROGRAM_CONCEPT: case FIRMWARE_REPLACE: case PROGRAM_584_984_2: case REPORT_LOCAL_ADDR_MB: /* these function codes are not part of the Modbus/TCP specification */ default: if (payload_len > 0) proto_tree_add_text(modbus_tree, tvb, payload_start, payload_len, "Data"); break; } } } /* move onto next packet (if there) */ offset += packet_len; packet_num++; if (tvb_reported_length_remaining(tvb, offset) > 0) { /* load header structure for next packet */ mh.transaction_id = tvb_get_ntohs(tvb, offset+0); mh.protocol_id = tvb_get_ntohs(tvb, offset+2); mh.len = tvb_get_ntohs(tvb, offset+4); mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, offset+6); mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, offset+7); if ( mh.mdbs_hdr.function_code & 0x80 ) { exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr)); mh.mdbs_hdr.function_code ^= 0x80; exception_returned = TRUE; } else exception_returned = FALSE; } else break; } return tvb_length(tvb); }