2 * Routines for QSIG packet dissection
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <epan/packet.h>
29 #include <epan/strutil.h>
30 #include <epan/asn1.h>
32 #include "packet-ber.h"
33 #include "packet-qsig.h"
39 /* Shifted codeset values */
49 #define QSIG_IE_TRANSIT_COUNTER 0x31
50 #define QSIG_IE_PARTY_CATEGORY 0x32
52 void proto_register_qsig(void);
53 void proto_reg_handoff_qsig(void);
55 static const value_string qsig_str_ie_type_cs4
[] = {
56 { QSIG_IE_TRANSIT_COUNTER
, "Transit counter" },
59 static const value_string qsig_str_ie_type_cs5
[] = {
60 { QSIG_IE_PARTY_CATEGORY
, "Party category" },
64 static const value_string
*qsig_str_ie_type
[] = {
76 static const value_string qsig_str_pc
[] = {
78 { 0x01 , "extension" },
79 { 0x02 , "operator" },
80 { 0x03 , "emergency extension" },
84 static const value_string qsig_str_service
[] = {
91 { 14844, "QSIG-DND(O)" },
93 { 15050, "QSIG-AOC" },
95 { 15054, "QSIG-CINT" },
96 { 15506, "QSIG-MWI" },
97 { 15507, "SYNC-SIG" },
98 { 15772, "QSIG-CMN" },
99 { 15992, "QSIG-CPI(P)" },
100 { 17876, "QSIG-PUMR" },
101 { 17878, "QSIG-PUMCH" },
102 { 19460, "QSIG-SSCT" },
103 { 15429, "QSIG-WTMLR" },
104 { 15431, "QSIG-WTMCH" },
105 { 15433, "QSIG-WTMAU" },
106 { 21407, "QSIG-SD" },
107 { 21889, "QSIG-CIDL" },
110 { 3471, "QSIG-MCM" },
111 { 3472, "QSIG-MID" },
115 static const value_string qsig_str_service_name
[] = {
116 { 13868, "Name-Operations" },
117 { 13873, "Call-Diversion-Operations" },
118 { 13874, "Path-Replacement-Operations" },
119 { 13869, "Call-Transfer-Operations" },
120 { 13870, "SS-CC-Operations" },
121 { 14843, "Call-Offer-Operations" },
122 { 14844, "Do-Not-Disturb-Operations" },
123 { 14846, "Call-Intrusion-Operations" },
124 { 15050, "SS-AOC-Operation" },
125 { 15052, "Recall-Operation" },
126 { 15054, "Call-Interception-Operations" },
127 { 15506, "SS-MWI-Operations" },
128 { 15507, "Synchronization-Operations" },
129 { 15772, "Common-Information-Operations" },
130 { 15992, "Call-Interruption-Operation" },
131 { 17876, "PUM-Registration-Operation" },
132 { 17878, "Private-User-Mobility-Call-Handling-Operations" },
133 { 19460, "Single-Step-Call-Transfer-Operations" },
134 { 15429, "WTM-Location-Registration-Operations" },
135 { 15431, "Wireless-Terminal-Call-Handling-Operations" },
136 { 15433, "WTM-Authentication-Operations" },
137 { 21407, "SS-SD-Operations" },
138 { 21889, "Call-Identification-and-Call-Linkage-Operations" },
139 { 325, "Short-Message-Service-Operations" },
140 { 344, "SS-MCR-Operations" },
141 { 3471, "SS-MCM-Operations" },
142 { 3472, "SS-MID-Operations" },
147 static const gint32 op2srv_tab
[] = {
271 static const value_string qsig_str_operation
[] = {
272 #include "packet-qsig-table10.c"
276 static const value_string qsig_str_error
[] = {
277 #include "packet-qsig-table20.c"
281 /* Initialize the protocol and registered fields */
282 static int proto_qsig
= -1;
283 static int hf_qsig_operation
= -1;
284 static int hf_qsig_service
= -1;
285 static int hf_qsig_error
= -1;
286 static int hf_qsig_ie_type
= -1;
287 static int hf_qsig_ie_type_cs4
= -1;
288 static int hf_qsig_ie_type_cs5
= -1;
289 static int hf_qsig_ie_len
= -1;
290 static int hf_qsig_ie_data
= -1;
291 static int hf_qsig_tc
= -1;
292 static int hf_qsig_pc
= -1;
293 #include "packet-qsig-hf.c"
295 static int *hf_qsig_ie_type_arr
[] = {
300 &hf_qsig_ie_type_cs4
,
301 &hf_qsig_ie_type_cs5
,
306 /* Initialize the subtree pointers */
307 static gint ett_qsig
= -1;
308 static gint ett_qsig_ie
= -1;
309 static gint ett_qsig_unknown_extension
= -1;
310 #include "packet-qsig-ett.c"
311 static gint ett_cnq_PSS1InformationElement
= -1;
316 static dissector_handle_t q931_ie_handle
= NULL
;
318 /* Global variables */
319 static const char *extension_oid
= NULL
;
320 static GHashTable
*qsig_opcode2oid_hashtable
= NULL
;
321 static GHashTable
*qsig_oid2op_hashtable
= NULL
;
323 /* Dissector tables */
324 static dissector_table_t extension_dissector_table
;
326 #include "packet-qsig-fn.c"
328 typedef struct _qsig_op_t
{
330 new_dissector_t arg_pdu
;
331 new_dissector_t res_pdu
;
334 static const qsig_op_t qsig_op_tab
[] = {
335 #include "packet-qsig-table11.c"
338 typedef struct _qsig_err_t
{
340 new_dissector_t err_pdu
;
343 static const qsig_err_t qsig_err_tab
[] = {
344 #include "packet-qsig-table21.c"
347 static const qsig_op_t
*get_op(gint32 opcode
) {
350 /* search from the end to get the last occurrence if the operation is redefined in some newer specification */
351 for (i
= array_length(qsig_op_tab
) - 1; i
>= 0; i
--)
352 if (qsig_op_tab
[i
].opcode
== opcode
)
353 return &qsig_op_tab
[i
];
357 static gint32
get_service(gint32 opcode
) {
358 if ((opcode
< 0) || (opcode
>= (int)array_length(op2srv_tab
)))
360 return op2srv_tab
[opcode
];
363 static const qsig_err_t
*get_err(gint32 errcode
) {
366 /* search from the end to get the last occurrence if the operation is redefined in some newer specification */
367 for (i
= array_length(qsig_err_tab
) - 1; i
>= 0; i
--)
368 if (qsig_err_tab
[i
].errcode
== errcode
)
369 return &qsig_err_tab
[i
];
373 /*--- dissect_qsig_arg ------------------------------------------------------*/
375 dissect_qsig_arg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
) {
377 rose_ctx_t
*rctx
= get_rose_ctx(data
);
378 gint32 opcode
= 0, service
;
379 const qsig_op_t
*op_ptr
;
381 proto_item
*ti
, *ti_tmp
;
382 proto_tree
*qsig_tree
;
386 DISSECTOR_ASSERT(rctx
);
387 if (rctx
->d
.pdu
!= 1) /* invoke */
389 if (rctx
->d
.code
== 0) { /* local */
390 opcode
= rctx
->d
.code_local
;
391 op_ptr
= get_op(opcode
);
392 } else if (rctx
->d
.code
== 1) { /* global */
393 op_ptr
= (qsig_op_t
*)g_hash_table_lookup(qsig_oid2op_hashtable
, rctx
->d
.code_global
);
394 if (op_ptr
) opcode
= op_ptr
->opcode
;
400 service
= get_service(opcode
);
402 ti
= proto_tree_add_item(tree
, proto_qsig
, tvb
, offset
, tvb_length(tvb
), ENC_NA
);
403 qsig_tree
= proto_item_add_subtree(ti
, ett_qsig
);
405 proto_tree_add_uint(qsig_tree
, hf_qsig_operation
, tvb
, 0, 0, opcode
);
406 p
= try_val_to_str(opcode
, VALS(qsig_str_operation
));
408 proto_item_append_text(ti
, ": %s", p
);
409 proto_item_append_text(rctx
->d
.code_item
, " - %s", p
);
410 if (rctx
->apdu_depth
>= 0)
411 proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree
), rctx
->apdu_depth
), " %s", p
);
414 ti_tmp
= proto_tree_add_uint(qsig_tree
, hf_qsig_service
, tvb
, 0, 0, service
);
415 p
= try_val_to_str(service
, VALS(qsig_str_service_name
));
416 if (p
) proto_item_append_text(ti_tmp
, " - %s", p
);
419 offset
= op_ptr
->arg_pdu(tvb
, pinfo
, qsig_tree
, NULL
);
421 if (tvb_length_remaining(tvb
, offset
) > 0) {
422 proto_tree_add_text(qsig_tree
, tvb
, offset
, -1, "UNSUPPORTED ARGUMENT TYPE (QSIG)");
423 offset
+= tvb_length_remaining(tvb
, offset
);
429 /*--- dissect_qsig_res -------------------------------------------------------*/
431 dissect_qsig_res(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
) {
433 rose_ctx_t
*rctx
= get_rose_ctx(data
);
434 gint32 opcode
, service
;
435 const qsig_op_t
*op_ptr
;
437 proto_item
*ti
, *ti_tmp
;
438 proto_tree
*qsig_tree
;
442 DISSECTOR_ASSERT(rctx
);
443 if (rctx
->d
.pdu
!= 2) /* returnResult */
445 if (rctx
->d
.code
!= 0) /* local */
447 opcode
= rctx
->d
.code_local
;
448 op_ptr
= get_op(opcode
);
451 service
= get_service(opcode
);
453 ti
= proto_tree_add_item(tree
, proto_qsig
, tvb
, offset
, tvb_length(tvb
), ENC_NA
);
454 qsig_tree
= proto_item_add_subtree(ti
, ett_qsig
);
456 proto_tree_add_uint(qsig_tree
, hf_qsig_operation
, tvb
, 0, 0, opcode
);
457 p
= try_val_to_str(opcode
, VALS(qsig_str_operation
));
459 proto_item_append_text(ti
, ": %s", p
);
460 proto_item_append_text(rctx
->d
.code_item
, " - %s", p
);
461 if (rctx
->apdu_depth
>= 0)
462 proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree
), rctx
->apdu_depth
), " %s", p
);
465 ti_tmp
= proto_tree_add_uint(qsig_tree
, hf_qsig_service
, tvb
, 0, 0, service
);
466 p
= try_val_to_str(service
, VALS(qsig_str_service_name
));
467 if (p
) proto_item_append_text(ti_tmp
, " - %s", p
);
470 offset
= op_ptr
->res_pdu(tvb
, pinfo
, qsig_tree
, NULL
);
472 if (tvb_length_remaining(tvb
, offset
) > 0) {
473 proto_tree_add_text(qsig_tree
, tvb
, offset
, -1, "UNSUPPORTED RESULT TYPE (QSIG)");
474 offset
+= tvb_length_remaining(tvb
, offset
);
480 /*--- dissect_qsig_err ------------------------------------------------------*/
482 dissect_qsig_err(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
) {
484 rose_ctx_t
*rctx
= get_rose_ctx(data
);
486 const qsig_err_t
*err_ptr
;
489 proto_tree
*qsig_tree
;
493 DISSECTOR_ASSERT(rctx
);
494 if (rctx
->d
.pdu
!= 3) /* returnError */
496 if (rctx
->d
.code
!= 0) /* local */
498 errcode
= rctx
->d
.code_local
;
499 err_ptr
= get_err(errcode
);
503 ti
= proto_tree_add_item(tree
, proto_qsig
, tvb
, offset
, tvb_length(tvb
), ENC_NA
);
504 qsig_tree
= proto_item_add_subtree(ti
, ett_qsig
);
506 proto_tree_add_uint(qsig_tree
, hf_qsig_error
, tvb
, 0, 0, errcode
);
507 p
= try_val_to_str(errcode
, VALS(qsig_str_error
));
509 proto_item_append_text(ti
, ": %s", p
);
510 proto_item_append_text(rctx
->d
.code_item
, " - %s", p
);
511 if (rctx
->apdu_depth
>= 0)
512 proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree
), rctx
->apdu_depth
), " %s", p
);
515 if (err_ptr
->err_pdu
)
516 offset
= err_ptr
->err_pdu(tvb
, pinfo
, qsig_tree
, NULL
);
518 if (tvb_length_remaining(tvb
, offset
) > 0) {
519 proto_tree_add_text(qsig_tree
, tvb
, offset
, -1, "UNSUPPORTED ERROR TYPE (QSIG)");
520 offset
+= tvb_length_remaining(tvb
, offset
);
526 /*--- dissect_qsig_transit_counter_ie ---------------------------------------*/
528 dissect_qsig_transit_counter_ie(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
, proto_tree
*tree
, int length _U_
) {
529 proto_tree_add_item(tree
, hf_qsig_tc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
533 /*--- dissect_qsig_party_category_ie ----------------------------------------*/
535 dissect_qsig_party_category_ie(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo _U_
, proto_tree
*tree
, int length _U_
) {
536 proto_tree_add_item(tree
, hf_qsig_pc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
541 /*--- dissect_qsig_ie -------------------------------------------------------*/
543 dissect_qsig_ie(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int codeset
) {
545 proto_item
*ti
, *ti_ie
, *hidden_item
;
547 guint8 ie_type
, ie_len
;
551 ti
= proto_tree_add_item(tree
, proto_qsig
, tvb
, offset
, -1, ENC_NA
);
552 PROTO_ITEM_SET_HIDDEN(ti
);
554 ie_type
= tvb_get_guint8(tvb
, offset
);
555 ie_len
= tvb_get_guint8(tvb
, offset
+ 1);
557 ti_ie
= proto_tree_add_text(tree
, tvb
, offset
, -1, "%s",
558 val_to_str(ie_type
, VALS(qsig_str_ie_type
[codeset
]), "unknown (0x%02X)"));
559 ie_tree
= proto_item_add_subtree(ti_ie
, ett_qsig_ie
);
560 proto_tree_add_item(ie_tree
, *hf_qsig_ie_type_arr
[codeset
], tvb
, offset
, 1, ENC_BIG_ENDIAN
);
561 hidden_item
= proto_tree_add_item(ie_tree
, hf_qsig_ie_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
562 PROTO_ITEM_SET_HIDDEN(hidden_item
);
563 proto_tree_add_item(ie_tree
, hf_qsig_ie_len
, tvb
, offset
+ 1, 1, ENC_BIG_ENDIAN
);
565 if (tvb_length_remaining(tvb
, offset
) <= 0)
567 switch ((codeset
<< 8) | ie_type
) {
568 case CS4
| QSIG_IE_TRANSIT_COUNTER
:
569 dissect_qsig_transit_counter_ie(tvb
, offset
, pinfo
, ie_tree
, ie_len
);
571 case CS5
| QSIG_IE_PARTY_CATEGORY
:
572 dissect_qsig_party_category_ie(tvb
, offset
, pinfo
, ie_tree
, ie_len
);
576 if (tree
) proto_tree_add_item(ie_tree
, hf_qsig_ie_data
, tvb
, offset
, ie_len
, ENC_NA
);
580 /*--- dissect_qsig_ie_cs4 ---------------------------------------------------*/
582 dissect_qsig_ie_cs4(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
583 dissect_qsig_ie(tvb
, pinfo
, tree
, 4);
585 /*--- dissect_qsig_ie_cs5 ---------------------------------------------------*/
587 dissect_qsig_ie_cs5(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
588 dissect_qsig_ie(tvb
, pinfo
, tree
, 5);
591 /*--- qsig_init_tables ---------------------------------------------------------*/
592 static void qsig_init_tables(void) {
597 if (qsig_opcode2oid_hashtable
)
598 g_hash_table_destroy(qsig_opcode2oid_hashtable
);
599 qsig_opcode2oid_hashtable
= g_hash_table_new_full(g_int_hash
, g_int_equal
, g_free
, g_free
);
601 if (qsig_oid2op_hashtable
)
602 g_hash_table_destroy(qsig_oid2op_hashtable
);
603 qsig_oid2op_hashtable
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
605 /* fill-in global OIDs */
606 for (i
=0; i
<array_length(qsig_op_tab
); i
++) {
607 opcode
= qsig_op_tab
[i
].opcode
;
608 oid
= g_strdup_printf("1.3.12.9.%d", opcode
);
609 key
= (gint
*)g_malloc(sizeof(gint
));
611 g_hash_table_insert(qsig_opcode2oid_hashtable
, key
, oid
);
612 g_hash_table_insert(qsig_oid2op_hashtable
, g_strdup(oid
), (gpointer
)&qsig_op_tab
[i
]);
617 /*--- proto_register_qsig ---------------------------------------------------*/
618 void proto_register_qsig(void) {
621 static hf_register_info hf
[] = {
622 { &hf_qsig_operation
, { "Operation", "qsig.operation",
623 FT_UINT8
, BASE_DEC
, VALS(qsig_str_operation
), 0x0,
625 { &hf_qsig_service
, { "Service", "qsig.service",
626 FT_UINT8
, BASE_DEC
, VALS(qsig_str_service
), 0x0,
627 "Supplementary Service", HFILL
}},
628 { &hf_qsig_error
, { "Error", "qsig.error",
629 FT_UINT8
, BASE_DEC
, VALS(qsig_str_error
), 0x0,
631 { &hf_qsig_ie_type
, { "Type", "qsig.ie.type",
632 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
633 "Information Element Type", HFILL
}},
634 { &hf_qsig_ie_type_cs4
, { "Type", "qsig.ie.type.cs4",
635 FT_UINT8
, BASE_HEX
, VALS(qsig_str_ie_type_cs4
), 0x0,
636 "Information Element Type (Codeset 4)", HFILL
}},
637 { &hf_qsig_ie_type_cs5
, { "Type", "qsig.ie.type.cs5",
638 FT_UINT8
, BASE_HEX
, VALS(qsig_str_ie_type_cs5
), 0x0,
639 "Information Element Type (Codeset 5)", HFILL
}},
640 { &hf_qsig_ie_len
, { "Length", "qsig.ie.len",
641 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
642 "Information Element Length", HFILL
}},
643 { &hf_qsig_ie_data
, { "Data", "qsig.ie.data",
644 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
646 { &hf_qsig_tc
, { "Transit count", "qsig.tc",
647 FT_UINT8
, BASE_DEC
, NULL
, 0x1F,
649 { &hf_qsig_pc
, { "Party category", "qsig.pc",
650 FT_UINT8
, BASE_HEX
, VALS(qsig_str_pc
), 0x07,
652 #include "packet-qsig-hfarr.c"
655 /* List of subtrees */
656 static gint
*ett
[] = {
659 &ett_qsig_unknown_extension
,
660 #include "packet-qsig-ettarr.c"
661 &ett_cnq_PSS1InformationElement
,
664 /* Register protocol and dissector */
665 proto_qsig
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
667 /* Register fields and subtrees */
668 proto_register_field_array(proto_qsig
, hf
, array_length(hf
));
669 proto_register_subtree_array(ett
, array_length(ett
));
671 /* Register dissector tables */
672 extension_dissector_table
= register_dissector_table("qsig.ext", "QSIG Extension", FT_STRING
, BASE_NONE
);
678 /*--- proto_reg_handoff_qsig ------------------------------------------------*/
679 void proto_reg_handoff_qsig(void) {
683 dissector_handle_t q931_handle
;
684 dissector_handle_t qsig_arg_handle
;
685 dissector_handle_t qsig_res_handle
;
686 dissector_handle_t qsig_err_handle
;
687 dissector_handle_t qsig_ie_handle
;
689 q931_handle
= find_dissector("q931");
690 q931_ie_handle
= find_dissector("q931.ie");
692 qsig_arg_handle
= new_create_dissector_handle(dissect_qsig_arg
, proto_qsig
);
693 qsig_res_handle
= new_create_dissector_handle(dissect_qsig_res
, proto_qsig
);
694 for (i
=0; i
<(int)array_length(qsig_op_tab
); i
++) {
695 dissector_add_uint("q932.ros.local.arg", qsig_op_tab
[i
].opcode
, qsig_arg_handle
);
696 dissector_add_uint("q932.ros.local.res", qsig_op_tab
[i
].opcode
, qsig_res_handle
);
697 key
= qsig_op_tab
[i
].opcode
;
698 oid
= (const gchar
*)g_hash_table_lookup(qsig_opcode2oid_hashtable
, &key
);
700 dissector_add_string("q932.ros.global.arg", oid
, qsig_arg_handle
);
701 dissector_add_string("q932.ros.global.res", oid
, qsig_res_handle
);
704 qsig_err_handle
= new_create_dissector_handle(dissect_qsig_err
, proto_qsig
);
705 for (i
=0; i
<(int)array_length(qsig_err_tab
); i
++) {
706 dissector_add_uint("q932.ros.local.err", qsig_err_tab
[i
].errcode
, qsig_err_handle
);
709 qsig_ie_handle
= create_dissector_handle(dissect_qsig_ie_cs4
, proto_qsig
);
710 /* QSIG-TC - Transit counter */
711 dissector_add_uint("q931.ie", CS4
| QSIG_IE_TRANSIT_COUNTER
, qsig_ie_handle
);
713 qsig_ie_handle
= create_dissector_handle(dissect_qsig_ie_cs5
, proto_qsig
);
714 /* SSIG-BC - Party category */
715 dissector_add_uint("q931.ie", CS5
| QSIG_IE_PARTY_CATEGORY
, qsig_ie_handle
);
717 /* RFC 3204, 3.2 QSIG Media Type */
718 dissector_add_string("media_type", "application/qsig", q931_handle
);
722 /*---------------------------------------------------------------------------*/