wireshark/epan/dissectors/packet-grebonding.c

587 lines
26 KiB
C

/* packet-grebonding.c
* Routines for Huawei's GRE bonding control (RFC8157) dissection
* Thomas Vogt
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/capture_dissectors.h>
#include <epan/expert.h>
#include <epan/to_str.h>
void proto_reg_handoff_greb(void);
void proto_register_greb(void);
static int proto_greb = -1;
static int hf_greb_message_type = -1;
static int hf_greb_tunnel_type = -1;
static int hf_greb_attr = -1;
static int hf_greb_attr_type = -1;
static int hf_greb_attr_length = -1;
static int hf_greb_attr_val_uint64 = -1;
static int hf_greb_attr_val_none = -1;
static int hf_greb_attr_val_ipv6 = -1;
static int hf_greb_attr_val_ipv4 = -1;
static int hf_greb_attr_val_time = -1;
static int hf_greb_attr_val_string = -1;
static int hf_greb_attr_DSL_prot = -1;
static int hf_greb_attr_dt_bras_name = -1;
static int hf_greb_attr_filter_commit = -1;
static int hf_greb_attr_filter_ack = -1;
static int hf_greb_attr_filter_packetsum = -1;
static int hf_greb_attr_filter_packetid = -1;
static int hf_greb_attr_filter_item_type = -1;
static int hf_greb_attr_filter_item_length = -1;
static int hf_greb_attr_filter_item_enabled = -1;
static int hf_greb_attr_filter_item_desc_length = -1;
static int hf_greb_attr_filter_item_desc_val = -1;
static int hf_greb_attr_filter_item_val = -1;
static int hf_greb_attr_error = -1;
/* Initialize the subtree pointers */
static gint ett_grebonding = -1;
static gint ett_grebonding_attrb = -1;
static gint ett_grebonding_filter_list = -1;
static gint ett_grebonding_filter_item = -1;
static gint ett_grebonding_ipv6_prefix = -1;
static gint *ett[] = {
&ett_grebonding,
&ett_grebonding_attrb,
&ett_grebonding_filter_list,
&ett_grebonding_filter_item,
&ett_grebonding_ipv6_prefix
};
static const value_string greb_message_types[] = {
#define GREB_TUNNEL_SETUP_REQ 1
{GREB_TUNNEL_SETUP_REQ, "Tunnel setup request"},
#define GREB_TUNNEL_SETUP_ACK 2
{GREB_TUNNEL_SETUP_ACK, "Tunnel setup accept"},
#define GREB_TUNNEL_SETUP_DENY 3
{GREB_TUNNEL_SETUP_DENY, "Tunnel setup deny"},
#define GREB_HELLO 4
{GREB_HELLO, "Hello"},
#define GREB_TUNNEL_TEAR_DOWN 5
{GREB_TUNNEL_TEAR_DOWN, "Tunnel tear down"},
#define GREB_NOTIFY 6
{GREB_NOTIFY, "Notify"},
#define GREB_LINK_DETECTION 10
{GREB_LINK_DETECTION, "Link Detection (Telekom specific)"},
{0, NULL}
};
static const value_string greb_tunnel_types[] = {
#define GREB_TUNNEL_LTE 0b0000
{GREB_TUNNEL_LTE, "LTE-GRE tunnel (Telekom specific)"},
#define GREB_TUNNEL_FIRST 0b0001
{GREB_TUNNEL_FIRST, "first tunnel (most likely the DSL GRE tunnel)"},
#define GREB_TUNNEL_SECOND 0b0010
{GREB_TUNNEL_SECOND, "second tunnel (most likely the LTE GRE tunnel)" },
#define GREB_TUNNEL_DSL 0b1000
{GREB_TUNNEL_DSL, "DSL Tunnel (Telekom specific)" },
{0, NULL}
};
static const value_string greb_error_codes[] = {
#define GREB_ERROR_HAAP_UNREACHABLE_LTE 1
{GREB_ERROR_HAAP_UNREACHABLE_LTE, "HAAP not reachable over LTE"},
#define GREB_ERROR_HAAP_UNREACHABLE_DSL 2
{GREB_ERROR_HAAP_UNREACHABLE_DSL, "HAAP not reachable via DSL"},
#define GREB_ERROR_LTE_TUNNEL_FAILED 3
{GREB_ERROR_LTE_TUNNEL_FAILED, "LTE tunnel failed"},
#define GREB_ERROR_DSL_TUNNEL_FAILED 4
{GREB_ERROR_DSL_TUNNEL_FAILED, "DSL tunnel failed"},
#define GREB_ERROR_DSL_UID_NOT_ALLOWED 5
{GREB_ERROR_DSL_UID_NOT_ALLOWED, "DSL UID not allowed"},
#define GREB_ERROR_UID_NOT_ALLOWED 6
{GREB_ERROR_UID_NOT_ALLOWED, "UID not allowed"},
#define GREB_ERROR_UID_NOT_MATCHING 7
{GREB_ERROR_UID_NOT_MATCHING, "LTE and DSL User IDs do not match"},
#define GREB_ERROR_SECOND_SESSION_WITH_UID 8
{GREB_ERROR_SECOND_SESSION_WITH_UID, "Session with the same User ID already exists"},
#define GREB_ERROR_CIN_NOT_PERMITTED 9
{GREB_ERROR_CIN_NOT_PERMITTED, "Denied: CIN not permitted"},
#define GREB_ERROR_MAINTENANCE 10
{GREB_ERROR_MAINTENANCE, "Terminated for maintenance"},
#define GREB_ERROR_BACKEND_COMMUNICATION_FAILURE_LTE 11
{GREB_ERROR_BACKEND_COMMUNICATION_FAILURE_LTE, "HAAP Backend failure on LTE tunnel establishment"},
#define GREB_ERROR_BACKEND_COMMUNICATION_FAILURE_DSL 12
{GREB_ERROR_BACKEND_COMMUNICATION_FAILURE_DSL, "HAAP Backend failure on DSL tunnel establishment"},
#define GREB_ERROR_DT_HAAP_UNREACHABLE_DSL 401
{GREB_ERROR_DT_HAAP_UNREACHABLE_DSL, "DSL GRE tunnel to the HAAP failed (Telekom specific)"},
#define GREB_ERROR_DT_HAAP_UNREACHABLE_LTE 402
{GREB_ERROR_DT_HAAP_UNREACHABLE_LTE, "LTE GRE tunnel to the HAAP failed (Telekom specific)"},
#define GREB_ERROR_DT_UID_NOT_MATCHING 403
{GREB_ERROR_DT_UID_NOT_MATCHING, "Mismatch of LTE and DSL User IDs (Telekom specific)"},
#define GREB_ERROR_DT_SECOND_SESSION_WITH_UID 404
{GREB_ERROR_DT_SECOND_SESSION_WITH_UID, "Session with the same User ID already exists (Telekom specific)"},
#define GREB_ERROR_DT_CIN_NOT_PERMITTED 405
{GREB_ERROR_DT_CIN_NOT_PERMITTED, "Client uses a not permitted CIN (Telekom specific)"},
#define GREB_ERROR_DT_DSL_TUNNEL_FAILED 406
{GREB_ERROR_DT_DSL_TUNNEL_FAILED, "Communication error during the DSL Tunnel setup (Telekom specific)"},
#define GREB_ERROR_DT_LTE_TUNNEL_FAILED 407
{GREB_ERROR_DT_LTE_TUNNEL_FAILED, "Communication error during the LTE Tunnel setup (Telekom specific)"},
#define GREB_ERROR_DT_MAINTENANCE 501
{GREB_ERROR_DT_MAINTENANCE, "Terminated for maintenance (Telekom specific)"},
#define GREB_ERROR_DT_LTE_PARAM_UPDATE 502
{GREB_ERROR_DT_LTE_PARAM_UPDATE, "LTE terminated to update parameters (Telekom specific)"},
#define GREB_ERROR_DT_DSL_PARAM_UPDATE 503
{GREB_ERROR_DT_DSL_PARAM_UPDATE, "DSL terminated to update parameters (Telekom specific)"},
{0,NULL}
};
static const value_string greb_attribute_types[] = {
#define GREB_ATTRB_H_IP4_ADDR 1
{GREB_ATTRB_H_IP4_ADDR, "H IPv4 address"},
#define GREB_ATTRB_H_IP6_ADDR 2
{GREB_ATTRB_H_IP6_ADDR, "H IPv6 address"},
#define GREB_ATTRB_CIN 3
{GREB_ATTRB_CIN, "CIN (Client ID)"},
#define GREB_ATTRB_SESSIONID 4
{GREB_ATTRB_SESSIONID, "Session ID"},
#define GREB_ATTRB_TIME 5
{GREB_ATTRB_TIME, "Time"},
#define GREB_ATTRB_BYPASS_RATE 6
{GREB_ATTRB_BYPASS_RATE, "Bypass rate"},
#define GREB_ATTRB_DOWNSTREAM_RATE 7
{GREB_ATTRB_DOWNSTREAM_RATE, "Downstream rate"},
#define GREB_ATTRB_FILTER_LIST 8
{GREB_ATTRB_FILTER_LIST, "Filter list"},
#define GREB_ATTRB_RTT_THRESHOLD 9
{GREB_ATTRB_RTT_THRESHOLD, "RTT threshold"},
#define GREB_ATTRB_BYPASS_INTERVAL 10
{GREB_ATTRB_BYPASS_INTERVAL, "Bypass interval"},
#define GREB_ATTRB_ONLY_FIRST_TUNNEL 11
{GREB_ATTRB_ONLY_FIRST_TUNNEL, "only first tunnel (DSL)"},
#define GREB_ATTRB_OVERFLOW_TO_SECOND 12
{GREB_ATTRB_OVERFLOW_TO_SECOND, "overflow to second tunnel (LTE)"},
#define GREB_ATTRB_IPV6_PREFIX 13
{GREB_ATTRB_IPV6_PREFIX, "IPv6 prefix assigned by HAAP"},
#define GREB_ATTRB_ACTIVE_HELLO_INTERVAL 14
{GREB_ATTRB_ACTIVE_HELLO_INTERVAL, "Active hello interval"},
#define GREB_ATTRB_HELLO_RETRYS 15
{GREB_ATTRB_HELLO_RETRYS, "Hello retries"},
#define GREB_ATTRB_IDLE_TIMEOUT 16
{GREB_ATTRB_IDLE_TIMEOUT, "Idle timeout"},
#define GREB_ATTRB_ERROR 17
{GREB_ATTRB_ERROR, "Error"},
#define GREB_ATTRB_DSL_FAIL 18
{GREB_ATTRB_DSL_FAIL, "DSL fail"},
#define GREB_ATTRB_LTE_FAIL 19
{GREB_ATTRB_LTE_FAIL, "LTE fail"},
#define GREB_ATTRB_BONDING_KEY 20
{GREB_ATTRB_BONDING_KEY, "Bonding key"},
#define GREB_ATTRB_IPV6_PREFIX2 21
{GREB_ATTRB_IPV6_PREFIX2, "IPv6 prefix assigned to host"},
#define GREB_ATTRB_CONFIGURED_UPSTREAM 22
{GREB_ATTRB_CONFIGURED_UPSTREAM, "Configured upstream"},
#define GREB_ATTRB_CONFIGURED_DOWNSTREAM 23
{GREB_ATTRB_CONFIGURED_DOWNSTREAM, "Configured downstream"},
#define GREB_ATTRB_RTT_VIOLATION 24
{GREB_ATTRB_RTT_VIOLATION, "RTT violation"},
#define GREB_ATTRB_RTT_COMPLIANCE 25
{GREB_ATTRB_RTT_COMPLIANCE, "RTT compliance"},
#define GREB_ATTRB_DIAG_START_BONDING 26
{GREB_ATTRB_DIAG_START_BONDING, "Diagnostic start bonding"},
#define GREB_ATTRB_DIAG_START_DSL 27
{GREB_ATTRB_DIAG_START_DSL, "Diagnostic start DSL"},
#define GREB_ATTRB_DIAG_END 29
{GREB_ATTRB_DIAG_END, "Diagnostic End"},
#define GREB_ATTRB_FILTER_LIST_ACK 30
{GREB_ATTRB_FILTER_LIST_ACK, "Filter list ACK"},
#define GREB_ATTRB_IDLE_HELLO_INTERVAL 31
{GREB_ATTRB_IDLE_HELLO_INTERVAL, "Idle hello interval"},
#define GREB_ATTRB_NO_TRAFFIC_INTERVAL 32
{GREB_ATTRB_NO_TRAFFIC_INTERVAL, "No traffic interval"},
#define GREB_ATTRB_ACTIVE_HELLO_STATE 33
{GREB_ATTRB_ACTIVE_HELLO_STATE, "Active hello state"},
#define GREB_ATTRB_IDLE_HELLO_STATE 34
{GREB_ATTRB_IDLE_HELLO_STATE, "Idle hello state"},
#define GREB_ATTRB_TUNNEL_VERIFICATION 35
{GREB_ATTRB_TUNNEL_VERIFICATION, "Tunnel verification"},
#define GREB_ATTRB_DT_DSL_PROT 53
{GREB_ATTRB_DT_DSL_PROT, "DSL protocol / link type (Telekom specific)"},
#define GREB_ATTRB_DT_BRAS_NAME 54
{GREB_ATTRB_DT_BRAS_NAME, "Broadband Remote Access Server name (Telekom specific)"},
#define GREB_ATTRB_DT_DOWN_REORDER_TIME 56
{GREB_ATTRB_DT_DOWN_REORDER_TIME, "Max. downstream reordering buffer time (Telekom specific)"},
#define GREB_ATTRB_DT_COM_UP_BURST_TIME 57
{GREB_ATTRB_DT_COM_UP_BURST_TIME, "Committed upstream burst time (Telekom specific)"},
#define GREB_ATTRB_DT_UPSTREAM_RATE 59
{GREB_ATTRB_DT_UPSTREAM_RATE, "DSL synchronization Rate upstream (Telekom specific)"},
{255, "FIN"},
{0, NULL}
};
static const value_string greb_DT_DSL_prots[] = {
#define DT_UNDEF 0
{DT_UNDEF, "Undefined"},
#define DT_ADSL_B 1
{DT_ADSL_B, "ADSL/ADSL2/ADSL2+ Annex B"},
#define DT_ADSL_J 2
{DT_ADSL_J, "ADSL2+ Annex J"},
#define DT_VDSL 3
{DT_VDSL, "VDSL2"},
#define DT_VDSL_VEC 4
{DT_VDSL_VEC, "VDSL2 Vectoring"},
{0, NULL}
};
static const value_string greb_filter_types[] = {
#define GREB_ATTRB_FILTER_FQDN 1
{GREB_ATTRB_FILTER_FQDN, "FQDN"},
#define GREB_ATTRB_FILTER_DSCP 2
{GREB_ATTRB_FILTER_DSCP, "DSCP"},
#define GREB_ATTRB_FILTER_DPORT 3
{GREB_ATTRB_FILTER_DPORT, "Destination Port"},
#define GREB_ATTRB_FILTER_DIP 4
{GREB_ATTRB_FILTER_DIP, "Destination IP"},
#define GREB_ATTRB_FILTER_DIPPORT 5
{GREB_ATTRB_FILTER_DIPPORT, "Destination IP&Port"},
#define GREB_ATTRB_FILTER_SPORT 6
{GREB_ATTRB_FILTER_SPORT, "Source Port"},
#define GREB_ATTRB_FILTER_SIP 7
{GREB_ATTRB_FILTER_SIP, "Source IP"},
#define GREB_ATTRB_FILTER_SIPPORT 8
{GREB_ATTRB_FILTER_SIPPORT, "Source IP&Port"},
#define GREB_ATTRB_FILTER_SMAC 9
{GREB_ATTRB_FILTER_SMAC, "Source Mac"},
#define GREB_ATTRB_FILTER_PROTO 10
{GREB_ATTRB_FILTER_PROTO, "Protocol"},
#define GREB_ATTRB_FILTER_SIPR 11
{GREB_ATTRB_FILTER_SIPR, "Source IP Range"},
#define GREB_ATTRB_FILTER_DIPR 12
{GREB_ATTRB_FILTER_DIPR, "Destination IP Range"},
#define GREB_ATTRB_FILTER_SIPRPORT 13
{GREB_ATTRB_FILTER_SIPRPORT, "Source IP Range&Port"},
#define GREB_ATTRB_FILTER_DIPRPORT 14
{GREB_ATTRB_FILTER_DIPRPORT, "Destination IP Range&Port"},
#define GREB_ATTRB_DT_COMBO 15
{GREB_ATTRB_DT_COMBO, "Combination (Telekom specific)"},
{0, NULL}
};
static const value_string greb_filter_ack_codes[] = {
#define GREB_ATTRB_FILTER_ACK 0
{GREB_ATTRB_FILTER_ACK, "Filter list acknowledged"},
#define GREB_ATTRB_FILTER_NACK_NO_OLD 1
{GREB_ATTRB_FILTER_NACK_NO_OLD, "Filter list not acknowledged. No previous filter list to use."},
#define GREB_ATTRB_FILTER_NACK_OLD_USED 2
{GREB_ATTRB_FILTER_NACK_OLD_USED, "Filter list not acknowledged. Previous filter list will be used."},
{0, NULL}
};
static void
dissect_greb_h_gateway_ip_address(tvbuff_t *tvb, proto_tree *attrb_tree, guint offset, guint attrb_length)
{
if (attrb_length == 16)
proto_tree_add_item(attrb_tree, hf_greb_attr_val_ipv6, tvb, offset, attrb_length, ENC_NA);
else if (attrb_length == 4)
proto_tree_add_item(attrb_tree, hf_greb_attr_val_ipv4, tvb, offset, attrb_length, ENC_BIG_ENDIAN);
else
proto_tree_add_item(attrb_tree, hf_greb_attr_val_uint64, tvb, offset, attrb_length, ENC_BIG_ENDIAN);
}
static void
dissect_greb_filter_list_ack(tvbuff_t *tvb, proto_tree *attrb_tree, guint offset, guint attrb_length)
{
proto_item *it_filter;
proto_tree *filter_tree;
guint filter_commit_count = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN);
it_filter = proto_tree_add_none_format(attrb_tree, hf_greb_attr_val_none, tvb, offset, attrb_length,
"Filter list ACK - Commit %d", filter_commit_count);
filter_tree = proto_item_add_subtree(it_filter, ett_grebonding_filter_list);
proto_tree_add_item(filter_tree, hf_greb_attr_filter_commit, tvb, offset, attrb_length - 1, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_tree, hf_greb_attr_filter_ack, tvb, offset + attrb_length, 1, ENC_BIG_ENDIAN);
}
static void
dissect_greb_filter_list(tvbuff_t *tvb, proto_tree *attrb_tree, guint offset, guint attrb_length)
{
proto_item *it_filter;
proto_tree *filter_tree;
guint filter_commit_count = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN);
guint filter_packet_sum = tvb_get_guint16(tvb, offset + 4, ENC_BIG_ENDIAN);
guint filter_packet_id = tvb_get_guint16(tvb, offset + 6, ENC_BIG_ENDIAN);
it_filter = proto_tree_add_none_format(attrb_tree, hf_greb_attr_val_none, tvb, offset, attrb_length,
"Filter list - Commit %d, Packet %d/%d", filter_commit_count, filter_packet_id, filter_packet_sum);
filter_tree = proto_item_add_subtree(it_filter, ett_grebonding_filter_list);
proto_tree_add_item(filter_tree, hf_greb_attr_filter_commit, tvb, offset, 4, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_tree, hf_greb_attr_filter_packetid, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_tree, hf_greb_attr_filter_packetsum, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
offset += 8;
while (offset < attrb_length) {
proto_item *it_filter_item;
proto_tree *filter_item_tree;
guint filter_item_length = tvb_get_guint16(tvb, offset + 2, ENC_BIG_ENDIAN);
guint filter_item_desc_length = tvb_get_guint16(tvb, offset + 6, ENC_BIG_ENDIAN);
// bound lengths to not exceed packet
if (filter_item_length > (guint) tvb_reported_length_remaining(tvb, offset + 2))
filter_item_length = tvb_reported_length_remaining(tvb, offset + 2);
if (filter_item_desc_length > filter_item_length)
filter_item_length = filter_item_desc_length;
it_filter_item = proto_tree_add_none_format(filter_tree, hf_greb_attr_val_none, tvb, offset,
filter_item_length + 4, "Filter item - %s", tvb_get_string_enc(wmem_packet_scope(), tvb, offset + 8,
filter_item_desc_length, ENC_UTF_8));
filter_item_tree = proto_item_add_subtree(it_filter_item, ett_grebonding_filter_item);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_type, tvb, offset, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_length, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_enabled, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_desc_length, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_desc_val, tvb, offset + 8,
filter_item_desc_length, ENC_UTF_8 | ENC_NA);
proto_tree_add_item(filter_item_tree, hf_greb_attr_filter_item_val, tvb, offset + 8 + filter_item_desc_length,
filter_item_length - 4 - filter_item_desc_length, ENC_UTF_8 | ENC_NA);
offset += filter_item_length + 4;
}
}
static void
dissect_greb_ipv6_prefix(packet_info *pinfo, tvbuff_t *tvb, proto_tree *attrb_tree, guint offset, guint attrb_length)
{
proto_item *item_ipv6_prefix;
proto_tree *ipv6_prefix_tree;
guint addr_length = attrb_length - 1;
ipv6_prefix_tree = proto_tree_add_subtree_format(attrb_tree, tvb, offset, attrb_length,
ett_grebonding_ipv6_prefix, &item_ipv6_prefix, "IPv6 prefix - %s/%d",
tvb_ip6_to_str(pinfo->pool, tvb, offset), tvb_get_guint8(tvb, offset + addr_length));
proto_tree_add_item(ipv6_prefix_tree, hf_greb_attr_val_ipv6, tvb, offset, addr_length, ENC_NA);
proto_tree_add_item(ipv6_prefix_tree, hf_greb_attr_val_uint64, tvb, offset + addr_length, 1, ENC_BIG_ENDIAN);
}
static int
dissect_greb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *ti, *it_attrb;
proto_tree *greb_tree, *attrb_tree = NULL;
guint offset = 0;
guint message_type = tvb_get_guint8(tvb, offset) >> 4;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "GREbond");
ti = proto_tree_add_protocol_format(tree, proto_greb, tvb, offset, -1, "Huawei GRE bonding control message (%s)",
val_to_str(message_type, greb_message_types, "0x%01X (unknown)"));
col_add_str(pinfo->cinfo, COL_INFO, val_to_str(message_type, greb_message_types, "0x%02X (unknown)"));
greb_tree = proto_item_add_subtree(ti, ett_grebonding);
proto_tree_add_item(greb_tree, hf_greb_message_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(greb_tree, hf_greb_tunnel_type, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
// going through the attributes, off by one to assure length field exists
while (offset + 1 < tvb_captured_length(tvb)) {
guint attrb_type = tvb_get_guint8(tvb, offset);
guint attrb_length = tvb_get_guint16(tvb, offset + 1, ENC_BIG_ENDIAN);
it_attrb = proto_tree_add_none_format(greb_tree, hf_greb_attr, tvb, offset, attrb_length + 3, "Attribute - %s",
val_to_str(attrb_type, greb_attribute_types, "unknown (%d)"));
attrb_tree = proto_item_add_subtree(it_attrb, ett_grebonding_attrb);
proto_tree_add_item(attrb_tree, hf_greb_attr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(attrb_tree, hf_greb_attr_length, tvb, offset + 1, 2, ENC_BIG_ENDIAN);
offset += 3;
// bound attrb_length to not exced packet
if (attrb_length > (guint) tvb_reported_length_remaining(tvb, offset))
attrb_length = tvb_reported_length_remaining(tvb, offset);
if (attrb_length > 0) {
switch (attrb_type) {
case GREB_ATTRB_H_IP4_ADDR:
case GREB_ATTRB_H_IP6_ADDR:
dissect_greb_h_gateway_ip_address(tvb, attrb_tree, offset, attrb_length);
break;
case GREB_ATTRB_IPV6_PREFIX2:
case GREB_ATTRB_IPV6_PREFIX:
dissect_greb_ipv6_prefix(pinfo, tvb, attrb_tree, offset, attrb_length);
break;
case GREB_ATTRB_TIME:
proto_tree_add_item(attrb_tree, hf_greb_attr_val_time, tvb, offset, attrb_length,
ENC_TIME_TIMEVAL);
break;
case GREB_ATTRB_FILTER_LIST:
dissect_greb_filter_list(tvb, attrb_tree, offset, attrb_length);
break;
case GREB_ATTRB_FILTER_LIST_ACK:
dissect_greb_filter_list_ack(tvb, attrb_tree, offset, attrb_length);
break;
case GREB_ATTRB_CIN:
proto_tree_add_item(attrb_tree, hf_greb_attr_val_string, tvb, offset, attrb_length,
ENC_UTF_8 | ENC_NA);
break;
case GREB_ATTRB_DT_BRAS_NAME:
proto_tree_add_item(attrb_tree, hf_greb_attr_dt_bras_name, tvb, offset, attrb_length,
ENC_UTF_8 | ENC_NA);
break;
case GREB_ATTRB_ERROR:
proto_tree_add_item(attrb_tree, hf_greb_attr_error, tvb, offset, attrb_length, ENC_BIG_ENDIAN);
break;
case GREB_ATTRB_DT_DSL_PROT:
proto_tree_add_item(attrb_tree, hf_greb_attr_DSL_prot, tvb, offset, attrb_length, ENC_BIG_ENDIAN);
break;
default:
proto_tree_add_item(attrb_tree, hf_greb_attr_val_uint64, tvb, offset, attrb_length,
ENC_BIG_ENDIAN);
break;
}
offset += attrb_length;
}
}
return tvb_captured_length(tvb);
}
void
proto_register_greb(void)
{
static hf_register_info hf[] = {
{ &hf_greb_message_type,
{ "Message type", "grebonding.type", FT_UINT8, BASE_DEC, VALS(greb_message_types), 0xF0, "", HFILL }
},
{ &hf_greb_tunnel_type,
{ "Tunnel type", "grebonding.tunneltype", FT_UINT8, BASE_DEC, VALS(greb_tunnel_types), 0x0F, "", HFILL }
},
{ &hf_greb_attr,
{ "Attribute", "grebonding.attr", FT_NONE, BASE_NONE, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_length,
{ "Attribute length", "grebonding.attr.length", FT_UINT16, BASE_DEC, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_type,
{ "Attribute type", "grebonding.attr.type", FT_UINT8, BASE_DEC, VALS(greb_attribute_types), 0, "", HFILL }
},
{ &hf_greb_attr_val_uint64,
{ "Attribute value", "grebonding.attr.val.uint64",
FT_UINT64, BASE_DEC, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_val_time,
{ "Attribute value", "grebonding.attr.val.time",
FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_val_string,
{ "Attribute value", "grebonding.attr.val.string",
FT_STRING, BASE_NONE, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_val_none,
{ "Attribute value", "grebonding.attr.val",
FT_NONE, BASE_NONE, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_val_ipv6,
{ "Attribute value", "grebonding.attr.val.ipv6",
FT_IPv6, BASE_NONE, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_val_ipv4,
{ "Attribute value", "grebonding.attr.val.ipv4",
FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_commit,
{ "Commit", "grebonding.attr.val.filter.commit", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_ack,
{ "Ack", "grebonding.attr.val.filter.ack",
FT_UINT8, BASE_DEC, VALS(greb_filter_ack_codes), 0, NULL, HFILL }
},
{ &hf_greb_attr_DSL_prot,
{ "DSL Protocol", "grebonding.attr.val.dslproto",
FT_UINT8, BASE_DEC, VALS(greb_DT_DSL_prots), 0, NULL, HFILL }
},
{ &hf_greb_attr_dt_bras_name,
{ "Broadband Remote Access Server (BRAS) name", "grebonding.attr.val.bras_name",
FT_STRING, BASE_NONE, NULL, 0, "", HFILL }
},
{ &hf_greb_attr_filter_packetsum,
{ "Packet sum", "grebonding.attr.val.filter.packetsum", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_packetid,
{ "Packet ID", "grebonding.attr.val.filter.packetid", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_enabled,
{ "Enabled", "grebonding.attr.val.filter.item.enabled", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_length,
{ "Length (excl. type and length)", "grebonding.attr.val.filter.item.length",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_type,
{ "Type", "grebonding.attr.val.filter.item.type",
FT_UINT16, BASE_DEC, VALS(greb_filter_types), 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_desc_val,
{ "Description", "grebonding.attr.val.filter.item.desc", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_desc_length,
{ "Description length", "grebonding.attr.val.filter.item.desc.length",
FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_filter_item_val,
{ "Value", "grebonding.attr.val.filter.item.val", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }
},
{ &hf_greb_attr_error,
{ "Error message", "grebonding.attr.val.error",
FT_UINT32, BASE_DEC, VALS(greb_error_codes), 0, NULL, HFILL }
}
};
proto_greb = proto_register_protocol("Huawei GRE bonding", "GREbond", "grebonding");
proto_register_field_array(proto_greb, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_greb(void)
{
dissector_handle_t greb_handle;
greb_handle = create_dissector_handle(dissect_greb, proto_greb);
dissector_add_uint("gre.proto", 0x0101, greb_handle); // used in production at Deutsche Telekom
dissector_add_uint("gre.proto", 0xB7EA, greb_handle); // according to RFC
// TODO
// when capturing on the gre-interfaces itself, "Linux cooked" interfaces
//dissector_add_uint("sll.ltype", 0x0101, greb_handle);
//dissector_add_uint("sll.ltype", 0xB7EA, greb_handle);
//dissector_add_uint("sll.gretype", 0x0101, greb_handle);
//dissector_add_uint("sll.gretype", 0xB7EA, greb_handle);
}