Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-twamp.c
blobfa346c5de6fa6a624ee6112eab4b79d85a522719
1 /* packet-twamp.c
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
13 /* Documentation:
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
25 #include <config.h>
26 #include <epan/packet.h>
27 #include <epan/conversation.h>
28 #include <epan/proto_data.h>
29 #include <epan/tfs.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 {
64 uint8_t accepted;
65 int padding;
66 uint16_t sender_port;
67 uint16_t receiver_port;
68 uint32_t sender_address[4];
69 uint32_t receiver_address[4];
70 uint8_t ipvn;
71 } twamp_session_t;
73 typedef struct twamp_control_packet {
74 uint32_t fd;
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;
82 GSList *sessions;
83 proto_tree *tree;
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[] = {
150 { 0, "OK" },
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" },
156 { 0, NULL }
159 static const value_string twamp_control_command_vals[] = {
160 { 0, "Reserved" },
161 { 1, "Forbidden" },
162 { 2, "Start-Sessions" },
163 { 3, "Stop-Sessions" },
164 { 4, "Reserved" },
165 { 5, "Request-TW-Session" },
166 { 6, "Experimentation" },
167 { 0, NULL }
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" },
182 { 0, NULL }
185 static
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);
193 static
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)
198 return 0;
200 return 1;
203 static int
204 dissect_twamp_control(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
206 int offset = 0;
207 bool is_request;
208 proto_item *twamp_tree;
209 proto_tree *it;
210 conversation_t *conversation;
211 twamp_control_transaction_t *ct;
212 twamp_control_packet_t *cp;
213 twamp_session_t *session = NULL;
214 uint8_t accept;
215 uint16_t sender_port;
216 uint16_t receiver_port;
217 GSList *list;
218 nstime_t ts;
219 proto_tree *item;
220 uint32_t modes;
221 uint32_t type_p;
222 uint8_t command_number;
223 uint8_t ipvn;
225 if (pinfo->destport == TWAMP_CONTROL_PORT) {
226 is_request = true;
227 } else {
228 is_request = false;
231 conversation = find_or_create_conversation(pinfo);
232 ct = (twamp_control_transaction_t *) conversation_get_proto_data(conversation, proto_twamp_control);
233 if (ct == NULL) {
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;
240 } else {
241 /* Can't do anything until we get a greeting */
242 return 0;
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);
249 /* detect state */
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;
269 if (ipvn == 6) {
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);
273 } else {
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) {
298 return 0;
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;
321 break;
322 case 3: /* Stop-Sessions */
323 ct->last_state = CONTROL_STATE_STOP_SESSIONS;
324 break;
325 case 5: /* Request-Session */
326 ct->last_state = CONTROL_STATE_REQUEST_SESSION;
327 break;
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;
333 } else {
334 /* response */
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"));
346 switch (cp->state) {
347 case CONTROL_STATE_GREETING:
348 proto_tree_add_item(twamp_tree, hf_twamp_control_unused, tvb, offset, 12, ENC_NA);
349 offset += 12;
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 " : "");
356 offset += 4;
357 proto_tree_add_item(twamp_tree, hf_twamp_control_challenge, tvb, offset, 16, ENC_NA);
358 offset += 16;
359 proto_tree_add_item(twamp_tree, hf_twamp_control_salt, tvb, offset, 16, ENC_NA);
360 offset += 16;
361 proto_tree_add_item(twamp_tree, hf_twamp_control_count, tvb, offset, 4, ENC_BIG_ENDIAN);
362 offset += 4;
363 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 12, ENC_NA);
364 /* offset += 12; */
365 break;
367 case CONTROL_STATE_SETUP_RESPONSE:
368 proto_tree_add_item(twamp_tree, hf_twamp_control_mode, tvb, offset, 4, ENC_BIG_ENDIAN);
369 offset += 4;
370 proto_tree_add_item(twamp_tree, hf_twamp_control_keyid, tvb, offset, 40, ENC_NA);
371 /* offset += 40; */
372 break;
374 case CONTROL_STATE_SERVER_START:
375 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA);
376 offset += 15;
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"));
381 offset += 1;
382 proto_tree_add_item(twamp_tree, hf_twamp_control_iv, tvb, offset, 16, ENC_NA);
383 offset += 16;
385 proto_tree_add_item(twamp_tree, hf_twamp_control_server_uptime, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
386 offset += 8;
387 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz2, tvb, offset, 8, ENC_NA);
389 break;
390 case CONTROL_STATE_REQUEST_SESSION:
391 proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_BIG_ENDIAN);
392 offset += 1;
394 ipvn = tvb_get_uint8(tvb, offset) & 0x0F;
395 proto_tree_add_uint(twamp_tree, hf_twamp_control_ipvn, tvb, offset, 1, ipvn);
396 offset += 1;
398 proto_tree_add_item(twamp_tree, hf_twamp_control_conf_sender, tvb, offset, 1, ENC_NA);
399 offset += 1;
401 proto_tree_add_item(twamp_tree, hf_twamp_control_conf_receiver, tvb, offset, 1, ENC_NA);
402 offset += 1;
404 proto_tree_add_item(twamp_tree, hf_twamp_control_number_of_schedule_slots, tvb, offset, 4, ENC_BIG_ENDIAN);
405 offset += 4;
407 proto_tree_add_item(twamp_tree, hf_twamp_control_number_of_packets, tvb, offset, 4, ENC_BIG_ENDIAN);
408 offset += 4;
410 proto_tree_add_item(twamp_tree, hf_twamp_control_sender_port, tvb, offset, 2, ENC_BIG_ENDIAN);
411 offset += 2;
412 proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_port, tvb, offset, 2, ENC_BIG_ENDIAN);
413 offset += 2;
415 if (ipvn == 6) {
416 proto_tree_add_item(twamp_tree, hf_twamp_control_sender_ipv6, tvb, offset, 16, ENC_NA);
417 } else {
418 proto_tree_add_item(twamp_tree, hf_twamp_control_sender_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
420 offset += 16;
421 if (ipvn == 6) {
422 proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_ipv6, tvb, offset, 16, ENC_NA);
423 } else {
424 proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
426 offset += 16;
427 proto_tree_add_item(twamp_tree, hf_twamp_control_sessionid, tvb, offset, 16, ENC_NA);
428 offset += 16;
430 proto_tree_add_item(twamp_tree, hf_twamp_control_padding_length, tvb, offset, 4, ENC_BIG_ENDIAN);
431 offset += 4;
433 proto_tree_add_item(twamp_tree, hf_twamp_control_start_time, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
434 offset += 8;
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);
439 offset += 8;
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);
444 /* offset += 4; */
445 break;
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"));
452 offset = 2;
453 proto_tree_add_item(twamp_tree, hf_twamp_control_receiver_port, tvb, offset, 2, ENC_BIG_ENDIAN);
454 offset += 2;
455 proto_tree_add_item(twamp_tree, hf_twamp_control_sessionid, tvb, offset, 16, ENC_NA);
456 offset += 16;
457 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 12, ENC_NA);
458 offset += 12;
459 proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA);
460 break;
461 case CONTROL_STATE_START_SESSIONS:
462 proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_BIG_ENDIAN);
463 offset += 1;
464 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA);
465 offset += 15;
466 proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA);
467 /* offset += 16; */
468 break;
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"));
474 offset += 1;
475 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 15, ENC_NA);
476 offset += 15;
477 proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA);
478 /* offset += 16; */
479 break;
481 case CONTROL_STATE_STOP_SESSIONS:
482 proto_tree_add_item(twamp_tree, hf_twamp_control_command, tvb, offset, 1, ENC_NA);
483 offset += 1;
484 proto_tree_add_item(twamp_tree, hf_twamp_control_accept, tvb, offset, 1, ENC_NA);
485 offset += 1;
486 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz1, tvb, offset, 2, ENC_NA);
487 offset += 2;
488 proto_tree_add_item(twamp_tree, hf_twamp_control_num_sessions, tvb, offset, 4, ENC_BIG_ENDIAN);
489 offset += 4;
490 proto_tree_add_item(twamp_tree, hf_twamp_control_mbz2, tvb, offset, 8, ENC_NA);
491 offset += 8;
492 proto_tree_add_item(twamp_tree, hf_twamp_control_hmac, tvb, offset, 16, ENC_NA);
493 /* offset += 16; */
494 break;
495 default:
496 break;
499 return tvb_captured_length(tvb);
502 static
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);
511 if (ct == NULL) {
512 return TWAMP_CONTROL_SERVER_GREETING_LEN;
513 } else {
514 return tvb_captured_length(tvb);
518 static int
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,
531 NULL
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)"
544 static int
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);
561 offset += 4;
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);
565 else
566 proto_tree_add_item(owamp_tree, hf_twamp_sender_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
567 offset += 8;
570 * 0 1
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);
578 offset += 2;
580 padding = tvb_reported_length(tvb) - offset;
581 if (padding > 0) {
582 proto_tree_add_item(owamp_tree, hf_twamp_padding, tvb, offset, padding, ENC_NA);
583 offset += padding;
586 return offset;
589 static int
590 dissect_twamp_test(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
592 int offset = 0;
593 proto_item *ti = NULL;
594 proto_item *twamp_tree = NULL;
595 int padding = 0;
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);
607 offset += 4;
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);
611 else
612 proto_tree_add_item(twamp_tree, hf_twamp_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
613 offset += 8;
616 * 0 1
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);
624 offset += 2;
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);
629 offset += 2;
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);
632 else
633 proto_tree_add_item(twamp_tree, hf_twamp_receive_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
634 offset += 8;
636 proto_tree_add_item (twamp_tree, hf_twamp_sender_seq_number, tvb, offset, 4, ENC_BIG_ENDIAN);
637 offset += 4;
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);
641 else
642 proto_tree_add_item(twamp_tree, hf_twamp_sender_timestamp, tvb, offset, 8, ENC_TIME_NTP | ENC_BIG_ENDIAN);
643 offset += 8;
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);
646 offset += 2;
647 proto_tree_add_item (twamp_tree, hf_twamp_mbz2, tvb, offset, 2, ENC_BIG_ENDIAN);
648 offset += 2;
649 proto_tree_add_item (twamp_tree, hf_twamp_sender_ttl, tvb, offset, 1, ENC_BIG_ENDIAN);
650 offset += 1;
653 padding = tvb_reported_length(tvb) - offset;
654 if (padding > 0) {
655 proto_tree_add_item (twamp_tree, hf_twamp_padding, tvb, offset, padding, ENC_NA);
656 offset += padding;
659 /* Return the total length */
660 return offset;
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}},
675 {&hf_twamp_mbz1,
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}},
688 {&hf_twamp_mbz2,
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}},
694 {&hf_twamp_padding,
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[] = {
712 &ett_owamp_test,
713 &ett_twamp_test
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[] = {
819 &ett_twamp_control,
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);
868 * Editor modelines
870 * Local Variables:
871 * c-basic-offset: 4
872 * tab-width: 8
873 * indent-tabs-mode: nil
874 * End:
876 * ex: set shiftwidth=4 tabstop=8 expandtab:
877 * :indentSize=4:tabSize=8:noTabs=true: