2 * Routines for the disassembly of the Trapeze TAPA protocol
4 * Copyright 2007 Joerg Mayer (see AUTHORS file)
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
23 #include <epan/packet.h>
24 #include <epan/to_str.h>
25 #include <epan/ipproto.h>
26 #include <epan/expert.h>
27 #include "packet-ip.h"
29 void proto_reg_handoff_tapa(void);
30 void proto_register_tapa(void);
32 /* protocol handles */
33 static int proto_tapa
;
36 static int ett_tapa_discover
;
37 static int ett_tapa_discover_req
;
38 static int ett_tapa_tunnel
;
41 static int hf_tapa_discover_type
;
42 static int hf_tapa_discover_flags
;
43 static int hf_tapa_discover_length
;
44 static int hf_tapa_discover_unknown
;
46 static int hf_tapa_discover_req_type
;
47 static int hf_tapa_discover_req_pad
;
48 static int hf_tapa_discover_req_length
;
49 static int hf_tapa_discover_req_value
;
51 static int hf_tapa_discover_newtlv_type
;
52 static int hf_tapa_discover_newtlv_pad
;
53 static int hf_tapa_discover_newtlv_length
;
54 static int hf_tapa_discover_newtlv_valuetext
;
55 static int hf_tapa_discover_newtlv_valuehex
;
57 static int hf_tapa_discover_reply_switchip
;
58 static int hf_tapa_discover_reply_unused
;
59 static int hf_tapa_discover_reply_bias
;
60 static int hf_tapa_discover_reply_pad
;
62 static int hf_tapa_tunnel_version
;
63 static int hf_tapa_tunnel_five
;
64 static int hf_tapa_tunnel_type
;
65 static int hf_tapa_tunnel_zero
;
66 static int hf_tapa_tunnel_dmac
;
67 static int hf_tapa_tunnel_smac
;
68 static int hf_tapa_tunnel_seqno
;
69 static int hf_tapa_tunnel_length
;
70 static int hf_tapa_tunnel_0804
;
71 static int hf_tapa_tunnel_tagsetc
;
73 static int hf_tapa_tunnel_remaining
;
75 static expert_field ei_tapa_length_too_short
;
77 static dissector_handle_t tapa_handle
;
79 #define PROTO_SHORT_NAME "TAPA"
80 #define PROTO_LONG_NAME "Trapeze Access Point Access Protocol"
82 #define PORT_TAPA 5000 /* Not IANA registered */
85 TAPA_TYPE_REQUEST
= 0x01,
86 TAPA_TYPE_REPLY
= 0x02,
87 TAPA_TYPE_REQUEST_NEW
= 0x04,
88 TAPA_TYPE_REPLY_NEW
= 0x05
89 } tapa_discover_type_t
;
91 static const value_string tapa_discover_type_vals
[] = {
92 { TAPA_TYPE_REQUEST
, "Request" },
93 { TAPA_TYPE_REPLY
, "Reply" },
94 { TAPA_TYPE_REQUEST_NEW
, "NewRequest" },
95 { TAPA_TYPE_REPLY_NEW
, "NewReply" },
101 TAPA_TUNNEL_TYPE_0
= 0x00,
102 TAPA_TUNNEL_TYPE_1
= 0x01
103 } tapa_tunnel_type_t
;
105 static const value_string tapa_tunnel_type_vals
[] = {
106 { TAPA_TUNNEL_TYPE_0
, "Type 0" },
107 { TAPA_TUNNEL_TYPE_1
, "Type 1" },
113 TAPA_REQUEST_SERIAL
= 0x01,
114 TAPA_REQUEST_MODEL
= 0x02
115 } tapa_discover_request_t
;
117 static const value_string tapa_discover_request_vals
[] = {
118 { TAPA_REQUEST_SERIAL
, "SerialNo" },
119 { TAPA_REQUEST_MODEL
, "Model" },
125 static const value_string tapa_discover_unknown_vals
[] = {
132 check_ascii(tvbuff_t
*tvb
, int offset
, int length
)
137 for (i
= 0; i
< length
; i
++) {
138 buf
= tvb_get_uint8(tvb
, offset
+i
);
139 if (buf
< 0x20 || buf
>= 0x80) {
147 dissect_tapa_discover_reply(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tapa_discover_tree
, uint32_t offset
, int remaining
)
149 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_reply_switchip
, tvb
, offset
, 4,
152 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", Switch: %s",
153 tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
157 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_reply_unused
, tvb
, offset
, 1,
161 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_reply_bias
, tvb
, offset
, 1,
166 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_reply_pad
, tvb
, offset
, remaining
,
174 dissect_tapa_discover_req(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tapa_discover_tree
, uint32_t offset
, int remaining
)
176 proto_tree
*tapa_discover_item_tree
;
180 const char *item_type_text
;
182 while (remaining
> 0) {
183 item_type
= tvb_get_uint8(tvb
, offset
);
184 item_type_text
= val_to_str(item_type
, tapa_discover_request_vals
, "%d");
185 item_length
= tvb_get_ntohs(tvb
, offset
+ 2);
186 item_text
= tvb_format_text(pinfo
->pool
, tvb
, offset
+ 4, item_length
);
188 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s: %s",
189 item_type_text
, item_text
);
191 tapa_discover_item_tree
= proto_tree_add_subtree_format(tapa_discover_tree
, tvb
, offset
, 4 + item_length
,
192 ett_tapa_discover_req
, NULL
, "Type %d = %s, length %d, value %s",
193 item_type
, item_type_text
, item_length
, item_text
);
195 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_req_type
, tvb
, offset
, 1,
199 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_req_pad
, tvb
, offset
, 1,
203 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_req_length
, tvb
, offset
, 2,
206 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_req_value
, tvb
, offset
, item_length
,
208 offset
+= item_length
;
210 remaining
-= (item_length
+ 4);
216 dissect_tapa_discover_unknown_new_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tapa_discover_tree
, uint32_t offset
, int remaining
)
218 proto_tree
*tapa_discover_item_tree
;
219 proto_item
*item
, *discover_item
;
222 const char *item_text
;
223 /*const char *item_type_text;*/
226 while (remaining
> 3) { /* type(1) + flags(1) + length(2) */
227 item_type
= tvb_get_uint8(tvb
, offset
);
228 /*item_type_text = val_to_str(item_type, tapa_discover_unknown_vals, "%d");*/
229 item_length
= tvb_get_ntohs(tvb
, offset
+ 2) - 4;
231 tapa_discover_item_tree
= proto_tree_add_subtree_format(tapa_discover_tree
, tvb
, offset
, 4 + item_length
,
232 ett_tapa_discover_req
, &discover_item
, "Type %d, length %d", item_type
, item_length
);
234 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_newtlv_type
, tvb
, offset
, 1,
238 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_newtlv_pad
, tvb
, offset
, 1,
242 item
= proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_newtlv_length
, tvb
, offset
, 2,
246 if (item_length
<= 0) {
247 expert_add_info(pinfo
, item
, &ei_tapa_length_too_short
);
251 is_ascii
= check_ascii(tvb
, offset
+ 4, item_length
);
253 item_text
= tvb_format_text(pinfo
->pool
, tvb
, offset
+ 4, item_length
);
255 item_text
= "BINARY-DATA";
257 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", T=%d L=%d",
258 item_type
, item_length
);
259 proto_item_append_text(discover_item
, ", value %s", item_text
);
262 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_newtlv_valuetext
,
263 tvb
, offset
, item_length
, ENC_ASCII
);
265 proto_tree_add_item(tapa_discover_item_tree
, hf_tapa_discover_newtlv_valuehex
,
266 tvb
, offset
, item_length
, ENC_NA
);
267 offset
+= item_length
;
269 remaining
-= (item_length
+ 4);
275 dissect_tapa_discover(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
278 proto_tree
*tapa_discover_tree
= NULL
;
283 packet_type
= tvb_get_uint8(tvb
, 0);
284 remaining
= tvb_get_ntohs(tvb
, 2) - 4;
286 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
287 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Discover - %s",
288 val_to_str(packet_type
, tapa_discover_type_vals
, "Unknown (%d)"));
291 ti
= proto_tree_add_item(tree
, proto_tapa
, tvb
, offset
, -1,
293 tapa_discover_tree
= proto_item_add_subtree(ti
, ett_tapa_discover
);
295 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_type
, tvb
, offset
, 1,
299 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_flags
, tvb
, offset
, 1,
303 ti
= proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_length
, tvb
, offset
, 2,
307 if (remaining
<= 0) {
308 expert_add_info(pinfo
, ti
, &ei_tapa_length_too_short
);
312 switch (packet_type
) {
313 case TAPA_TYPE_REQUEST
:
314 offset
= dissect_tapa_discover_req(tvb
, pinfo
, tapa_discover_tree
, offset
, remaining
);
316 case TAPA_TYPE_REPLY
:
317 offset
= dissect_tapa_discover_reply(tvb
, pinfo
, tapa_discover_tree
, offset
, remaining
);
319 case TAPA_TYPE_REQUEST_NEW
:
320 case TAPA_TYPE_REPLY_NEW
:
321 offset
= dissect_tapa_discover_unknown_new_tlv(tvb
, pinfo
, tapa_discover_tree
,
325 proto_tree_add_item(tapa_discover_tree
, hf_tapa_discover_unknown
, tvb
, offset
,
336 dissect_tapa_tunnel(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
339 proto_tree
*tapa_tunnel_tree
= NULL
;
345 version
= tvb_get_uint8(tvb
, 0) & 0xF0;
346 type
= tvb_get_uint8(tvb
, 1);
347 remaining
= tvb_reported_length(tvb
);
349 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
350 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Tunnel - V=%d, T=%s", version
>> 4,
351 val_to_str(type
, tapa_tunnel_type_vals
, "Unknown (%d)"));
354 ti
= proto_tree_add_item(tree
, proto_tapa
, tvb
, offset
, -1,
356 tapa_tunnel_tree
= proto_item_add_subtree(ti
, ett_tapa_tunnel
);
358 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_version
, tvb
, offset
, 1,
360 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_five
, tvb
, offset
, 1,
364 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_type
, tvb
, offset
, 1,
368 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_zero
, tvb
, offset
, 8,
372 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_dmac
, tvb
, offset
, 6,
376 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_smac
, tvb
, offset
, 6,
381 case TAPA_TUNNEL_TYPE_0
:
382 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_0804
, tvb
, offset
, 2,
386 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_tagsetc
, tvb
, offset
, 6,
391 case TAPA_TUNNEL_TYPE_1
:
392 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_seqno
, tvb
, offset
, 2,
396 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_length
, tvb
, offset
, 2,
405 /* FIXME: This is just to help figuring out what the bytes mean */
406 proto_tree_add_item(tapa_tunnel_tree
, hf_tapa_tunnel_remaining
, tvb
,
407 offset
, remaining
- offset
, ENC_NA
);
415 test_tapa_discover(tvbuff_t
*tvb
)
417 uint8_t type
, req_type
;
420 if (tvb_captured_length(tvb
) < 4)
423 /* Type(1 byte) <= 5, unknown(1 byte), length(2 bytes) */
424 type
= tvb_get_uint8(tvb
, 0);
425 /* unknown = tvb_get_uint8(tvb, 1); */
426 length
= tvb_get_ntohs(tvb
, 2);
427 req_type
= tvb_get_uint8(tvb
, 4);
429 if (type
< TAPA_TYPE_REQUEST
||
430 type
> TAPA_TYPE_REPLY_NEW
||
433 (type
== TAPA_TYPE_REQUEST
&& (req_type
< TAPA_REQUEST_SERIAL
|| req_type
> TAPA_REQUEST_MODEL
))) {
441 test_tapa_tunnel(tvbuff_t
*tvb
)
443 /* If it isn't IPv4, it's TAPA. IPv4: Version(1 byte) = 4,
444 length(2 bytes) >= 20 */
445 if (tvb_captured_length(tvb
) < 4 ||
446 (tvb_get_uint8(tvb
, 0) & 0xF0) >= 0x40 ||
447 tvb_get_ntohs(tvb
, 2) > 0 ||
448 tvb_get_uint8(tvb
, 1) > 1) { /* Is tunnel type known? */
455 dissect_tapa_static(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
457 if (test_tapa_discover(tvb
)) {
458 return dissect_tapa_discover(tvb
, pinfo
, tree
);
459 } else if (test_tapa_tunnel(tvb
)) {
460 return dissect_tapa_tunnel(tvb
, pinfo
, tree
);
465 /* heuristic dissector */
467 dissect_tapa_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *iph
)
469 /* The TAPA protocol also uses IP protocol number 4 but it isn't really IPIP */
470 if ((ws_ip_protocol(iph
) == IP_PROTO_IPIP
) && ((tvb_get_uint8(tvb
, 0) & 0xF0) != 0x40) &&
471 (tvb_get_ntohs(tvb
, 2)) < 20) {
472 dissect_tapa_static(tvb
, pinfo
, tree
, iph
);
480 proto_register_tapa(void)
482 expert_module_t
* expert_tapa
;
484 static hf_register_info hf
[] = {
486 /* TAPA discover header */
487 { &hf_tapa_discover_type
,
488 { "Type", "tapa.discover.type", FT_UINT8
, BASE_DEC
, VALS(tapa_discover_type_vals
),
491 { &hf_tapa_discover_flags
,
492 { "Flags", "tapa.discover.flags", FT_UINT8
, BASE_HEX
, NULL
,
495 { &hf_tapa_discover_length
,
496 { "Length", "tapa.discover.length", FT_UINT16
, BASE_DEC
, NULL
,
499 /* TAPA discover request */
500 { &hf_tapa_discover_req_type
,
501 { "Req type", "tapa.discover.req.type", FT_UINT8
, BASE_DEC
, VALS(tapa_discover_request_vals
),
504 { &hf_tapa_discover_req_pad
,
505 { "Req padding", "tapa.discover.req.pad", FT_UINT8
, BASE_DEC
, NULL
,
508 { &hf_tapa_discover_req_length
,
509 { "Req length", "tapa.discover.req.length", FT_UINT16
, BASE_DEC
, NULL
,
512 { &hf_tapa_discover_req_value
,
513 { "Req value", "tapa.discover.req.value", FT_BYTES
, BASE_NONE
, NULL
,
516 /* TAPA discover reply */
517 { &hf_tapa_discover_reply_switchip
,
518 { "Switch Ip", "tapa.discover.reply.switchip", FT_IPv4
, BASE_NONE
, NULL
,
521 { &hf_tapa_discover_reply_unused
,
522 { "Reply unused", "tapa.discover.reply.unused", FT_UINT8
, BASE_DEC
, NULL
,
525 { &hf_tapa_discover_reply_bias
,
526 { "Reply bias", "tapa.discover.reply.bias", FT_UINT8
, BASE_DEC
, NULL
,
529 { &hf_tapa_discover_reply_pad
,
530 { "Reply pad", "tapa.discover.reply.pad", FT_BYTES
, BASE_NONE
, NULL
,
533 /* TAPA discover new request/reply tlv */
534 { &hf_tapa_discover_newtlv_type
,
535 { "New tlv type", "tapa.discover.newtlv.type", FT_UINT8
, BASE_DEC
, VALS(tapa_discover_request_vals
),
538 { &hf_tapa_discover_newtlv_pad
,
539 { "New tlv padding", "tapa.discover.newtlv.pad", FT_UINT8
, BASE_DEC
, NULL
,
542 { &hf_tapa_discover_newtlv_length
,
543 { "New tlv length", "tapa.discover.newtlv.length", FT_UINT16
, BASE_DEC
, NULL
,
546 { &hf_tapa_discover_newtlv_valuetext
,
547 { "New tlv value", "tapa.discover.newtlv.valuetext", FT_STRING
, BASE_NONE
, NULL
,
550 { &hf_tapa_discover_newtlv_valuehex
,
551 { "New tlv value", "tapa.discover.newtlv.valuehex", FT_BYTES
, BASE_NONE
, NULL
,
554 /* TAPA discover unknown packet */
555 { &hf_tapa_discover_unknown
,
556 { "Tapa unknown packet", "tapa.discover.unknown", FT_BYTES
, BASE_NONE
, NULL
,
560 { &hf_tapa_tunnel_version
,
561 { "Tapa tunnel version", "tapa.tunnel.version", FT_UINT8
, BASE_HEX
, NULL
,
562 0xF0, NULL
, HFILL
}},
564 { &hf_tapa_tunnel_five
,
565 { "Tapa tunnel five", "tapa.tunnel.five", FT_UINT8
, BASE_HEX
, NULL
,
566 0x0F, NULL
, HFILL
}},
568 { &hf_tapa_tunnel_type
,
569 { "Tapa tunnel type", "tapa.tunnel.type", FT_UINT8
, BASE_HEX
, VALS(tapa_tunnel_type_vals
),
572 { &hf_tapa_tunnel_zero
,
573 { "Tapa tunnel zeroes", "tapa.tunnel.zero", FT_BYTES
, BASE_NONE
, NULL
,
576 { &hf_tapa_tunnel_dmac
,
577 { "Tapa tunnel dest mac", "tapa.tunnel.dmac", FT_ETHER
, BASE_NONE
, NULL
,
580 { &hf_tapa_tunnel_smac
,
581 { "Tapa tunnel src mac", "tapa.tunnel.smac", FT_ETHER
, BASE_NONE
, NULL
,
584 /* TAPA tunnel type 0 */
585 { &hf_tapa_tunnel_0804
,
586 { "Tapa tunnel 0804", "tapa.tunnel.0804", FT_UINT16
, BASE_HEX
, NULL
,
589 { &hf_tapa_tunnel_tagsetc
,
590 { "Tapa tunnel tags, seqno, pad", "tapa.tunnel.tags", FT_BYTES
, BASE_NONE
, NULL
,
593 /* TAPA tunnel type 1 */
594 { &hf_tapa_tunnel_seqno
,
595 { "Tapa tunnel seqno", "tapa.tunnel.seqno", FT_UINT16
, BASE_DEC
, NULL
,
598 { &hf_tapa_tunnel_length
,
599 { "Tapa tunnel length", "tapa.tunnel.length", FT_UINT16
, BASE_DEC
, NULL
,
603 /* TAPA tunnel remaining stuff */
604 { &hf_tapa_tunnel_remaining
,
605 { "Tapa tunnel all data", "tapa.tunnel.remaining", FT_BYTES
, BASE_NONE
, NULL
,
609 static int *ett
[] = {
611 &ett_tapa_discover_req
,
615 static ei_register_info ei
[] = {
616 { &ei_tapa_length_too_short
,
617 { "tapa.length_too_short", PI_MALFORMED
, PI_ERROR
,
618 "Length is too short (<= 4)", EXPFILL
}}
621 proto_tapa
= proto_register_protocol(PROTO_LONG_NAME
, PROTO_SHORT_NAME
, "tapa");
622 proto_register_field_array(proto_tapa
, hf
, array_length(hf
));
623 proto_register_subtree_array(ett
, array_length(ett
));
624 expert_tapa
= expert_register_protocol(proto_tapa
);
625 expert_register_field_array(expert_tapa
, ei
, array_length(ei
));
627 tapa_handle
= register_dissector("tapa", dissect_tapa_static
, proto_tapa
);
632 proto_reg_handoff_tapa(void)
634 dissector_add_uint_with_preference("udp.port", PORT_TAPA
, tapa_handle
);
635 heur_dissector_add( "ip", dissect_tapa_heur
, "TAPA over IP", "tapa_ip", proto_tapa
, HEURISTIC_ENABLE
);
639 * Editor modelines - https://www.wireshark.org/tools/modelines.html
644 * indent-tabs-mode: t
647 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
648 * :indentSize=8:tabSize=8:noTabs=false: