Minor cleanup mostly related to proto_reg_handoff
[obnox/wireshark/wip.git] / asn1 / qsig / packet-qsig-template.c
1 /* packet-qsig.c
2  * Routines for QSIG packet dissection
3  * 2007  Tomas Kukosa
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <epan/packet.h>
31 #include <epan/prefs.h>
32 #include <epan/strutil.h>
33 #include <epan/emem.h>
34 #include <epan/asn1.h>
35
36 #include "packet-ber.h"
37 #include "packet-qsig.h"
38
39 #define PNAME  "QSIG"
40 #define PSNAME "QSIG"
41 #define PFNAME "qsig"
42
43 /* Shifted codeset values */
44 #define CS0 0x000
45 #define CS1 0x100
46 #define CS2 0x200
47 #define CS3 0x300
48 #define CS4 0x400
49 #define CS5 0x500
50 #define CS6 0x600
51 #define CS7 0x700
52
53 #define QSIG_IE_TRANSIT_COUNTER 0x31
54 #define QSIG_IE_PARTY_CATEGORY  0x32
55
56 static const value_string qsig_str_ie_type_cs4[] = {
57   { QSIG_IE_TRANSIT_COUNTER , "Transit counter" },
58   { 0, NULL}
59 };
60 static const value_string qsig_str_ie_type_cs5[] = {
61   { QSIG_IE_PARTY_CATEGORY  , "Party category" },
62   { 0, NULL}
63 };
64 /* Codeset array */
65 static const value_string *qsig_str_ie_type[] = {
66   NULL,
67   NULL,
68   NULL,
69   NULL,
70   qsig_str_ie_type_cs4,
71   qsig_str_ie_type_cs5,
72   NULL,
73   NULL,
74 };
75
76
77 static const value_string qsig_str_pc[] = {
78   { 0x00 , "unknown" },
79   { 0x01 , "extension" },
80   { 0x02 , "operator" },
81   { 0x03 , "emergency extension" },
82   { 0, NULL}
83 };
84
85 static const value_string qsig_str_service[] = {
86   { 13868, "QSIG-NA" },
87   { 13873, "QSIG-CF" },
88   { 13874, "QSIG-PR" },
89   { 13869, "QSIG-CT" },
90   { 13870, "QSIG-CC" },
91   { 14843, "QSIG-CO" },
92   { 14844, "QSIG-DND(O)" },
93   { 14846, "QSIG-CI" },
94   { 15050, "QSIG-AOC" },
95   { 15052, "QSIG-RE" },
96   { 15054, "QSIG-CINT" },
97   { 15506, "QSIG-MWI" },
98   { 15507, "SYNC-SIG" },
99   { 15772, "QSIG-CMN" },
100   { 15992, "QSIG-CPI(P)" },
101   { 17876, "QSIG-PUMR" },
102   { 17878, "QSIG-PUMCH" },
103   { 19460, "QSIG-SSCT" },
104   { 15429, "QSIG-WTMLR" },
105   { 15431, "QSIG-WTMCH" },
106   { 15433, "QSIG-WTMAU" },
107   { 21407, "QSIG-SD" },
108   { 21889, "QSIG-CIDL" },
109   {   325, "QSIG-SMS" },
110   {   344, "QSIG-MCR" },
111   {  3471, "QSIG-MCM" },
112   {  3472, "QSIG-MID" },
113   {   0, NULL}
114 };
115
116 static const value_string qsig_str_service_name[] = {
117   { 13868, "Name-Operations" },
118   { 13873, "Call-Diversion-Operations" },
119   { 13874, "Path-Replacement-Operations" },
120   { 13869, "Call-Transfer-Operations" },
121   { 13870, "SS-CC-Operations" },
122   { 14843, "Call-Offer-Operations" },
123   { 14844, "Do-Not-Disturb-Operations" },
124   { 14846, "Call-Intrusion-Operations" },
125   { 15050, "SS-AOC-Operation" },
126   { 15052, "Recall-Operation" },
127   { 15054, "Call-Interception-Operations" },
128   { 15506, "SS-MWI-Operations" },
129   { 15507, "Synchronization-Operations" },
130   { 15772, "Common-Information-Operations" },
131   { 15992, "Call-Interruption-Operation" },
132   { 17876, "PUM-Registration-Operation" },
133   { 17878, "Private-User-Mobility-Call-Handling-Operations" },
134   { 19460, "Single-Step-Call-Transfer-Operations" },
135   { 15429, "WTM-Location-Registration-Operations" },
136   { 15431, "Wireless-Terminal-Call-Handling-Operations" },
137   { 15433, "WTM-Authentication-Operations" },
138   { 21407, "SS-SD-Operations" },
139   { 21889, "Call-Identification-and-Call-Linkage-Operations" },
140   {   325, "Short-Message-Service-Operations" },
141   {   344, "SS-MCR-Operations" },
142   {  3471, "SS-MCM-Operations" },
143   {  3472, "SS-MID-Operations" },
144   {   0, NULL}
145 };
146
147 #define NO_SRV (-1)
148 static const gint32 op2srv_tab[] = {
149   /*   0 */ 13868, 
150   /*   1 */ 13868, 
151   /*   2 */ 13868, 
152   /*   3 */ 13868, 
153   /*   4 */ 13874, 
154   /*   5 */ 13874, 
155   /*   6 */ 13874, 
156   /*   7 */ 13869, 
157   /*   8 */ 13869, 
158   /*   9 */ 13869, 
159   /*  10 */ 13869, 
160   /*  11 */ 13869, 
161   /*  12 */ 13869, 
162   /*  13 */ 13869, 
163   /*  14 */ 13869, 
164   /*  15 */ 13873, 
165   /*  16 */ 13873, 
166   /*  17 */ 13873, 
167   /*  18 */ 13873, 
168   /*  19 */ 13873, 
169   /*  20 */ 13873, 
170   /*  21 */ 13873, 
171   /*  22 */ 13873, 
172   /*  23 */ 13873, 
173   /*  24 */ NO_SRV,
174   /*  25 */ NO_SRV,
175   /*  26 */ NO_SRV,
176   /*  27 */ 13870, 
177   /*  28 */ 13870, 
178   /*  29 */ 13870, 
179   /*  30 */ 13870, 
180   /*  31 */ 13870, 
181   /*  32 */ 13870, 
182   /*  33 */ 13870, 
183   /*  34 */ 14843, 
184   /*  35 */ 14844, 
185   /*  36 */ 14844, 
186   /*  37 */ 14844, 
187   /*  38 */ 14844, 
188   /*  39 */ 14844, 
189   /*  40 */ 13870, 
190   /*  41 */ 90001, 
191   /*  42 */ 90001, 
192   /*  43 */ 14846, 
193   /*  44 */ 14846, 
194   /*  45 */ 14846, 
195   /*  46 */ 14846, 
196   /*  47 */ 14846, 
197   /*  48 */ 14846, 
198   /*  49 */ 90001, 
199   /*  50 */ 15429, 
200   /*  51 */ 15429, 
201   /*  52 */ 15429, 
202   /*  53 */ 15429, 
203   /*  54 */ 15431, 
204   /*  55 */ 15431, 
205   /*  56 */ 15431, 
206   /*  57 */ 15052, 
207   /*  58 */ 15052, 
208   /*  59 */ 15050, 
209   /*  60 */ 15050, 
210   /*  61 */ 15050, 
211   /*  62 */ 15050, 
212   /*  63 */ 15050, 
213   /*  64 */ 15050, 
214   /*  65 */ 15050, 
215   /*  66 */ 15054, 
216   /*  67 */ 15054, 
217   /*  68 */ 15054, 
218   /*  69 */ 15054, 
219   /*  70 */ 15054, 
220   /*  71 */ 15431, 
221   /*  72 */ 15433, 
222   /*  73 */ 15433, 
223   /*  74 */ 15433, 
224   /*  75 */ 15433, 
225   /*  76 */ 15433, 
226   /*  77 */ 15433, 
227   /*  78 */ 15507, 
228   /*  79 */ 15507, 
229   /*  80 */  3471, 
230   /*  81 */  3471, 
231   /*  82 */  3471, 
232   /*  83 */ NO_SRV,
233   /*  84 */ 15772, 
234   /*  85 */ 15772, 
235   /*  86 */ 13874, 
236   /*  87 */ 15992, 
237   /*  88 */ 15992, 
238   /*  89 */ 17876, 
239   /*  90 */ 17876, 
240   /*  91 */ 17876, 
241   /*  92 */ 17876, 
242   /*  93 */ 17878, 
243   /*  94 */ 17878, 
244   /*  95 */ 17878, 
245   /*  96 */ 17878, 
246   /*  97 */ 15429, 
247   /*  98 */ 15429, 
248   /*  99 */ 19460, 
249   /* 100 */ 19460, 
250   /* 101 */ 19460, 
251   /* 102 */ 19460, 
252   /* 103 */ 21407, 
253   /* 104 */ 21407, 
254   /* 105 */ 21889, 
255   /* 106 */ 21889, 
256   /* 107 */   325, 
257   /* 108 */   325, 
258   /* 109 */   325, 
259   /* 110 */   325, 
260   /* 111 */   325, 
261   /* 112 */   344, 
262   /* 113 */   344, 
263   /* 114 */   344, 
264   /* 115 */  3471, 
265   /* 116 */  3471, 
266   /* 117 */  3471, 
267   /* 118 */  3471, 
268   /* 119 */  3472, 
269   /* 120 */  3472, 
270 };                                 
271
272 static const value_string qsig_str_operation[] = {
273 #include "packet-qsig-table10.c"
274   {   0, NULL}
275 };
276
277 static const value_string qsig_str_error[] = {
278 #include "packet-qsig-table20.c"
279   {   0, NULL}
280 };
281                      
282 /* Initialize the protocol and registered fields */
283 int proto_qsig = -1;
284 static int hf_qsig_operation = -1;
285 static int hf_qsig_service = -1;
286 static int hf_qsig_error = -1;
287 static int hf_qsig_ie_type = -1;
288 static int hf_qsig_ie_type_cs4 = -1;
289 static int hf_qsig_ie_type_cs5 = -1;
290 static int hf_qsig_ie_len = -1;
291 static int hf_qsig_ie_data = -1;
292 static int hf_qsig_tc = -1;
293 static int hf_qsig_pc = -1;
294 #include "packet-qsig-hf.c"
295
296 static int *hf_qsig_ie_type_arr[] = {
297   NULL,
298   NULL,
299   NULL,
300   NULL,
301   &hf_qsig_ie_type_cs4,
302   &hf_qsig_ie_type_cs5,
303   NULL,
304   NULL,
305 };
306
307 /* Initialize the subtree pointers */
308 static gint ett_qsig = -1;
309 static gint ett_qsig_ie = -1;
310 static gint ett_qsig_unknown_extension = -1;
311 #include "packet-qsig-ett.c"
312
313 /* Preferences */
314
315 /* Global variables */
316 static const char *extension_oid = NULL;
317
318 /* Dissector tables */
319 static dissector_table_t extension_dissector_table;
320
321 #include "packet-qsig-fn.c"
322
323 typedef struct _qsig_op_t {
324   gint32 opcode;
325   new_dissector_t arg_pdu;
326   new_dissector_t res_pdu;
327 } qsig_op_t;
328
329 static const qsig_op_t qsig_op_tab[] = {
330 #include "packet-qsig-table11.c"
331 };                                 
332
333 typedef struct _qsig_err_t {
334   gint32 errcode;
335   new_dissector_t err_pdu;
336 } qsig_err_t;
337
338 static const qsig_err_t qsig_err_tab[] = {
339 #include "packet-qsig-table21.c"
340 };                                 
341
342 static const qsig_op_t *get_op(gint32 opcode) {
343   int i;
344
345   /* search from the end to get the last occurence if the operation is redefined in some newer specification */
346   for (i = array_length(qsig_op_tab) - 1; i >= 0; i--)
347     if (qsig_op_tab[i].opcode == opcode)
348       return &qsig_op_tab[i];
349   return NULL;
350 }
351
352 static gint32 get_service(gint32 opcode) {
353   if ((opcode < 0) || (opcode >= (int)array_length(op2srv_tab)))
354     return NO_SRV;
355   return op2srv_tab[opcode];
356 }
357
358 static const qsig_err_t *get_err(gint32 errcode) {
359   int i;
360
361   /* search from the end to get the last occurence if the operation is redefined in some newer specification */
362   for (i = array_length(qsig_err_tab) - 1; i >= 0; i--)
363     if (qsig_err_tab[i].errcode == errcode)
364       return &qsig_err_tab[i];
365   return NULL;
366 }
367                   
368 /*--- dissect_qsig_arg ------------------------------------------------------*/
369 static int   
370 dissect_qsig_arg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
371   int offset;
372   rose_ctx_t *rctx;
373   gint32 opcode, service;
374   const qsig_op_t *op_ptr;
375   const gchar *p;
376   proto_item *ti, *ti_tmp;
377   proto_tree *qsig_tree;
378
379   offset = 0;
380   rctx = get_rose_ctx(pinfo->private_data);
381   DISSECTOR_ASSERT(rctx);
382   if (rctx->d.pdu != 1)  /* invoke */
383     return offset; 
384   if (rctx->d.code != 0)  /* local */
385     return offset; 
386   opcode = rctx->d.code_local;
387   op_ptr = get_op(opcode);
388   if (!op_ptr)
389     return offset; 
390   service = get_service(opcode);
391
392   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
393   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
394
395   proto_tree_add_uint(qsig_tree, hf_qsig_operation, tvb, 0, 0, opcode);
396   p = match_strval(opcode, VALS(qsig_str_operation));
397   if (p) {
398     proto_item_append_text(ti, ": %s", p);
399     proto_item_append_text(rctx->d.code_item, " - %s", p);
400     if (rctx->apdu_depth >= 0)
401       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
402   }
403
404   ti_tmp = proto_tree_add_uint(qsig_tree, hf_qsig_service, tvb, 0, 0, service);
405   p = match_strval(service, VALS(qsig_str_service_name));
406   if (p) proto_item_append_text(ti_tmp, " - %s", p);
407
408   if (op_ptr->arg_pdu)
409     offset = op_ptr->arg_pdu(tvb, pinfo, qsig_tree);
410   else 
411     if (tvb_length_remaining(tvb, offset) > 0) {
412       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ARGUMENT TYPE (QSIG)");
413       offset += tvb_length_remaining(tvb, offset);
414     }
415
416   return offset;
417 }
418
419 /*--- dissect_qsig_res -------------------------------------------------------*/
420 static int
421 dissect_qsig_res(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
422   gint offset;
423   rose_ctx_t *rctx;
424   gint32 opcode, service;
425   const qsig_op_t *op_ptr;
426   const gchar *p;
427   proto_item *ti, *ti_tmp;
428   proto_tree *qsig_tree;
429
430   offset = 0;
431   rctx = get_rose_ctx(pinfo->private_data);
432   DISSECTOR_ASSERT(rctx);
433   if (rctx->d.pdu != 2)  /* returnResult */
434     return offset; 
435   if (rctx->d.code != 0)  /* local */
436     return offset; 
437   opcode = rctx->d.code_local;
438   op_ptr = get_op(opcode);
439   if (!op_ptr)
440     return offset; 
441   service = get_service(opcode);
442
443   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
444   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
445
446   proto_tree_add_uint(qsig_tree, hf_qsig_operation, tvb, 0, 0, opcode);
447   p = match_strval(opcode, VALS(qsig_str_operation));
448   if (p) {
449     proto_item_append_text(ti, ": %s", p);
450     proto_item_append_text(rctx->d.code_item, " - %s", p);
451     if (rctx->apdu_depth >= 0)
452       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
453   }
454
455   ti_tmp = proto_tree_add_uint(qsig_tree, hf_qsig_service, tvb, 0, 0, service);
456   p = match_strval(service, VALS(qsig_str_service_name));
457   if (p) proto_item_append_text(ti_tmp, " - %s", p);
458
459   if (op_ptr->res_pdu)
460     offset = op_ptr->res_pdu(tvb, pinfo, qsig_tree);
461   else 
462     if (tvb_length_remaining(tvb, offset) > 0) {
463       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED RESULT TYPE (QSIG)");
464       offset += tvb_length_remaining(tvb, offset);
465     }
466
467   return offset;
468 }
469
470 /*--- dissect_qsig_err ------------------------------------------------------*/
471 static int   
472 dissect_qsig_err(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
473   int offset;
474   rose_ctx_t *rctx;
475   gint32 errcode;
476   const qsig_err_t *err_ptr;
477   const gchar *p;
478   proto_item *ti;
479   proto_tree *qsig_tree;
480
481   offset = 0;
482   rctx = get_rose_ctx(pinfo->private_data);
483   DISSECTOR_ASSERT(rctx);
484   if (rctx->d.pdu != 3)  /* returnError */
485     return offset; 
486   if (rctx->d.code != 0)  /* local */
487     return offset; 
488   errcode = rctx->d.code_local;
489   err_ptr = get_err(errcode);
490   if (!err_ptr)
491     return offset; 
492
493   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
494   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
495
496   proto_tree_add_uint(qsig_tree, hf_qsig_error, tvb, 0, 0, errcode);
497   p = match_strval(errcode, VALS(qsig_str_error));
498   if (p) {
499     proto_item_append_text(ti, ": %s", p);
500     proto_item_append_text(rctx->d.code_item, " - %s", p);
501     if (rctx->apdu_depth >= 0)
502       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
503   }
504
505   if (err_ptr->err_pdu)
506     offset = err_ptr->err_pdu(tvb, pinfo, qsig_tree);
507   else 
508     if (tvb_length_remaining(tvb, offset) > 0) {
509       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ERROR TYPE (QSIG)");
510       offset += tvb_length_remaining(tvb, offset);
511     }
512
513   return offset;
514 }
515
516 /*--- dissect_qsig_transit_counter_ie ---------------------------------------*/
517 static int
518 dissect_qsig_transit_counter_ie(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int length  _U_) {
519   proto_tree_add_item(tree, hf_qsig_tc, tvb, offset, 1, FALSE);
520   offset++;
521   return offset;
522 }
523 /*--- dissect_qsig_party_category_ie ----------------------------------------*/
524 static int 
525 dissect_qsig_party_category_ie(tvbuff_t *tvb, int offset, packet_info *pinfo  _U_, proto_tree *tree, int length  _U_) {
526   proto_tree_add_item(tree, hf_qsig_pc, tvb, offset, 1, FALSE);
527   offset++;
528   return offset;
529 }
530
531 /*--- dissect_qsig_ie -------------------------------------------------------*/
532 static void
533 dissect_qsig_ie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int codeset) {
534   gint offset;
535   proto_item *ti, *ti_ie, *hidden_item;
536   proto_tree *ie_tree;
537   guint8 ie_type, ie_len;
538
539   offset = 0;
540
541   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, -1, FALSE);
542   PROTO_ITEM_SET_HIDDEN(ti);
543
544   ie_type = tvb_get_guint8(tvb, offset);
545   ie_len = tvb_get_guint8(tvb, offset + 1);
546
547   ti_ie = proto_tree_add_text(tree, tvb, offset, -1, "%s",
548             val_to_str(ie_type, VALS(qsig_str_ie_type[codeset]), "unknown (0x%02X)"));
549   ie_tree = proto_item_add_subtree(ti_ie, ett_qsig_ie); 
550   proto_tree_add_item(ie_tree, *hf_qsig_ie_type_arr[codeset], tvb, offset, 1, FALSE);
551   hidden_item = proto_tree_add_item(ie_tree, hf_qsig_ie_type, tvb, offset, 1, FALSE);
552   PROTO_ITEM_SET_HIDDEN(hidden_item);
553   proto_tree_add_item(ie_tree, hf_qsig_ie_len, tvb, offset + 1, 1, FALSE);
554   offset += 2;
555   if (tvb_length_remaining(tvb, offset) <= 0)
556     return;
557   switch ((codeset << 8) | ie_type) {
558     case CS4 | QSIG_IE_TRANSIT_COUNTER :
559       dissect_qsig_transit_counter_ie(tvb, offset, pinfo, ie_tree, ie_len);
560       break;
561     case CS5 | QSIG_IE_PARTY_CATEGORY :
562       dissect_qsig_party_category_ie(tvb, offset, pinfo, ie_tree, ie_len);
563       break;
564     default:
565       if (ie_len > 0) {
566         if (tree) proto_tree_add_item(ie_tree, hf_qsig_ie_data, tvb, offset, ie_len, FALSE);
567       }
568   }
569 }
570 /*--- dissect_qsig_ie_cs4 ---------------------------------------------------*/
571 static void
572 dissect_qsig_ie_cs4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
573   dissect_qsig_ie(tvb, pinfo, tree, 4);
574 }
575 /*--- dissect_qsig_ie_cs5 ---------------------------------------------------*/
576 static void
577 dissect_qsig_ie_cs5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
578   dissect_qsig_ie(tvb, pinfo, tree, 5);
579 }
580
581 /*--- proto_register_qsig ---------------------------------------------------*/
582 void proto_register_qsig(void) {
583
584   /* List of fields */
585   static hf_register_info hf[] = {
586     { &hf_qsig_operation, { "Operation", "qsig.operation",
587                            FT_UINT8, BASE_DEC, VALS(qsig_str_operation), 0x0,
588                            "Operation", HFILL }},
589     { &hf_qsig_service,   { "Service", "qsig.service",
590                            FT_UINT8, BASE_DEC, VALS(qsig_str_service), 0x0,
591                            "Supplementary Service", HFILL }},
592     { &hf_qsig_error,     { "Error", "qsig.error",
593                            FT_UINT8, BASE_DEC, VALS(qsig_str_error), 0x0,
594                            "Error", HFILL }},
595     { &hf_qsig_ie_type, { "Type", "qsig.ie.type",
596                           FT_UINT8, BASE_HEX, NULL, 0x0,
597                           "Information Element Type", HFILL }},
598     { &hf_qsig_ie_type_cs4, { "Type", "qsig.ie.type.cs4",
599                           FT_UINT8, BASE_HEX, VALS(qsig_str_ie_type_cs4), 0x0,
600                           "Information Element Type (Codeset 4)", HFILL }},
601     { &hf_qsig_ie_type_cs5, { "Type", "qsig.ie.type.cs5",
602                           FT_UINT8, BASE_HEX, VALS(qsig_str_ie_type_cs5), 0x0,
603                           "Information Element Type (Codeset 5)", HFILL }},
604     { &hf_qsig_ie_len,  { "Length", "qsig.ie.len",
605                           FT_UINT8, BASE_DEC, NULL, 0x0,
606                           "Information Element Length", HFILL }},
607     { &hf_qsig_ie_data, { "Data", "qsig.ie.data",
608                           FT_BYTES, BASE_HEX, NULL, 0x0,
609                           "Data", HFILL }},
610     { &hf_qsig_tc,      { "Transit count", "qsig.tc",
611                           FT_UINT8, BASE_DEC, NULL, 0x1F,
612                           "Transit count", HFILL }},
613     { &hf_qsig_pc,      { "Party category", "qsig.pc",
614                           FT_UINT8, BASE_HEX, VALS(qsig_str_pc), 0x07,
615                           "Party category", HFILL }},
616 #include "packet-qsig-hfarr.c"
617   };
618
619   /* List of subtrees */
620   static gint *ett[] = {
621     &ett_qsig,
622     &ett_qsig_ie,
623     &ett_qsig_unknown_extension,
624 #include "packet-qsig-ettarr.c"
625   };
626
627   /* Register protocol and dissector */
628   proto_qsig = proto_register_protocol(PNAME, PSNAME, PFNAME);
629
630   /* Register fields and subtrees */
631   proto_register_field_array(proto_qsig, hf, array_length(hf));
632   proto_register_subtree_array(ett, array_length(ett));
633
634   /* Register dissector tables */
635   extension_dissector_table = register_dissector_table("qsig.ext", "QSIG Extension", FT_STRING, BASE_NONE);
636 }
637
638
639 /*--- proto_reg_handoff_qsig ------------------------------------------------*/
640 void proto_reg_handoff_qsig(void) {
641   int i;
642   dissector_handle_t q931_handle; 
643   dissector_handle_t qsig_arg_handle;
644   dissector_handle_t qsig_res_handle;
645   dissector_handle_t qsig_err_handle;
646   dissector_handle_t qsig_ie_handle;
647
648   q931_handle = find_dissector("q931");
649
650   qsig_arg_handle = new_create_dissector_handle(dissect_qsig_arg, proto_qsig);
651   qsig_res_handle = new_create_dissector_handle(dissect_qsig_res, proto_qsig);
652   for (i=0; i<(int)array_length(qsig_op_tab); i++) {
653     dissector_add("q932.ros.local.arg", qsig_op_tab[i].opcode, qsig_arg_handle);
654     dissector_add("q932.ros.local.res", qsig_op_tab[i].opcode, qsig_res_handle);
655   }
656   qsig_err_handle = new_create_dissector_handle(dissect_qsig_err, proto_qsig);
657   for (i=0; i<(int)array_length(qsig_err_tab); i++) {
658     dissector_add("q932.ros.local.err", qsig_err_tab[i].errcode, qsig_err_handle);
659   }
660
661   qsig_ie_handle = create_dissector_handle(dissect_qsig_ie_cs4, proto_qsig);
662   /* QSIG-TC - Transit counter */
663   dissector_add("q931.ie", CS4 | QSIG_IE_TRANSIT_COUNTER, qsig_ie_handle);
664
665   qsig_ie_handle = create_dissector_handle(dissect_qsig_ie_cs5, proto_qsig);
666   /* SSIG-BC - Party category */
667   dissector_add("q931.ie", CS5 | QSIG_IE_PARTY_CATEGORY, qsig_ie_handle);
668
669   /* RFC 3204, 3.2 QSIG Media Type */
670   dissector_add_string("media_type", "application/qsig", q931_handle);
671
672 }
673
674 /*---------------------------------------------------------------------------*/