2 * Helper-dissector for Tektronix k12xx-k15xx .rf5 file type
4 * Luis E. Garcia Ontanon <luis@ontanon.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/conversation.h>
17 #include <epan/prefs.h>
19 #include <epan/expert.h>
20 #include <epan/strutil.h>
21 #include <epan/proto_data.h>
23 #include <wiretap/wtap.h>
24 #include <wsutil/pint.h>
25 #include <wsutil/str_util.h>
26 #include "packet-sscop.h"
27 #include "packet-umts_fp.h"
29 void proto_reg_handoff_k12(void);
30 void proto_register_k12(void);
32 typedef struct _k12_hdls_t
{
35 dissector_handle_t
* handles
;
40 static int hf_k12_port_id
;
41 static int hf_k12_port_name
;
42 static int hf_k12_stack_file
;
43 static int hf_k12_port_type
;
44 static int hf_k12_atm_vp
;
45 static int hf_k12_atm_vc
;
46 static int hf_k12_atm_cid
;
53 static expert_field ei_k12_unmatched_stk_file
;
54 static expert_field ei_k12_unmatched_info
;
56 static dissector_handle_t k12_handle
;
57 static dissector_handle_t data_handle
;
58 static dissector_handle_t sscop_handle
;
59 static dissector_handle_t fp_handle
;
61 extern int proto_sscop
;
64 static wmem_tree_t
* port_handles
;
65 static uat_t
* k12_uat
;
66 static k12_handles_t
* k12_handles
;
67 static unsigned nk12_handles
;
69 static const value_string k12_port_types
[] = {
70 { K12_PORT_DS1
, "Ds1" },
71 { K12_PORT_DS0S
, "Ds0 Range" },
72 { K12_PORT_ATMPVC
, "ATM PVC" },
77 fill_fp_info(fp_info
* p_fp_info
, unsigned char* extra_info
, uint32_t length
)
80 /* 0x11=control frame 0x30=data frame */
81 unsigned info_type
= pntoh16(extra_info
);
82 /* 1=FDD, 2=TDD 3.84, 3=TDD 1.28 */
83 unsigned char radio_mode
= extra_info
[14];
84 unsigned char channel_type
= 0;
87 if (!p_fp_info
|| length
< 22)
90 /* Store division type */
91 p_fp_info
->division
= (enum division_type
)radio_mode
;
93 /* Format used by K15, later fields are shifted by 8 bytes. */
94 if (pntoh16(extra_info
+2) == 5)
97 p_fp_info
->iface_type
= IuB_Interface
;
99 p_fp_info
->release
= 0; /* dummy */
100 p_fp_info
->release_year
= 0; /* dummy */
101 p_fp_info
->release_month
= 0; /* dummy */
104 if (extra_info
[15] == 1)
105 p_fp_info
->is_uplink
= 1;
107 p_fp_info
->is_uplink
= 0;
109 if (info_type
== 0x11) /* control frame */
110 channel_type
= extra_info
[21 + adj
];
111 else if (info_type
== 0x30) /* data frame */
112 channel_type
= extra_info
[22 + adj
];
114 switch (channel_type
) {
116 p_fp_info
->channel
= CHANNEL_BCH
;
119 p_fp_info
->channel
= CHANNEL_PCH
;
120 p_fp_info
->paging_indications
= 0; /* dummy */
123 p_fp_info
->channel
= CHANNEL_CPCH
;
127 p_fp_info
->channel
= CHANNEL_RACH_FDD
;
128 else if (radio_mode
== 2)
129 p_fp_info
->channel
= CHANNEL_RACH_TDD
;
131 p_fp_info
->channel
= CHANNEL_RACH_TDD_128
;
135 p_fp_info
->channel
= CHANNEL_FACH_FDD
;
137 p_fp_info
->channel
= CHANNEL_FACH_TDD
;
141 p_fp_info
->channel
= CHANNEL_USCH_TDD_384
;
143 p_fp_info
->channel
= CHANNEL_USCH_TDD_128
;
147 p_fp_info
->channel
= CHANNEL_DSCH_FDD
;
149 p_fp_info
->channel
= CHANNEL_DSCH_TDD
;
152 p_fp_info
->channel
= CHANNEL_DCH
;
156 p_fp_info
->dch_crc_present
= 2; /* information not available */
158 if (info_type
== 0x30) { /* data frame */
159 p_fp_info
->num_chans
= extra_info
[23 + adj
];
160 /* For each channel */
161 for (i
= 0; i
< (unsigned)p_fp_info
->num_chans
&& (36+i
*104+adj
) <= length
; ++i
) {
163 p_fp_info
->chan_tf_size
[i
] = pntoh32(extra_info
+28+i
*104+adj
);
164 if (p_fp_info
->chan_tf_size
[i
])
165 /* Work out number of TBs on this channel */
166 p_fp_info
->chan_num_tbs
[i
] = pntoh32(extra_info
+32+i
*104+adj
)
167 / p_fp_info
->chan_tf_size
[i
];
173 dissect_k12(tvbuff_t
* tvb
,packet_info
* pinfo
,proto_tree
* tree
, void* data _U_
)
175 static dissector_handle_t data_handles
[2] = {NULL
, NULL
};
176 proto_item
* k12_item
;
177 proto_tree
* k12_tree
;
178 proto_item
* stack_item
;
179 dissector_handle_t sub_handle
= NULL
;
180 dissector_handle_t
* handles
;
183 k12_item
= proto_tree_add_protocol_format(tree
, proto_k12
, tvb
, 0, 0,
184 "Packet from: '%s' (0x%.8x)",
185 pinfo
->pseudo_header
->k12
.input_name
,
186 pinfo
->pseudo_header
->k12
.input
);
188 k12_tree
= proto_item_add_subtree(k12_item
, ett_k12
);
190 proto_tree_add_uint(k12_tree
, hf_k12_port_id
, tvb
, 0,0,pinfo
->pseudo_header
->k12
.input
);
191 proto_tree_add_string(k12_tree
, hf_k12_port_name
, tvb
, 0,0,pinfo
->pseudo_header
->k12
.input_name
);
192 stack_item
= proto_tree_add_string(k12_tree
, hf_k12_stack_file
, tvb
, 0,0,pinfo
->pseudo_header
->k12
.stack_file
);
194 k12_item
= proto_tree_add_uint(k12_tree
, hf_k12_port_type
, tvb
, 0, 0,
195 pinfo
->pseudo_header
->k12
.input_type
);
197 k12_tree
= proto_item_add_subtree(k12_item
, ett_port
);
199 switch ( pinfo
->pseudo_header
->k12
.input_type
) {
201 proto_tree_add_uint(k12_tree
, hf_k12_ts
, tvb
, 0,0,pinfo
->pseudo_header
->k12
.input_info
.ds0mask
);
203 case K12_PORT_ATMPVC
:
205 char* circuit_str
= wmem_strdup_printf(pinfo
->pool
, "%u:%u:%u",
206 (unsigned)pinfo
->pseudo_header
->k12
.input_info
.atm
.vp
,
207 (unsigned)pinfo
->pseudo_header
->k12
.input_info
.atm
.vc
,
208 (unsigned)pinfo
->pseudo_header
->k12
.input_info
.atm
.cid
);
211 * XXX: this is prone to collisions!
212 * we need an uniform way to manage circuits between dissectors
214 conversation_set_elements_by_id(pinfo
, CONVERSATION_NONE
, g_str_hash(circuit_str
));
216 proto_tree_add_uint(k12_tree
, hf_k12_atm_vp
, tvb
, 0, 0,
217 pinfo
->pseudo_header
->k12
.input_info
.atm
.vp
);
218 proto_tree_add_uint(k12_tree
, hf_k12_atm_vc
, tvb
, 0, 0,
219 pinfo
->pseudo_header
->k12
.input_info
.atm
.vc
);
220 if (pinfo
->pseudo_header
->k12
.input_info
.atm
.cid
)
221 proto_tree_add_uint(k12_tree
, hf_k12_atm_cid
, tvb
, 0, 0,
222 pinfo
->pseudo_header
->k12
.input_info
.atm
.cid
);
229 handles
= (dissector_handle_t
*)wmem_tree_lookup32(port_handles
, pinfo
->pseudo_header
->k12
.input
);
232 for (i
=0 ; i
< nk12_handles
; i
++) {
233 if ( ws_ascii_strcasestr(pinfo
->pseudo_header
->k12
.stack_file
, k12_handles
[i
].match
)
234 || ws_ascii_strcasestr(pinfo
->pseudo_header
->k12
.input_name
, k12_handles
[i
].match
) ) {
235 handles
= k12_handles
[i
].handles
;
241 data_handles
[0] = data_handle
;
242 handles
= data_handles
;
245 wmem_tree_insert32(port_handles
, pinfo
->pseudo_header
->k12
.input
, handles
);
249 if (handles
== data_handles
) {
250 expert_add_info(pinfo
, stack_item
, &ei_k12_unmatched_stk_file
);
251 expert_add_info(pinfo
, stack_item
, &ei_k12_unmatched_info
);
253 call_dissector(data_handle
, tvb
, pinfo
, tree
);
254 return tvb_captured_length(tvb
);
257 /* Setup subdissector information */
259 for (i
= 0; handles
[i
] && handles
[i
+1]; ++i
) {
260 if (handles
[i
] == sscop_handle
) {
261 sscop_payload_info
* p_sscop_info
= (sscop_payload_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_sscop
, 0);
263 p_sscop_info
= wmem_new0(wmem_file_scope(), sscop_payload_info
);
264 p_add_proto_data(wmem_file_scope(), pinfo
, proto_sscop
, 0, p_sscop_info
);
265 p_sscop_info
->subdissector
= handles
[i
+1];
268 /* Add more protocols here */
271 sub_handle
= handles
[0];
273 /* Setup information required by certain protocols */
274 if (sub_handle
== fp_handle
) {
275 fp_info
* p_fp_info
= (fp_info
*)p_get_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0);
277 p_fp_info
= wmem_new0(wmem_file_scope(), fp_info
);
278 p_add_proto_data(wmem_file_scope(), pinfo
, proto_fp
, 0, p_fp_info
);
280 fill_fp_info(p_fp_info
,
281 pinfo
->pseudo_header
->k12
.extra_info
,
282 pinfo
->pseudo_header
->k12
.extra_length
);
286 call_dissector(sub_handle
, tvb
, pinfo
, tree
);
287 return tvb_captured_length(tvb
);
291 k12_update_cb(void* r
, char** err
)
293 k12_handles_t
* h
= (k12_handles_t
*)r
;
295 unsigned num_protos
, i
;
297 protos
= g_strsplit(h
->protos
,":",0);
299 for (num_protos
= 0; protos
[num_protos
]; num_protos
++)
300 g_strstrip(protos
[num_protos
]);
303 /* Allocate extra space for NULL marker */
304 h
->handles
= g_new0(dissector_handle_t
, (num_protos
+1));
306 for (i
= 0; i
< num_protos
; i
++) {
307 if ( ! (h
->handles
[i
] = find_dissector(protos
[i
])) ) {
308 h
->handles
[i
] = data_handle
;
309 h
->handles
[i
+1] = NULL
;
310 *err
= ws_strdup_printf("Could not find dissector for: '%s'",protos
[i
]);
316 h
->handles
[i
] = NULL
;
323 k12_copy_cb(void* dest
, const void* orig
, size_t len _U_
)
325 k12_handles_t
* d
= (k12_handles_t
*)dest
;
326 const k12_handles_t
* o
= (const k12_handles_t
*)orig
;
327 char** protos
= g_strsplit(d
->protos
,":",0);
330 for (num_protos
= 0; protos
[num_protos
]; num_protos
++)
331 g_strstrip(protos
[num_protos
]);
333 d
->match
= g_strdup(o
->match
);
334 d
->protos
= g_strdup(o
->protos
);
335 d
->handles
= (dissector_handle_t
*)g_memdup2(o
->handles
,(unsigned)(sizeof(dissector_handle_t
)*(num_protos
+1)));
345 k12_handles_t
* h
= (k12_handles_t
*)r
;
354 protos_chk_cb(void* r _U_
, const char* p
, unsigned len
, const void* u1 _U_
, const void* u2 _U_
, char** err
)
357 char* line
= wmem_strndup(NULL
,p
,len
);
358 unsigned num_protos
, i
;
361 ascii_strdown_inplace(line
);
363 protos
= g_strsplit(line
,":",0);
365 for (num_protos
= 0; protos
[num_protos
]; num_protos
++)
366 g_strstrip(protos
[num_protos
]);
369 *err
= g_strdup("No protocols given");
370 wmem_free(NULL
, line
);
375 for (i
= 0; i
< num_protos
; i
++) {
376 if (!find_dissector(protos
[i
])) {
377 *err
= ws_strdup_printf("Could not find dissector for: '%s'",protos
[i
]);
378 wmem_free(NULL
, line
);
384 wmem_free(NULL
, line
);
389 UAT_CSTRING_CB_DEF(k12
,match
,k12_handles_t
)
390 UAT_CSTRING_CB_DEF(k12
,protos
,k12_handles_t
)
394 proto_register_k12(void)
396 static hf_register_info hf
[] = {
398 { "Port Id", "k12.port_id",
399 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
403 { "Port Name", "k12.port_name",
404 FT_STRING
, BASE_NONE
, NULL
, 0x0,
407 { &hf_k12_stack_file
,
408 { "Stack file used", "k12.stack_file",
409 FT_STRING
, BASE_NONE
, NULL
, 0x0,
413 { "Port type", "k12.input_type",
414 FT_UINT32
, BASE_HEX
, VALS(k12_port_types
), 0x0,
418 { "Timeslot mask", "k12.ds0.ts",
419 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
423 { "ATM VPI", "atm.vpi",
424 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
428 { "ATM VCI", "atm.vci",
429 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
433 { "AAL2 CID", "aal2.cid",
434 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
439 static int* ett
[] = {
444 static ei_register_info ei
[] = {
445 { &ei_k12_unmatched_stk_file
,
446 { "k12.unmatched_stk_file", PI_UNDECODED
, PI_WARN
,
447 "Warning: stk file not matched in the 'K12 Protocols' table", EXPFILL
}},
449 { &ei_k12_unmatched_info
,
450 { "k12.unmatched_info", PI_PROTOCOL
, PI_NOTE
,
451 "You can edit the 'K12 Protocols' table from Preferences->Protocols->k12xx", EXPFILL
}},
454 static uat_field_t uat_k12_flds
[] = {
455 UAT_FLD_CSTRING_ISPRINT(k12
,match
,"Match string",
456 "A string that will be matched (a=A) against an .stk filename or the name of a port.\n"
457 "The first match wins, the order of entries in the table is important!."),
458 UAT_FLD_CSTRING_OTHER(k12
,protos
,"Protocol",protos_chk_cb
,
459 "The lowest layer protocol described by this .stk file (eg: mtp2).\n"
460 "Use (sscop:sscf-nni) for sscf-nni (MTP3b) with sscop"),
464 module_t
* k12_module
;
465 expert_module_t
* expert_k12
;
467 proto_k12
= proto_register_protocol("K12xx", "K12xx", "k12");
468 proto_register_field_array(proto_k12
, hf
, array_length(hf
));
469 proto_register_subtree_array(ett
, array_length(ett
));
470 expert_k12
= expert_register_protocol(proto_k12
);
471 expert_register_field_array(expert_k12
, ei
, array_length(ei
));
472 k12_handle
= register_dissector("k12", dissect_k12
, proto_k12
);
474 k12_uat
= uat_new("K12 Protocols",
475 sizeof(k12_handles_t
),
476 "k12_protos", /* filename */
477 true, /* from_profile */
478 &k12_handles
, /* data_ptr */
479 &nk12_handles
, /* numitems_ptr */
480 UAT_AFFECTS_DISSECTION
, /* affects dissection of packets, but not set of named fields */
481 "ChK12ProtocolsSection", /* help */
489 k12_module
= prefs_register_protocol(proto_k12
, NULL
);
491 prefs_register_obsolete_preference(k12_module
, "config");
493 prefs_register_uat_preference(k12_module
, "cfg",
495 "A table of matches vs stack filenames and relative protocols",
498 port_handles
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
502 void proto_reg_handoff_k12(void)
504 data_handle
= find_dissector("data");
505 sscop_handle
= find_dissector("sscop");
506 fp_handle
= find_dissector("fp");
508 dissector_add_uint("wtap_encap", WTAP_ENCAP_K12
, k12_handle
);
512 * Editor modelines - https://www.wireshark.org/tools/modelines.html
517 * indent-tabs-mode: t
520 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
521 * :indentSize=8:tabSize=8:noTabs=false: