/* packet-twamp.c * Routines for TWAMP packet dissection * * Murat Demirten * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* Documentation: * RFC 4656: A One-way Active Measurement Protocol (OWAMP) * RFC 5357: A Two-Way Active Measurement Protocol (TWAMP) * RFC 5618: Mixed Security Mode for the TWAMP * (not yet implemented) * RFC 5938: Individual Session Control Feature for the TWAMP * (not yet implemented) * RFC 6038: TWAMP Reflect Octets and Symmetrical Size Features * (not yet implemented) */ #include #include #include #include #include #include "packet-tcp.h" void proto_reg_handoff_twamp(void); void proto_register_twamp(void); #define TWAMP_CONTROL_PORT 862 #define TWAMP_CONTROL_SERVER_GREETING_LEN 64 #define TWAMP_SESSION_ACCEPT_OK 0 /* Twamp times start from year 1900 */ #define TWAMP_FLOAT_DENOM 4294.967296 #define TWAMP_MODE_UNAUTHENTICATED 0x1 #define TWAMP_MODE_AUTHENTICATED 0x2 #define TWAMP_MODE_ENCRYPTED 0x4 enum twamp_control_state { CONTROL_STATE_UNKNOWN = 0, CONTROL_STATE_GREETING, CONTROL_STATE_SETUP_RESPONSE, CONTROL_STATE_SERVER_START, CONTROL_STATE_REQUEST_SESSION, CONTROL_STATE_ACCEPT_SESSION, CONTROL_STATE_START_SESSIONS, CONTROL_STATE_START_SESSIONS_ACK, CONTROL_STATE_TEST_RUNNING, CONTROL_STATE_STOP_SESSIONS, CONTROL_STATE_REQUEST_TW_SESSION }; typedef struct _twamp_session { guint8 accepted; int padding; guint16 sender_port; guint16 receiver_port; guint32 sender_address[4]; guint32 receiver_address[4]; guint8 ipvn; } twamp_session_t; typedef struct twamp_control_packet { guint32 fd; enum twamp_control_state state; conversation_t *conversation; } twamp_control_packet_t; typedef struct twamp_control_transaction { enum twamp_control_state last_state; guint32 first_data_frame; GSList *sessions; proto_tree *tree; } twamp_control_transaction_t; static dissector_handle_t owamp_test_handle; static dissector_handle_t twamp_test_handle; static dissector_handle_t twamp_control_handle; /* Protocol enabled flags */ static int proto_owamp_test = -1; static int proto_twamp_test = -1; static int proto_twamp_control = -1; static gint ett_owamp_test = -1; static gint ett_twamp_test = -1; static gint ett_twamp_control = -1; static gint ett_twamp_error_estimate = -1; /* Twamp test fields */ static int hf_twamp_seq_number = -1; static int hf_twamp_sender_timestamp = -1; static int hf_twamp_error_estimate = -1; static int hf_twamp_mbz1 = -1; static int hf_twamp_receive_timestamp = -1; static int hf_twamp_sender_seq_number = -1; static int hf_twamp_timestamp = -1; static int hf_twamp_sender_error_estimate = -1; static int hf_twamp_mbz2 = -1; static int hf_twamp_sender_ttl = -1; static int hf_twamp_padding = -1; static int hf_twamp_error_estimate_multiplier = -1; static int hf_twamp_error_estimate_scale = -1; static int hf_twamp_error_estimate_b14 = -1; static int hf_twamp_error_estimate_b15 = -1; /* Twamp control fields */ static int hf_twamp_control_unused = -1; static int hf_twamp_control_command = -1; static int hf_twamp_control_modes = -1; static int hf_twamp_control_mode = -1; static int hf_twamp_control_challenge = -1; static int hf_twamp_control_salt = -1; static int hf_twamp_control_count = -1; static int hf_twamp_control_keyid = -1; static int hf_twamp_control_sessionid = -1; static int hf_twamp_control_iv = -1; static int hf_twamp_control_ipvn = -1; static int hf_twamp_control_start_time = -1; static int hf_twamp_control_accept = -1; static int hf_twamp_control_timeout = -1; static int hf_twamp_control_type_p = -1; static int hf_twamp_control_mbz1 = -1; static int hf_twamp_control_mbz2 = -1; static int hf_twamp_control_hmac = -1; static int hf_twamp_control_num_sessions = -1; static int hf_twamp_control_sender_port = -1; static int hf_twamp_control_server_uptime = -1; static int hf_twamp_control_receiver_port = -1; static int hf_twamp_control_padding_length = -1; static int hf_twamp_control_sender_ipv4 = -1; static int hf_twamp_control_sender_ipv6 = -1; static int hf_twamp_control_receiver_ipv4 = -1; static int hf_twamp_control_receiver_ipv6 = -1; static const value_string twamp_control_accept_vals[] = { { 0, "OK" }, { 1, "Failure, reason unspecified (catch-all)" }, { 2, "Internal error" }, { 3, "Some aspect of request is not supported" }, { 4, "Cannot perform request due to permanent resource limitations" }, { 5, "Cannot perform request due to temporary resource limitations" }, { 0, NULL } }; static const value_string twamp_control_command_vals[] = { { 0, "Reserved" }, { 1, "Forbidden" }, { 2, "Start-Sessions" }, { 3, "Stop-Sessions" }, { 4, "Reserved" }, { 5, "Request-TW-Session" }, { 6, "Experimentation" }, { 0, NULL } }; static const value_string twamp_control_state_vals[] = { { CONTROL_STATE_UNKNOWN, "Unknown" }, { CONTROL_STATE_GREETING, "Server Greeting" }, { CONTROL_STATE_SETUP_RESPONSE, "Setup Response" }, { CONTROL_STATE_SERVER_START, "Server Start" }, { CONTROL_STATE_REQUEST_SESSION, "Request Session" }, { CONTROL_STATE_ACCEPT_SESSION, "Accept Session" }, { CONTROL_STATE_START_SESSIONS, "Start Sessions" }, { CONTROL_STATE_START_SESSIONS_ACK, "Start Sessions ACK" }, { CONTROL_STATE_TEST_RUNNING, "Test Running" }, { CONTROL_STATE_STOP_SESSIONS, "Stop Session" }, { CONTROL_STATE_REQUEST_TW_SESSION, "Request-TW-Session" }, { 0, NULL } }; static gint find_twamp_session_by_sender_port (gconstpointer element, gconstpointer compared) { const guint16 *sender_port = (const guint16*) compared; const twamp_session_t *session = (const twamp_session_t*) element; return !(session->sender_port == *sender_port); } static gint find_twamp_session_by_first_accept_waiting (gconstpointer element, gconstpointer dummy _U_) { const twamp_session_t *session = (const twamp_session_t*) element; if (session->accepted == 0) return 0; return 1; } static int dissect_twamp_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { gint offset = 0; gboolean is_request; proto_item *twamp_tree; proto_tree *it; conversation_t *conversation; twamp_control_transaction_t *ct; twamp_control_packet_t *cp; twamp_session_t *session = NULL; guint8 accept; guint16 sender_port; guint16 receiver_port; GSList *list; nstime_t ts; proto_tree *item; guint32 modes; guint32 type_p; guint8 ipvn; if (pinfo->destport == TWAMP_CONTROL_PORT) { is_request = TRUE; } else { is_request = FALSE; } conversation = find_or_create_conversation(pinfo); ct = (twamp_control_transaction_t *) conversation_get_proto_data(conversation, proto_twamp_control); if (ct == NULL) { if (is_request == FALSE && tvb_reported_length(tvb) == TWAMP_CONTROL_SERVER_GREETING_LEN) { /* We got server greeting */ ct = wmem_new0(wmem_file_scope(), twamp_control_transaction_t); conversation_add_proto_data(conversation, proto_twamp_control, ct); ct->last_state = CONTROL_STATE_UNKNOWN; ct->first_data_frame = pinfo->fd->num; } else { /* Can't do anything until we get a greeting */ return 0; } } if ((cp = (twamp_control_packet_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_twamp_control, 0)) == NULL) { cp = wmem_new0(wmem_file_scope(), twamp_control_packet_t); p_add_proto_data(wmem_file_scope(), pinfo, proto_twamp_control, 0, cp); /* detect state */ if (pinfo->fd->num == ct->first_data_frame) { ct->last_state = CONTROL_STATE_GREETING; } else if (ct->last_state == CONTROL_STATE_GREETING) { ct->last_state = CONTROL_STATE_SETUP_RESPONSE; } else if (ct->last_state == CONTROL_STATE_SETUP_RESPONSE) { ct->last_state = CONTROL_STATE_SERVER_START; } else if (ct->last_state == CONTROL_STATE_SERVER_START) { ct->last_state = CONTROL_STATE_REQUEST_SESSION; sender_port = tvb_get_ntohs(tvb, 12); receiver_port = tvb_get_ntohs(tvb, 14); /* try to find session from past visits */ if ((list = g_slist_find_custom(ct->sessions, &sender_port, (GCompareFunc) find_twamp_session_by_sender_port)) == NULL) { session = (twamp_session_t *) g_malloc0(sizeof(twamp_session_t)); session->sender_port = sender_port; session->receiver_port = receiver_port; session->accepted = 0; ipvn = tvb_get_guint8(tvb, 1) & 0x0F; if (ipvn == 6) { tvb_get_ipv6(tvb, 16, (struct e_in6_addr*) &session->sender_address); tvb_get_ipv6(tvb, 32, (struct e_in6_addr*) &session->receiver_address); } else { session->sender_address[0] = tvb_get_ipv4(tvb, 16); session->receiver_address[0] = tvb_get_ipv4(tvb, 32); } /* * If ip addresses not specified in control protocol, we have to choose from IP header. * It is a design decision by TWAMP and we need that ports for identifying future UDP conversations */ if (session->sender_address[0] == 0) { memcpy(&session->sender_address[0], pinfo->src.data, pinfo->src.len); } if (session->receiver_address[0] == 0) { memcpy(&session->receiver_address[0], pinfo->dst.data, pinfo->dst.len); } session->padding = tvb_get_ntohl(tvb, 64); ct->sessions = g_slist_append(ct->sessions, session); } } else if (ct->last_state == CONTROL_STATE_REQUEST_SESSION) { ct->last_state = CONTROL_STATE_ACCEPT_SESSION; accept = tvb_get_guint8(tvb, 0); if (accept == TWAMP_SESSION_ACCEPT_OK) { receiver_port = tvb_get_ntohs(tvb, 2); if ((list = g_slist_find_custom(ct->sessions, NULL, find_twamp_session_by_first_accept_waiting)) == NULL) { return 0; } session = (twamp_session_t*) list->data; session->receiver_port = receiver_port; cp->conversation = find_conversation(pinfo->fd->num, &pinfo->dst, &pinfo->src, ENDPOINT_UDP, session->sender_port, session->receiver_port, 0); if (cp->conversation == NULL /*|| cp->conversation->dissector_handle != twamp_test_handle*/) { cp->conversation = conversation_new(pinfo->fd->num, &pinfo->dst, &pinfo->src, ENDPOINT_UDP, session->sender_port, session->receiver_port, 0); if (cp->conversation) { /* create conversation specific data for test sessions */ conversation_add_proto_data(cp->conversation, proto_twamp_test, session); conversation_set_dissector(cp->conversation, twamp_test_handle); } } } } else if (ct->last_state == CONTROL_STATE_ACCEPT_SESSION) { ct->last_state = CONTROL_STATE_START_SESSIONS; } else if (ct->last_state == CONTROL_STATE_START_SESSIONS) { ct->last_state = CONTROL_STATE_START_SESSIONS_ACK; } else if (ct->last_state == CONTROL_STATE_START_SESSIONS_ACK) { ct->last_state = CONTROL_STATE_STOP_SESSIONS; } else { /* response */ } cp->state = ct->last_state; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "TWAMP-Control"); it = proto_tree_add_item(tree, proto_twamp_control, tvb, 0, -1, ENC_NA); twamp_tree = proto_item_add_subtree(it, ett_twamp_control); col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_const(cp->state, twamp_control_state_vals, "Unknown")); switch (cp->state) { case CONTROL_STATE_GREETING: proto_tree_add_item(twamp_tree, hf_twamp_control_unused, tvb, offset, 12, ENC_NA); offset += 12; modes = tvb_get_ntohl(tvb, offset) & 0x00000007; item = proto_tree_add_item(twamp_tree, hf_twamp_control_modes, tvb, offset, 4, ENC_BIG_ENDIAN); proto_item_append_text(item, " (%s%s%s)", (modes & TWAMP_MODE_UNAUTHENTICATED) ? " Unauthenticated " : "", (modes & TWAMP_MODE_AUTHENTICATED) ? "Authenticated " : "", (modes & TWAMP_MODE_ENCRYPTED) ? "Encrypted " : ""); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_control_challenge, tvb, offset, 16, ENC_NA); offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_salt, tvb, offset, 16, ENC_NA); offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_count, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 12, ENC_NA); /* offset += 12; */ break; case CONTROL_STATE_SETUP_RESPONSE: proto_tree_add_item(twamp_tree, hf_twamp_control_mode, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_control_keyid, tvb, offset, 40, ENC_NA); /* offset += 40; */ break; case CONTROL_STATE_SERVER_START: proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA); offset += 15; accept = tvb_get_guint8(tvb, offset); proto_tree_add_uint(twamp_tree, hf_twamp_control_accept, tvb, offset, 1, accept); col_append_fstr(pinfo->cinfo, COL_INFO, ", (%s%s)", (accept == 0) ? "" : "Error: ", val_to_str(accept, twamp_control_accept_vals, "%u")); offset += 1; proto_tree_add_item(twamp_tree, hf_twamp_control_iv, tvb, offset, 16, ENC_NA); offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_server_uptime, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz2, tvb, offset, 8, ENC_NA); break; case CONTROL_STATE_REQUEST_SESSION: proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; ipvn = tvb_get_guint8(tvb, offset) & 0x0F; proto_tree_add_uint(twamp_tree, hf_twamp_control_ipvn, tvb, offset, 1, ipvn); offset = 12; proto_tree_add_item(twamp_tree, hf_twamp_control_sender_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; if (ipvn == 6) { proto_tree_add_item(twamp_tree, hf_twamp_control_sender_ipv6, tvb, offset, 16, ENC_NA); } else { proto_tree_add_item(twamp_tree, hf_twamp_control_sender_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN); } offset += 16; if (ipvn == 6) { proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_ipv6, tvb, offset, 16, ENC_NA); } else { proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN); } offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_sessionid, tvb, offset, 16, ENC_NA); offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_padding_length, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_control_start_time, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; ts.secs = tvb_get_ntohl(tvb, offset); ts.nsecs = (int)(tvb_get_ntohl(tvb, offset + 4) / TWAMP_FLOAT_DENOM); proto_tree_add_time(twamp_tree, hf_twamp_control_timeout, tvb, offset, 8, &ts); offset += 8; type_p = tvb_get_ntohl(tvb, offset); item = proto_tree_add_item(twamp_tree, hf_twamp_control_type_p, tvb, offset, 4, ENC_BIG_ENDIAN); proto_item_append_text(item, " (DSCP: %d)", type_p); /* offset += 4; */ break; case CONTROL_STATE_ACCEPT_SESSION: accept = tvb_get_guint8(tvb, offset); proto_tree_add_uint(twamp_tree, hf_twamp_control_accept, tvb, offset, 1, accept); col_append_fstr(pinfo->cinfo, COL_INFO, ", (%s%s)", (accept == 0) ? "" : "Error: ", val_to_str(accept, twamp_control_accept_vals, "%u")); offset = 2; proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(twamp_tree, hf_twamp_control_sessionid, tvb, offset, 16, ENC_NA); offset += 16; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 12, ENC_NA); offset += 12; proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA); break; case CONTROL_STATE_START_SESSIONS: proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA); offset += 15; proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA); /* offset += 16; */ break; case CONTROL_STATE_START_SESSIONS_ACK: accept = tvb_get_guint8(tvb, offset); proto_tree_add_uint(twamp_tree, hf_twamp_control_accept, tvb, offset, 1, accept); col_append_fstr(pinfo->cinfo, COL_INFO, ", (%s%s)", (accept == 0) ? "" : "Error: ", val_to_str(accept, twamp_control_accept_vals, "%u")); offset += 1; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA); offset += 15; proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA); /* offset += 16; */ break; case CONTROL_STATE_STOP_SESSIONS: proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(twamp_tree, hf_twamp_control_accept, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 2, ENC_NA); offset += 2; proto_tree_add_item(twamp_tree, hf_twamp_control_num_sessions, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_control_mbz2, tvb, offset, 8, ENC_NA); offset += 8; proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA); /* offset += 16; */ break; default: break; } return tvb_captured_length(tvb); } static guint get_server_greeting_len(packet_info *pinfo _U_, tvbuff_t *tvb _U_, int offset _U_, void *data _U_) { conversation_t *conversation; twamp_control_transaction_t *ct; conversation = find_or_create_conversation(pinfo); ct = (twamp_control_transaction_t *) conversation_get_proto_data(conversation, proto_twamp_control); if (ct == NULL) { return TWAMP_CONTROL_SERVER_GREETING_LEN; } else { return tvb_captured_length(tvb); } } static int dissect_twamp_server_greeting(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { /* Try to reassemble server greeting message */ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 0, get_server_greeting_len, dissect_twamp_control, data); return tvb_captured_length(tvb); } static const int * twamp_error_estimate_flags[] = { &hf_twamp_error_estimate_b15, &hf_twamp_error_estimate_b14, &hf_twamp_error_estimate_scale, &hf_twamp_error_estimate_multiplier, NULL }; static const true_false_string tfs_twamp_sbit_tfs = { "Synchronized to UTC using an external source", "No notion of external synchronization" }; static int dissect_owamp_test(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { proto_item *ti = NULL; proto_item *owamp_tree = NULL; int offset = 0, padding = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "OWAMP-Test"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_owamp_test, tvb, 0, -1, ENC_NA); owamp_tree = proto_item_add_subtree(ti, ett_owamp_test); col_append_str(pinfo->cinfo, COL_INFO, "Measurement packet"); /* Sequence number ar in both packet types.*/ proto_tree_add_item(owamp_tree, hf_twamp_seq_number, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(owamp_tree, hf_twamp_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; /* * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S|Z| Scale | Multiplier | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ proto_tree_add_bitmask(owamp_tree, tvb, offset, hf_twamp_error_estimate, ett_twamp_error_estimate, twamp_error_estimate_flags, ENC_BIG_ENDIAN); offset += 2; padding = tvb_reported_length(tvb) - offset; if (padding > 0) { proto_tree_add_item(owamp_tree, hf_twamp_padding, tvb, offset, padding, ENC_NA); offset += padding; } return offset; } static int dissect_twamp_test(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { gint offset = 0; proto_item *ti = NULL; proto_item *twamp_tree = NULL; int padding = 0; col_set_str(pinfo-> cinfo, COL_PROTOCOL, "TWAMP-Test"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item (tree, proto_twamp_test, tvb, 0, -1, ENC_NA); twamp_tree = proto_item_add_subtree (ti, ett_twamp_test); col_append_str(pinfo->cinfo, COL_INFO, "Measurement packet"); /* Sequence number are in both packet types.*/ proto_tree_add_item(twamp_tree, hf_twamp_seq_number, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; /* * 0 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S|Z| Scale | Multiplier | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ proto_tree_add_bitmask(twamp_tree, tvb, offset, hf_twamp_error_estimate, ett_twamp_error_estimate, twamp_error_estimate_flags, ENC_BIG_ENDIAN); offset += 2; /* Responder sends TWAMP-Test packets with additional fields */ if (tvb_reported_length(tvb) - offset >= 27) { proto_tree_add_item (twamp_tree, hf_twamp_mbz1, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(twamp_tree, hf_twamp_receive_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item (twamp_tree, hf_twamp_sender_seq_number, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(twamp_tree, hf_twamp_sender_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN); offset += 8; proto_tree_add_item (twamp_tree, hf_twamp_sender_error_estimate, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item (twamp_tree, hf_twamp_mbz2, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item (twamp_tree, hf_twamp_sender_ttl, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; } padding = tvb_reported_length(tvb) - offset; if (padding > 0) { proto_tree_add_item (twamp_tree, hf_twamp_padding, tvb, offset, padding, ENC_NA); offset += padding; } /* Return the total length */ return offset; } void proto_register_twamp(void) { static hf_register_info hf_twamp_test[] = { {&hf_twamp_seq_number, {"Sequence Number", "twamp.test.seq_number", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_timestamp, {"Timestamp", "twamp.test.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_error_estimate, {"Error Estimate", "twamp.test.error_estimate", FT_UINT16, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_mbz1, {"MBZ", "twamp.test.mbz1", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_receive_timestamp, {"Receive Timestamp", "twamp.test.receive_timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_sender_seq_number, {"Sender Sequence Number", "twamp.test.sender_seq_number", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_sender_timestamp, {"Sender Timestamp", "twamp.test.sender_timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_sender_error_estimate, {"Sender Error Estimate", "twamp.test.sender_error_estimate", FT_UINT16, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_mbz2, {"MBZ", "twamp.test.mbz2", FT_UINT8, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_sender_ttl, {"Sender TTL", "twamp.test.sender_ttl", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}}, {&hf_twamp_padding, {"Packet Padding", "twamp.test.padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}}, { &hf_twamp_error_estimate_multiplier, { "Multiplier", "twamp.test.error_estimate.multiplier", FT_UINT16, BASE_DEC, NULL, 0x00ff, NULL, HFILL } }, { &hf_twamp_error_estimate_scale, { "Scale", "twamp.test.error_estimate.scale", FT_UINT16, BASE_DEC, NULL, 0x3f00, NULL, HFILL } }, { &hf_twamp_error_estimate_b14, { "Z", "twamp.test.error_estimate.z", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL } }, { &hf_twamp_error_estimate_b15, { "S", "twamp.test.error_estimate.s", FT_BOOLEAN, 16, TFS(&tfs_twamp_sbit_tfs), 0x8000, NULL, HFILL } }, }; static gint *ett_twamp_test_arr[] = { &ett_owamp_test, &ett_twamp_test }; static hf_register_info hf_twamp_control[] = { {&hf_twamp_control_unused, {"Unused", "twamp.control.unused", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_command, {"Control Command", "twamp.control.command", FT_UINT8, BASE_DEC, VALS(twamp_control_command_vals), 0x0, NULL, HFILL} }, {&hf_twamp_control_modes, {"Supported Modes", "twamp.control.modes", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_mode, {"Mode", "twamp.control.mode", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_keyid, {"Key ID", "twamp.control.keyid", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_challenge, {"Challenge", "twamp.control.challenge", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_salt, {"Salt", "twamp.control.salt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_count, {"Count", "twamp.control.count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_iv, {"Control IV", "twamp.control.iv", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_sessionid, {"Session Id", "twamp.control.session_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_mbz1, {"MBZ", "twamp.control.mbz1", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_mbz2, {"MBZ", "twamp.control.mbz2", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_hmac, {"HMAC", "twamp.control.hmac", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_padding_length, {"Padding Length", "twamp.control.padding_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_start_time, {"Start Time", "twamp.control.start_time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_timeout, {"Timeout", "twamp.control.timeout", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_type_p, {"Type-P Descriptor", "twamp.control.type-p", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_num_sessions, {"Number of Sessions", "twamp.control.numsessions", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_server_uptime, {"Server Start Time", "twamp.control.server_uptime", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_accept, {"Accept", "twamp.control.accept", FT_UINT8, BASE_DEC, VALS(twamp_control_accept_vals), 0x0, "Message acceptence by the other side", HFILL} }, {&hf_twamp_control_sender_port, {"Sender Port", "twamp.control.sender_port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_receiver_port, {"Receiver Port", "twamp.control.receiver_port", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_ipvn, {"IP Version", "twamp.control.ipvn", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} }, {&hf_twamp_control_sender_ipv4, {"Sender Address", "twamp.control.sender_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv4 sender address want to use in test packets", HFILL} }, {&hf_twamp_control_sender_ipv6, {"Sender Address", "twamp.control.sender_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, "IPv6 sender address want to use in test packets", HFILL} }, {&hf_twamp_control_receiver_ipv4, {"Receiver Address", "twamp.control.receiver_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv4 sender address want to use in test packets", HFILL} }, {&hf_twamp_control_receiver_ipv6, {"Receiver Address", "twamp.control.receiver_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, "IPv6 receiver address want to use in test packets", HFILL} } }; static gint *ett_twamp_control_arr[] = { &ett_twamp_control, &ett_twamp_error_estimate }; /* Register the protocol */ proto_twamp_test = proto_register_protocol( "TwoWay Active Measurement Test Protocol", "TWAMP-Test", "twamp.test"); /* Register the field array */ proto_register_field_array (proto_twamp_test, hf_twamp_test, array_length(hf_twamp_test)); /* Register the subtree array */ proto_register_subtree_array (ett_twamp_test_arr, array_length(ett_twamp_test_arr)); /* Register the protocol */ proto_twamp_control = proto_register_protocol( "TwoWay Active Measurement Control Protocol", "TWAMP-Control", "twamp.control"); /* Register the field array */ proto_register_field_array (proto_twamp_control, hf_twamp_control, array_length(hf_twamp_control)); /* Register the subtree array */ proto_register_subtree_array (ett_twamp_control_arr, array_length(ett_twamp_control_arr)); proto_owamp_test = proto_register_protocol( "One-way Active Measurement Protocol", "OWAMP-Test", "owamp.test"); } void proto_reg_handoff_twamp(void) { twamp_test_handle = create_dissector_handle(dissect_twamp_test, proto_twamp_test); owamp_test_handle = create_dissector_handle(dissect_owamp_test, proto_owamp_test); twamp_control_handle = create_dissector_handle(dissect_twamp_server_greeting, proto_twamp_control); dissector_add_uint("tcp.port", TWAMP_CONTROL_PORT, twamp_control_handle); dissector_add_for_decode_as("udp.port", twamp_test_handle); dissector_add_for_decode_as("udp.port", owamp_test_handle); } /* * Editor modelines * * Local Variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */