2 * Routines for TWAMP packet dissection
4 * Murat Demirten <murat@debian.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * RFC 4656: A One-way Active Measurement Protocol (OWAMP)
15 * RFC 5357: A Two-Way Active Measurement Protocol (TWAMP)
16 * RFC 5618: Mixed Security Mode for the TWAMP
17 * (not yet implemented)
18 * RFC 5938: Individual Session Control Feature for the TWAMP
19 * (not yet implemented)
20 * RFC 6038: TWAMP Reflect Octets and Symmetrical Size Features
21 * (not yet implemented)
22 * RFC 8186: Support of the IEEE 1588 Timestamp Format in TWAMP
26 #include <epan/packet.h>
27 #include <epan/conversation.h>
28 #include <epan/proto_data.h>
30 #include <wsutil/array.h>
31 #include "packet-tcp.h"
34 void proto_reg_handoff_twamp(void);
35 void proto_register_twamp(void);
37 #define TWAMP_CONTROL_PORT 862
38 #define TWAMP_CONTROL_SERVER_GREETING_LEN 64
39 #define TWAMP_SESSION_ACCEPT_OK 0
40 /* Twamp times start from year 1900 */
41 #define TWAMP_FLOAT_DENOM 4294.967296
43 #define TWAMP_MODE_UNAUTHENTICATED 0x1
44 #define TWAMP_MODE_AUTHENTICATED 0x2
45 #define TWAMP_MODE_ENCRYPTED 0x4
47 #define TWAMP_ERROR_ESTIMATE_ZBIT 0x4000
49 enum twamp_control_state
{
50 CONTROL_STATE_UNKNOWN
= 0,
51 CONTROL_STATE_GREETING
,
52 CONTROL_STATE_SETUP_RESPONSE
,
53 CONTROL_STATE_SERVER_START
,
54 CONTROL_STATE_REQUEST_SESSION
,
55 CONTROL_STATE_ACCEPT_SESSION
,
56 CONTROL_STATE_START_SESSIONS
,
57 CONTROL_STATE_START_SESSIONS_ACK
,
58 CONTROL_STATE_TEST_RUNNING
,
59 CONTROL_STATE_STOP_SESSIONS
,
60 CONTROL_STATE_REQUEST_TW_SESSION
63 typedef struct _twamp_session
{
67 uint16_t receiver_port
;
68 uint32_t sender_address
[4];
69 uint32_t receiver_address
[4];
73 typedef struct twamp_control_packet
{
75 enum twamp_control_state state
;
76 conversation_t
*conversation
;
77 } twamp_control_packet_t
;
79 typedef struct twamp_control_transaction
{
80 enum twamp_control_state last_state
;
81 uint32_t first_data_frame
;
84 } twamp_control_transaction_t
;
86 static dissector_handle_t owamp_test_handle
;
87 static dissector_handle_t twamp_test_handle
;
88 static dissector_handle_t twamp_control_handle
;
90 /* Protocol enabled flags */
91 static int proto_owamp_test
;
92 static int proto_twamp_test
;
93 static int proto_twamp_control
;
94 static int ett_owamp_test
;
95 static int ett_twamp_test
;
96 static int ett_twamp_control
;
97 static int ett_twamp_error_estimate
;
99 /* Twamp test fields */
100 static int hf_twamp_seq_number
;
101 static int hf_twamp_sender_timestamp
;
102 static int hf_twamp_error_estimate
;
103 static int hf_twamp_mbz1
;
104 static int hf_twamp_receive_timestamp
;
105 static int hf_twamp_sender_seq_number
;
106 static int hf_twamp_timestamp
;
107 static int hf_twamp_sender_error_estimate
;
108 static int hf_twamp_mbz2
;
109 static int hf_twamp_sender_ttl
;
110 static int hf_twamp_padding
;
111 static int hf_twamp_error_estimate_multiplier
;
112 static int hf_twamp_error_estimate_scale
;
113 static int hf_twamp_error_estimate_b14
;
114 static int hf_twamp_error_estimate_b15
;
116 /* Twamp control fields */
117 static int hf_twamp_control_unused
;
118 static int hf_twamp_control_command
;
119 static int hf_twamp_control_modes
;
120 static int hf_twamp_control_mode
;
121 static int hf_twamp_control_challenge
;
122 static int hf_twamp_control_salt
;
123 static int hf_twamp_control_count
;
124 static int hf_twamp_control_keyid
;
125 static int hf_twamp_control_sessionid
;
126 static int hf_twamp_control_iv
;
127 static int hf_twamp_control_ipvn
;
128 static int hf_twamp_control_conf_sender
;
129 static int hf_twamp_control_conf_receiver
;
130 static int hf_twamp_control_number_of_schedule_slots
;
131 static int hf_twamp_control_number_of_packets
;
132 static int hf_twamp_control_start_time
;
133 static int hf_twamp_control_accept
;
134 static int hf_twamp_control_timeout
;
135 static int hf_twamp_control_type_p
;
136 static int hf_twamp_control_mbz1
;
137 static int hf_twamp_control_mbz2
;
138 static int hf_twamp_control_hmac
;
139 static int hf_twamp_control_num_sessions
;
140 static int hf_twamp_control_sender_port
;
141 static int hf_twamp_control_server_uptime
;
142 static int hf_twamp_control_receiver_port
;
143 static int hf_twamp_control_padding_length
;
144 static int hf_twamp_control_sender_ipv4
;
145 static int hf_twamp_control_sender_ipv6
;
146 static int hf_twamp_control_receiver_ipv4
;
147 static int hf_twamp_control_receiver_ipv6
;
149 static const value_string twamp_control_accept_vals
[] = {
151 { 1, "Failure, reason unspecified (catch-all)" },
152 { 2, "Internal error" },
153 { 3, "Some aspect of request is not supported" },
154 { 4, "Cannot perform request due to permanent resource limitations" },
155 { 5, "Cannot perform request due to temporary resource limitations" },
159 static const value_string twamp_control_command_vals
[] = {
162 { 2, "Start-Sessions" },
163 { 3, "Stop-Sessions" },
165 { 5, "Request-TW-Session" },
166 { 6, "Experimentation" },
170 static const value_string twamp_control_state_vals
[] = {
171 { CONTROL_STATE_UNKNOWN
, "Unknown" },
172 { CONTROL_STATE_GREETING
, "Server Greeting" },
173 { CONTROL_STATE_SETUP_RESPONSE
, "Setup Response" },
174 { CONTROL_STATE_SERVER_START
, "Server Start" },
175 { CONTROL_STATE_REQUEST_SESSION
, "Request Session" },
176 { CONTROL_STATE_ACCEPT_SESSION
, "Accept Session" },
177 { CONTROL_STATE_START_SESSIONS
, "Start Sessions" },
178 { CONTROL_STATE_START_SESSIONS_ACK
, "Start Sessions ACK" },
179 { CONTROL_STATE_TEST_RUNNING
, "Test Running" },
180 { CONTROL_STATE_STOP_SESSIONS
, "Stop Session" },
181 { CONTROL_STATE_REQUEST_TW_SESSION
, "Request-TW-Session" },
186 int find_twamp_session_by_sender_port (const void *element
, const void *compared
)
188 const uint16_t *sender_port
= (const uint16_t*) compared
;
189 const twamp_session_t
*session
= (const twamp_session_t
*) element
;
190 return !(session
->sender_port
== *sender_port
);
194 int find_twamp_session_by_first_accept_waiting (const void *element
, const void *dummy _U_
)
196 const twamp_session_t
*session
= (const twamp_session_t
*) element
;
197 if (session
->accepted
== 0)
204 dissect_twamp_control(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
208 proto_item
*twamp_tree
;
210 conversation_t
*conversation
;
211 twamp_control_transaction_t
*ct
;
212 twamp_control_packet_t
*cp
;
213 twamp_session_t
*session
= NULL
;
215 uint16_t sender_port
;
216 uint16_t receiver_port
;
222 uint8_t command_number
;
225 if (pinfo
->destport
== TWAMP_CONTROL_PORT
) {
231 conversation
= find_or_create_conversation(pinfo
);
232 ct
= (twamp_control_transaction_t
*) conversation_get_proto_data(conversation
, proto_twamp_control
);
234 if (is_request
== false && tvb_reported_length(tvb
) == TWAMP_CONTROL_SERVER_GREETING_LEN
) {
235 /* We got server greeting */
236 ct
= wmem_new0(wmem_file_scope(), twamp_control_transaction_t
);
237 conversation_add_proto_data(conversation
, proto_twamp_control
, ct
);
238 ct
->last_state
= CONTROL_STATE_UNKNOWN
;
239 ct
->first_data_frame
= pinfo
->fd
->num
;
241 /* Can't do anything until we get a greeting */
245 if ((cp
= (twamp_control_packet_t
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_twamp_control
, 0)) == NULL
) {
246 cp
= wmem_new0(wmem_file_scope(), twamp_control_packet_t
);
247 p_add_proto_data(wmem_file_scope(), pinfo
, proto_twamp_control
, 0, cp
);
250 if (pinfo
->fd
->num
== ct
->first_data_frame
) {
251 ct
->last_state
= CONTROL_STATE_GREETING
;
252 } else if (ct
->last_state
== CONTROL_STATE_GREETING
) {
253 ct
->last_state
= CONTROL_STATE_SETUP_RESPONSE
;
254 } else if (ct
->last_state
== CONTROL_STATE_SETUP_RESPONSE
) {
255 ct
->last_state
= CONTROL_STATE_SERVER_START
;
256 } else if (ct
->last_state
== CONTROL_STATE_SERVER_START
) {
257 ct
->last_state
= CONTROL_STATE_REQUEST_SESSION
;
258 sender_port
= tvb_get_ntohs(tvb
, 12);
259 receiver_port
= tvb_get_ntohs(tvb
, 14);
260 /* try to find session from past visits */
261 if (g_slist_find_custom(ct
->sessions
, &sender_port
,
262 (GCompareFunc
) find_twamp_session_by_sender_port
) == NULL
) {
263 session
= g_new0(twamp_session_t
, 1);
264 session
->sender_port
= sender_port
;
265 session
->receiver_port
= receiver_port
;
266 session
->accepted
= 0;
267 ipvn
= tvb_get_uint8(tvb
, 1) & 0x0F;
270 tvb_get_ipv6(tvb
, 16, (struct e_in6_addr
*) &session
->sender_address
);
271 tvb_get_ipv6(tvb
, 32, (struct e_in6_addr
*) &session
->receiver_address
);
274 session
->sender_address
[0] = tvb_get_ipv4(tvb
, 16);
275 session
->receiver_address
[0] = tvb_get_ipv4(tvb
, 32);
278 * If ip addresses not specified in control protocol, we have to choose from IP header.
279 * It is a design decision by TWAMP and we need that ports for identifying future UDP conversations
281 if (session
->sender_address
[0] == 0) {
282 memcpy(&session
->sender_address
[0], pinfo
->src
.data
, pinfo
->src
.len
);
284 if (session
->receiver_address
[0] == 0) {
285 memcpy(&session
->receiver_address
[0], pinfo
->dst
.data
, pinfo
->dst
.len
);
287 session
->padding
= tvb_get_ntohl(tvb
, 64);
288 ct
->sessions
= g_slist_append(ct
->sessions
, session
);
290 } else if (ct
->last_state
== CONTROL_STATE_REQUEST_SESSION
) {
291 ct
->last_state
= CONTROL_STATE_ACCEPT_SESSION
;
292 accept
= tvb_get_uint8(tvb
, 0);
293 if (accept
== TWAMP_SESSION_ACCEPT_OK
) {
294 receiver_port
= tvb_get_ntohs(tvb
, 2);
296 if ((list
= g_slist_find_custom(ct
->sessions
, NULL
,
297 find_twamp_session_by_first_accept_waiting
)) == NULL
) {
300 session
= (twamp_session_t
*) list
->data
;
301 session
->receiver_port
= receiver_port
;
303 cp
->conversation
= find_conversation(pinfo
->fd
->num
, &pinfo
->dst
, &pinfo
->src
, CONVERSATION_UDP
,
304 session
->sender_port
, session
->receiver_port
, 0);
305 if (cp
->conversation
== NULL
/*|| cp->conversation->dissector_handle != twamp_test_handle*/) {
306 cp
->conversation
= conversation_new(pinfo
->fd
->num
, &pinfo
->dst
, &pinfo
->src
, CONVERSATION_UDP
,
307 session
->sender_port
, session
->receiver_port
, 0);
308 if (cp
->conversation
) {
309 /* create conversation specific data for test sessions */
310 conversation_add_proto_data(cp
->conversation
, proto_twamp_test
, session
);
311 conversation_set_dissector(cp
->conversation
, twamp_test_handle
);
315 } else if (ct
->last_state
== CONTROL_STATE_ACCEPT_SESSION
) {
316 /* We shall check the Command Number to determine current CONTROL_STATE_XXX */
317 command_number
= tvb_get_uint8(tvb
, 0);
318 switch(command_number
){
319 case 2: /* Start-Sessions */
320 ct
->last_state
= CONTROL_STATE_START_SESSIONS
;
322 case 3: /* Stop-Sessions */
323 ct
->last_state
= CONTROL_STATE_STOP_SESSIONS
;
325 case 5: /* Request-Session */
326 ct
->last_state
= CONTROL_STATE_REQUEST_SESSION
;
329 } else if (ct
->last_state
== CONTROL_STATE_START_SESSIONS
) {
330 ct
->last_state
= CONTROL_STATE_START_SESSIONS_ACK
;
331 } else if (ct
->last_state
== CONTROL_STATE_START_SESSIONS_ACK
) {
332 ct
->last_state
= CONTROL_STATE_STOP_SESSIONS
;
336 cp
->state
= ct
->last_state
;
339 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TWAMP-Control");
341 it
= proto_tree_add_item(tree
, proto_twamp_control
, tvb
, 0, -1, ENC_NA
);
342 twamp_tree
= proto_item_add_subtree(it
, ett_twamp_control
);
344 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(cp
->state
, twamp_control_state_vals
, "Unknown"));
347 case CONTROL_STATE_GREETING
:
348 proto_tree_add_item(twamp_tree
, hf_twamp_control_unused
, tvb
, offset
, 12, ENC_NA
);
350 modes
= tvb_get_ntohl(tvb
, offset
) & 0x00000007;
351 item
= proto_tree_add_item(twamp_tree
, hf_twamp_control_modes
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
352 proto_item_append_text(item
, " (%s%s%s)",
353 (modes
& TWAMP_MODE_UNAUTHENTICATED
) ? " Unauthenticated " : "",
354 (modes
& TWAMP_MODE_AUTHENTICATED
) ? "Authenticated " : "",
355 (modes
& TWAMP_MODE_ENCRYPTED
) ? "Encrypted " : "");
357 proto_tree_add_item(twamp_tree
, hf_twamp_control_challenge
, tvb
, offset
, 16, ENC_NA
);
359 proto_tree_add_item(twamp_tree
, hf_twamp_control_salt
, tvb
, offset
, 16, ENC_NA
);
361 proto_tree_add_item(twamp_tree
, hf_twamp_control_count
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
363 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 12, ENC_NA
);
367 case CONTROL_STATE_SETUP_RESPONSE
:
368 proto_tree_add_item(twamp_tree
, hf_twamp_control_mode
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
370 proto_tree_add_item(twamp_tree
, hf_twamp_control_keyid
, tvb
, offset
, 40, ENC_NA
);
374 case CONTROL_STATE_SERVER_START
:
375 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 15, ENC_NA
);
377 accept
= tvb_get_uint8(tvb
, offset
);
378 proto_tree_add_uint(twamp_tree
, hf_twamp_control_accept
, tvb
, offset
, 1, accept
);
379 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", (%s%s)",
380 (accept
== 0) ? "" : "Error: ", val_to_str(accept
, twamp_control_accept_vals
, "%u"));
382 proto_tree_add_item(twamp_tree
, hf_twamp_control_iv
, tvb
, offset
, 16, ENC_NA
);
385 proto_tree_add_item(twamp_tree
, hf_twamp_control_server_uptime
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
387 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz2
, tvb
, offset
, 8, ENC_NA
);
390 case CONTROL_STATE_REQUEST_SESSION
:
391 proto_tree_add_item(twamp_tree
, hf_twamp_control_command
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
394 ipvn
= tvb_get_uint8(tvb
, offset
) & 0x0F;
395 proto_tree_add_uint(twamp_tree
, hf_twamp_control_ipvn
, tvb
, offset
, 1, ipvn
);
398 proto_tree_add_item(twamp_tree
, hf_twamp_control_conf_sender
, tvb
, offset
, 1, ENC_NA
);
401 proto_tree_add_item(twamp_tree
, hf_twamp_control_conf_receiver
, tvb
, offset
, 1, ENC_NA
);
404 proto_tree_add_item(twamp_tree
, hf_twamp_control_number_of_schedule_slots
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
407 proto_tree_add_item(twamp_tree
, hf_twamp_control_number_of_packets
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
410 proto_tree_add_item(twamp_tree
, hf_twamp_control_sender_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
412 proto_tree_add_item(twamp_tree
, hf_twamp_control_receiver_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
416 proto_tree_add_item(twamp_tree
, hf_twamp_control_sender_ipv6
, tvb
, offset
, 16, ENC_NA
);
418 proto_tree_add_item(twamp_tree
, hf_twamp_control_sender_ipv4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
422 proto_tree_add_item(twamp_tree
, hf_twamp_control_receiver_ipv6
, tvb
, offset
, 16, ENC_NA
);
424 proto_tree_add_item(twamp_tree
, hf_twamp_control_receiver_ipv4
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
427 proto_tree_add_item(twamp_tree
, hf_twamp_control_sessionid
, tvb
, offset
, 16, ENC_NA
);
430 proto_tree_add_item(twamp_tree
, hf_twamp_control_padding_length
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
433 proto_tree_add_item(twamp_tree
, hf_twamp_control_start_time
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
436 ts
.secs
= tvb_get_ntohl(tvb
, offset
);
437 ts
.nsecs
= (int)(tvb_get_ntohl(tvb
, offset
+ 4) / TWAMP_FLOAT_DENOM
);
438 proto_tree_add_time(twamp_tree
, hf_twamp_control_timeout
, tvb
, offset
, 8, &ts
);
441 type_p
= tvb_get_ntohl(tvb
, offset
);
442 item
= proto_tree_add_item(twamp_tree
, hf_twamp_control_type_p
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
443 proto_item_append_text(item
, " (DSCP: %d)", type_p
);
447 case CONTROL_STATE_ACCEPT_SESSION
:
448 accept
= tvb_get_uint8(tvb
, offset
);
449 proto_tree_add_uint(twamp_tree
, hf_twamp_control_accept
, tvb
, offset
, 1, accept
);
450 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", (%s%s)",
451 (accept
== 0) ? "" : "Error: ", val_to_str(accept
, twamp_control_accept_vals
, "%u"));
453 proto_tree_add_item(twamp_tree
, hf_twamp_control_receiver_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
455 proto_tree_add_item(twamp_tree
, hf_twamp_control_sessionid
, tvb
, offset
, 16, ENC_NA
);
457 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 12, ENC_NA
);
459 proto_tree_add_item(twamp_tree
, hf_twamp_control_hmac
, tvb
, offset
, 16, ENC_NA
);
461 case CONTROL_STATE_START_SESSIONS
:
462 proto_tree_add_item(twamp_tree
, hf_twamp_control_command
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
464 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 15, ENC_NA
);
466 proto_tree_add_item(twamp_tree
, hf_twamp_control_hmac
, tvb
, offset
, 16, ENC_NA
);
469 case CONTROL_STATE_START_SESSIONS_ACK
:
470 accept
= tvb_get_uint8(tvb
, offset
);
471 proto_tree_add_uint(twamp_tree
, hf_twamp_control_accept
, tvb
, offset
, 1, accept
);
472 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", (%s%s)",
473 (accept
== 0) ? "" : "Error: ", val_to_str(accept
, twamp_control_accept_vals
, "%u"));
475 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 15, ENC_NA
);
477 proto_tree_add_item(twamp_tree
, hf_twamp_control_hmac
, tvb
, offset
, 16, ENC_NA
);
481 case CONTROL_STATE_STOP_SESSIONS
:
482 proto_tree_add_item(twamp_tree
, hf_twamp_control_command
, tvb
, offset
, 1, ENC_NA
);
484 proto_tree_add_item(twamp_tree
, hf_twamp_control_accept
, tvb
, offset
, 1, ENC_NA
);
486 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz1
, tvb
, offset
, 2, ENC_NA
);
488 proto_tree_add_item(twamp_tree
, hf_twamp_control_num_sessions
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
490 proto_tree_add_item(twamp_tree
, hf_twamp_control_mbz2
, tvb
, offset
, 8, ENC_NA
);
492 proto_tree_add_item(twamp_tree
, hf_twamp_control_hmac
, tvb
, offset
, 16, ENC_NA
);
499 return tvb_captured_length(tvb
);
503 unsigned get_server_greeting_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb _U_
, int offset _U_
, void *data _U_
)
505 conversation_t
*conversation
;
506 twamp_control_transaction_t
*ct
;
508 conversation
= find_or_create_conversation(pinfo
);
509 ct
= (twamp_control_transaction_t
*) conversation_get_proto_data(conversation
, proto_twamp_control
);
512 return TWAMP_CONTROL_SERVER_GREETING_LEN
;
514 return tvb_captured_length(tvb
);
519 dissect_twamp_server_greeting(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
521 /* Try to reassemble server greeting message */
522 tcp_dissect_pdus(tvb
, pinfo
, tree
, true, 0, get_server_greeting_len
, dissect_twamp_control
, data
);
523 return tvb_captured_length(tvb
);
526 static int * const twamp_error_estimate_flags
[] = {
527 &hf_twamp_error_estimate_b15
,
528 &hf_twamp_error_estimate_b14
,
529 &hf_twamp_error_estimate_scale
,
530 &hf_twamp_error_estimate_multiplier
,
534 static const true_false_string tfs_twamp_sbit_tfs
= {
535 "Synchronized to UTC using an external source",
536 "No notion of external synchronization"
539 static const true_false_string tfs_twamp_zbit_tfs
= {
540 "Abbreviated PTP Timestamp (RFC8186)",
541 "Always Zero (RFC5357) or NTP Timestamp (RFC8186)"
545 dissect_owamp_test(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
547 proto_item
*ti
= NULL
;
548 proto_item
*owamp_tree
= NULL
;
549 int offset
= 0, padding
= 0;
551 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "OWAMP-Test");
552 col_clear(pinfo
->cinfo
, COL_INFO
);
554 ti
= proto_tree_add_item(tree
, proto_owamp_test
, tvb
, 0, -1, ENC_NA
);
555 owamp_tree
= proto_item_add_subtree(ti
, ett_owamp_test
);
557 col_append_str(pinfo
->cinfo
, COL_INFO
, "Measurement packet");
559 /* Sequence number ar in both packet types.*/
560 proto_tree_add_item(owamp_tree
, hf_twamp_seq_number
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
563 if (tvb_get_ntohs(tvb
, offset
+ 8) & TWAMP_ERROR_ESTIMATE_ZBIT
)
564 proto_tree_add_item(owamp_tree
, hf_twamp_sender_timestamp
, tvb
, offset
, 8, ENC_TIME_SECS_NSECS
| ENC_BIG_ENDIAN
);
566 proto_tree_add_item(owamp_tree
, hf_twamp_sender_timestamp
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
571 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
572 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
573 * |S|Z| Scale | Multiplier |
574 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577 proto_tree_add_bitmask(owamp_tree
, tvb
, offset
, hf_twamp_error_estimate
, ett_twamp_error_estimate
, twamp_error_estimate_flags
, ENC_BIG_ENDIAN
);
580 padding
= tvb_reported_length(tvb
) - offset
;
582 proto_tree_add_item(owamp_tree
, hf_twamp_padding
, tvb
, offset
, padding
, ENC_NA
);
590 dissect_twamp_test(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
593 proto_item
*ti
= NULL
;
594 proto_item
*twamp_tree
= NULL
;
597 col_set_str(pinfo
-> cinfo
, COL_PROTOCOL
, "TWAMP-Test");
598 col_clear(pinfo
->cinfo
, COL_INFO
);
600 ti
= proto_tree_add_item (tree
, proto_twamp_test
, tvb
, 0, -1, ENC_NA
);
601 twamp_tree
= proto_item_add_subtree (ti
, ett_twamp_test
);
603 col_append_str(pinfo
->cinfo
, COL_INFO
, "Measurement packet");
605 /* Sequence number are in both packet types.*/
606 proto_tree_add_item(twamp_tree
, hf_twamp_seq_number
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
609 if (tvb_get_ntohs(tvb
, offset
+ 8) & TWAMP_ERROR_ESTIMATE_ZBIT
)
610 proto_tree_add_item(twamp_tree
, hf_twamp_timestamp
, tvb
, offset
, 8, ENC_TIME_SECS_NSECS
| ENC_BIG_ENDIAN
);
612 proto_tree_add_item(twamp_tree
, hf_twamp_timestamp
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
617 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
618 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
619 * |S|Z| Scale | Multiplier |
620 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
623 proto_tree_add_bitmask(twamp_tree
, tvb
, offset
, hf_twamp_error_estimate
, ett_twamp_error_estimate
, twamp_error_estimate_flags
, ENC_BIG_ENDIAN
);
626 /* Responder sends TWAMP-Test packets with additional fields */
627 if (tvb_reported_length(tvb
) - offset
>= 27) {
628 proto_tree_add_item (twamp_tree
, hf_twamp_mbz1
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
630 if (tvb_get_ntohs(tvb
, offset
- 4) & TWAMP_ERROR_ESTIMATE_ZBIT
)
631 proto_tree_add_item(twamp_tree
, hf_twamp_receive_timestamp
, tvb
, offset
, 8, ENC_TIME_SECS_NSECS
| ENC_BIG_ENDIAN
);
633 proto_tree_add_item(twamp_tree
, hf_twamp_receive_timestamp
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
636 proto_tree_add_item (twamp_tree
, hf_twamp_sender_seq_number
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
639 if (tvb_get_ntohs(tvb
, offset
+ 8) & TWAMP_ERROR_ESTIMATE_ZBIT
)
640 proto_tree_add_item(twamp_tree
, hf_twamp_sender_timestamp
, tvb
, offset
, 8, ENC_TIME_SECS_NSECS
| ENC_BIG_ENDIAN
);
642 proto_tree_add_item(twamp_tree
, hf_twamp_sender_timestamp
, tvb
, offset
, 8, ENC_TIME_NTP
| ENC_BIG_ENDIAN
);
645 proto_tree_add_bitmask(twamp_tree
, tvb
, offset
, hf_twamp_sender_error_estimate
, ett_twamp_error_estimate
, twamp_error_estimate_flags
, ENC_BIG_ENDIAN
);
647 proto_tree_add_item (twamp_tree
, hf_twamp_mbz2
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
649 proto_tree_add_item (twamp_tree
, hf_twamp_sender_ttl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
653 padding
= tvb_reported_length(tvb
) - offset
;
655 proto_tree_add_item (twamp_tree
, hf_twamp_padding
, tvb
, offset
, padding
, ENC_NA
);
659 /* Return the total length */
663 void proto_register_twamp(void)
665 static hf_register_info hf_twamp_test
[] = {
666 {&hf_twamp_seq_number
,
667 {"Sequence Number", "twamp.test.seq_number", FT_UINT32
,
668 BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
669 {&hf_twamp_timestamp
,
670 {"Timestamp", "twamp.test.timestamp", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
,
671 NULL
, 0x0, NULL
, HFILL
}},
672 {&hf_twamp_error_estimate
,
673 {"Error Estimate", "twamp.test.error_estimate", FT_UINT16
,
674 BASE_DEC_HEX
, NULL
, 0x0, NULL
, HFILL
}},
676 {"MBZ", "twamp.test.mbz1", FT_UINT16
, BASE_DEC_HEX
,
677 NULL
, 0x0, NULL
, HFILL
}},
678 {&hf_twamp_receive_timestamp
,
679 {"Receive Timestamp", "twamp.test.receive_timestamp", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}},
680 {&hf_twamp_sender_seq_number
,
681 {"Sender Sequence Number", "twamp.test.sender_seq_number",
682 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
683 {&hf_twamp_sender_timestamp
,
684 {"Sender Timestamp", "twamp.test.sender_timestamp", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}},
685 {&hf_twamp_sender_error_estimate
,
686 {"Sender Error Estimate", "twamp.test.sender_error_estimate",
687 FT_UINT16
, BASE_DEC_HEX
, NULL
, 0x0, NULL
, HFILL
}},
689 {"MBZ", "twamp.test.mbz2", FT_UINT16
, BASE_DEC_HEX
,
690 NULL
, 0x0, NULL
, HFILL
}},
691 {&hf_twamp_sender_ttl
,
692 {"Sender TTL", "twamp.test.sender_ttl", FT_UINT8
, BASE_DEC
,
693 NULL
, 0x0, NULL
, HFILL
}},
695 {"Packet Padding", "twamp.test.padding", FT_BYTES
, BASE_NONE
,
696 NULL
, 0x0, NULL
, HFILL
}},
697 { &hf_twamp_error_estimate_multiplier
,
698 { "Multiplier", "twamp.test.error_estimate.multiplier", FT_UINT16
, BASE_DEC
,
699 NULL
, 0x00ff, NULL
, HFILL
} },
700 { &hf_twamp_error_estimate_scale
,
701 { "Scale", "twamp.test.error_estimate.scale", FT_UINT16
, BASE_DEC
,
702 NULL
, 0x3f00, NULL
, HFILL
} },
703 { &hf_twamp_error_estimate_b14
,
704 { "Z", "twamp.test.error_estimate.z", FT_BOOLEAN
, 16,
705 TFS(&tfs_twamp_zbit_tfs
), 0x4000, NULL
, HFILL
} },
706 { &hf_twamp_error_estimate_b15
,
707 { "S", "twamp.test.error_estimate.s", FT_BOOLEAN
, 16,
708 TFS(&tfs_twamp_sbit_tfs
), 0x8000, NULL
, HFILL
} },
711 static int *ett_twamp_test_arr
[] = {
716 static hf_register_info hf_twamp_control
[] = {
717 {&hf_twamp_control_unused
,
718 {"Unused", "twamp.control.unused", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
720 {&hf_twamp_control_command
,
721 {"Control Command", "twamp.control.command", FT_UINT8
, BASE_DEC
,
722 VALS(twamp_control_command_vals
), 0x0, NULL
, HFILL
}
724 {&hf_twamp_control_modes
,
725 {"Supported Modes", "twamp.control.modes", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
727 {&hf_twamp_control_mode
,
728 {"Mode", "twamp.control.mode", FT_UINT32
, BASE_DEC_HEX
, NULL
, 0x0, NULL
, HFILL
}
730 {&hf_twamp_control_keyid
,
731 {"Key ID", "twamp.control.keyid", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
733 {&hf_twamp_control_challenge
,
734 {"Challenge", "twamp.control.challenge", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
736 {&hf_twamp_control_salt
,
737 {"Salt", "twamp.control.salt", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
739 {&hf_twamp_control_count
,
740 {"Count", "twamp.control.count", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
742 {&hf_twamp_control_iv
,
743 {"Control IV", "twamp.control.iv", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
745 {&hf_twamp_control_sessionid
,
746 {"Session Id", "twamp.control.session_id", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
748 {&hf_twamp_control_mbz1
,
749 {"MBZ", "twamp.control.mbz1", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
751 {&hf_twamp_control_mbz2
,
752 {"MBZ", "twamp.control.mbz2", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
754 {&hf_twamp_control_hmac
,
755 {"HMAC", "twamp.control.hmac", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
757 {&hf_twamp_control_padding_length
,
758 {"Padding Length", "twamp.control.padding_length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
760 {&hf_twamp_control_start_time
,
761 {"Start Time", "twamp.control.start_time", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}
763 {&hf_twamp_control_timeout
,
764 {"Timeout", "twamp.control.timeout", FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
766 {&hf_twamp_control_type_p
,
767 {"Type-P Descriptor", "twamp.control.type-p", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
769 {&hf_twamp_control_num_sessions
,
770 {"Number of Sessions", "twamp.control.numsessions", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
772 {&hf_twamp_control_server_uptime
,
773 {"Server Start Time", "twamp.control.server_uptime", FT_ABSOLUTE_TIME
, ABSOLUTE_TIME_LOCAL
, NULL
, 0x0, NULL
, HFILL
}
775 {&hf_twamp_control_accept
,
776 {"Accept", "twamp.control.accept", FT_UINT8
, BASE_DEC
, VALS(twamp_control_accept_vals
), 0x0,
777 "Message acceptance by the other side", HFILL
}
779 {&hf_twamp_control_sender_port
,
780 {"Sender Port", "twamp.control.sender_port", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
782 {&hf_twamp_control_receiver_port
,
783 {"Receiver Port", "twamp.control.receiver_port", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
785 {&hf_twamp_control_ipvn
,
786 {"IP Version", "twamp.control.ipvn", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
788 {&hf_twamp_control_conf_sender
,
789 {"Conf-Sender", "twamp.control.conf_sender", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
791 {&hf_twamp_control_conf_receiver
,
792 {"Conf-Receiver", "twamp.control.conf_receiver", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
794 {&hf_twamp_control_number_of_schedule_slots
,
795 {"Number of Schedule Slots", "twamp.control.number_of_schedule_slots", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
797 {&hf_twamp_control_number_of_packets
,
798 {"Number of Packets", "twamp.control.number_of_packets", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
800 {&hf_twamp_control_sender_ipv4
,
801 {"Sender Address", "twamp.control.sender_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
802 "IPv4 sender address want to use in test packets", HFILL
}
804 {&hf_twamp_control_sender_ipv6
,
805 {"Sender Address", "twamp.control.sender_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
806 "IPv6 sender address want to use in test packets", HFILL
}
808 {&hf_twamp_control_receiver_ipv4
,
809 {"Receiver Address", "twamp.control.receiver_ipv4", FT_IPv4
, BASE_NONE
, NULL
, 0x0,
810 "IPv4 sender address want to use in test packets", HFILL
}
812 {&hf_twamp_control_receiver_ipv6
,
813 {"Receiver Address", "twamp.control.receiver_ipv6", FT_IPv6
, BASE_NONE
, NULL
, 0x0,
814 "IPv6 receiver address want to use in test packets", HFILL
}
818 static int *ett_twamp_control_arr
[] = {
820 &ett_twamp_error_estimate
824 /* Register the protocol */
825 proto_twamp_test
= proto_register_protocol("TwoWay Active Measurement Test Protocol", "TWAMP-Test", "twamp.test");
827 /* Register the field array */
828 proto_register_field_array (proto_twamp_test
, hf_twamp_test
,
829 array_length(hf_twamp_test
));
831 /* Register the subtree array */
832 proto_register_subtree_array (ett_twamp_test_arr
,
833 array_length(ett_twamp_test_arr
));
835 /* Register the dissector handle */
836 twamp_test_handle
= register_dissector("twamp.test", dissect_twamp_test
, proto_twamp_test
);
838 /* Register the protocol */
839 proto_twamp_control
= proto_register_protocol("TwoWay Active Measurement Control Protocol", "TWAMP-Control", "twamp.control");
841 /* Register the field array */
842 proto_register_field_array (proto_twamp_control
, hf_twamp_control
,
843 array_length(hf_twamp_control
));
845 /* Register the subtree array */
846 proto_register_subtree_array (ett_twamp_control_arr
,
847 array_length(ett_twamp_control_arr
));
849 /* Register the dissector handle */
850 twamp_control_handle
= register_dissector("twamp.control", dissect_twamp_server_greeting
, proto_twamp_control
);
852 /* Register the protocol */
853 proto_owamp_test
= proto_register_protocol("One-way Active Measurement Protocol", "OWAMP-Test", "owamp.test");
855 /* Register the dissector handle */
856 owamp_test_handle
= register_dissector("owamp.test", dissect_owamp_test
, proto_owamp_test
);
859 void proto_reg_handoff_twamp(void)
861 dissector_add_uint("tcp.port", TWAMP_CONTROL_PORT
, twamp_control_handle
);
863 dissector_add_for_decode_as("udp.port", twamp_test_handle
);
864 dissector_add_for_decode_as("udp.port", owamp_test_handle
);
873 * indent-tabs-mode: nil
876 * ex: set shiftwidth=4 tabstop=8 expandtab:
877 * :indentSize=4:tabSize=8:noTabs=true: