summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-grebonding.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-grebonding.c')
-rw-r--r--epan/dissectors/packet-grebonding.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/epan/dissectors/packet-grebonding.c b/epan/dissectors/packet-grebonding.c
new file mode 100644
index 00000000..4f3da8ce
--- /dev/null
+++ b/epan/dissectors/packet-grebonding.c
@@ -0,0 +1,587 @@
+/* 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 dissector_handle_t greb_handle;
+
+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));
+
+ greb_handle = register_dissector("grebonding", dissect_greb, proto_greb);
+}
+
+void
+proto_reg_handoff_greb(void)
+{
+ 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);
+}