QSIG fully implemented
[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 #include "packet-qsig-ett.c"
311
312 /* Preferences */
313
314 /* Subdissectors */
315 static dissector_handle_t data_handle = NULL; 
316
317 /* Gloabl variables */
318
319
320 #include "packet-qsig-fn.c"
321
322 typedef struct _qsig_op_t {
323   gint32 opcode;
324   new_dissector_t arg_pdu;
325   new_dissector_t res_pdu;
326 } qsig_op_t;
327
328 static const qsig_op_t qsig_op_tab[] = {
329 #include "packet-qsig-table11.c"
330 };                                 
331
332 typedef struct _qsig_err_t {
333   gint32 errcode;
334   new_dissector_t err_pdu;
335 } qsig_err_t;
336
337 static const qsig_err_t qsig_err_tab[] = {
338 #include "packet-qsig-table21.c"
339 };                                 
340
341 static const qsig_op_t *get_op(gint32 opcode) {
342   int i;
343
344   /* search from the end to get the last occurence if the operation is redefined in some newer specification */
345   for (i = array_length(qsig_op_tab) - 1; i >= 0; i--)
346     if (qsig_op_tab[i].opcode == opcode)
347       return &qsig_op_tab[i];
348   return NULL;
349 }
350
351 static gint32 get_service(gint32 opcode) {
352   if ((opcode < 0) || (opcode >= (int)array_length(op2srv_tab)))
353     return NO_SRV;
354   return op2srv_tab[opcode];
355 }
356
357 static const qsig_err_t *get_err(gint32 errcode) {
358   int i;
359
360   /* search from the end to get the last occurence if the operation is redefined in some newer specification */
361   for (i = array_length(qsig_err_tab) - 1; i >= 0; i--)
362     if (qsig_err_tab[i].errcode == errcode)
363       return &qsig_err_tab[i];
364   return NULL;
365 }
366                   
367 /*--- dissect_qsig_arg ------------------------------------------------------*/
368 static int   
369 dissect_qsig_arg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
370   int offset;
371   rose_ctx_t *rctx;
372   gint32 opcode, service;
373   const qsig_op_t *op_ptr;
374   const gchar *p;
375   proto_item *ti, *ti_tmp;
376   proto_tree *qsig_tree;
377
378   offset = 0;
379   rctx = get_rose_ctx(pinfo->private_data);
380   DISSECTOR_ASSERT(rctx);
381   if (rctx->d.pdu != 1)  /* invoke */
382     return offset; 
383   if (rctx->d.code != 0)  /* local */
384     return offset; 
385   opcode = rctx->d.code_local;
386   op_ptr = get_op(opcode);
387   if (!op_ptr)
388     return offset; 
389   service = get_service(opcode);
390
391   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
392   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
393
394   proto_tree_add_uint(qsig_tree, hf_qsig_operation, tvb, 0, 0, opcode);
395   p = match_strval(opcode, VALS(qsig_str_operation));
396   if (p) {
397     proto_item_append_text(ti, ": %s", p);
398     proto_item_append_text(rctx->d.code_item, " - %s", p);
399     if (rctx->apdu_depth >= 0)
400       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
401   }
402
403   ti_tmp = proto_tree_add_uint(qsig_tree, hf_qsig_service, tvb, 0, 0, service);
404   p = match_strval(service, VALS(qsig_str_service_name));
405   if (p) proto_item_append_text(ti_tmp, " - %s", p);
406
407   if (op_ptr->arg_pdu)
408     offset = op_ptr->arg_pdu(tvb, pinfo, qsig_tree);
409   else 
410     if (tvb_length_remaining(tvb, offset) > 0) {
411       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ARGUMENT TYPE (QSIG)");
412       offset += tvb_length_remaining(tvb, offset);
413     }
414
415   return offset;
416 }
417
418 /*--- dissect_qsig_res -------------------------------------------------------*/
419 static int
420 dissect_qsig_res(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
421   gint offset;
422   rose_ctx_t *rctx;
423   gint32 opcode, service;
424   const qsig_op_t *op_ptr;
425   const gchar *p;
426   proto_item *ti, *ti_tmp;
427   proto_tree *qsig_tree;
428
429   offset = 0;
430   rctx = get_rose_ctx(pinfo->private_data);
431   DISSECTOR_ASSERT(rctx);
432   if (rctx->d.pdu != 2)  /* returnResult */
433     return offset; 
434   if (rctx->d.code != 0)  /* local */
435     return offset; 
436   opcode = rctx->d.code_local;
437   op_ptr = get_op(opcode);
438   if (!op_ptr)
439     return offset; 
440   service = get_service(opcode);
441
442   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
443   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
444
445   proto_tree_add_uint(qsig_tree, hf_qsig_operation, tvb, 0, 0, opcode);
446   p = match_strval(opcode, VALS(qsig_str_operation));
447   if (p) {
448     proto_item_append_text(ti, ": %s", p);
449     proto_item_append_text(rctx->d.code_item, " - %s", p);
450     if (rctx->apdu_depth >= 0)
451       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
452   }
453
454   ti_tmp = proto_tree_add_uint(qsig_tree, hf_qsig_service, tvb, 0, 0, service);
455   p = match_strval(service, VALS(qsig_str_service_name));
456   if (p) proto_item_append_text(ti_tmp, " - %s", p);
457
458   if (op_ptr->res_pdu)
459     offset = op_ptr->res_pdu(tvb, pinfo, qsig_tree);
460   else 
461     if (tvb_length_remaining(tvb, offset) > 0) {
462       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED RESULT TYPE (QSIG)");
463       offset += tvb_length_remaining(tvb, offset);
464     }
465
466   return offset;
467 }
468
469 /*--- dissect_qsig_err ------------------------------------------------------*/
470 static int   
471 dissect_qsig_err(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
472   int offset;
473   rose_ctx_t *rctx;
474   gint32 errcode;
475   const qsig_err_t *err_ptr;
476   const gchar *p;
477   proto_item *ti;
478   proto_tree *qsig_tree;
479
480   offset = 0;
481   rctx = get_rose_ctx(pinfo->private_data);
482   DISSECTOR_ASSERT(rctx);
483   if (rctx->d.pdu != 3)  /* returnError */
484     return offset; 
485   if (rctx->d.code != 0)  /* local */
486     return offset; 
487   errcode = rctx->d.code_local;
488   err_ptr = get_err(errcode);
489   if (!err_ptr)
490     return offset; 
491
492   ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), FALSE);
493   qsig_tree = proto_item_add_subtree(ti, ett_qsig); 
494
495   proto_tree_add_uint(qsig_tree, hf_qsig_error, tvb, 0, 0, errcode);
496   p = match_strval(errcode, VALS(qsig_str_error));
497   if (p) {
498     proto_item_append_text(ti, ": %s", p);
499     proto_item_append_text(rctx->d.code_item, " - %s", p);
500     if (rctx->apdu_depth >= 0)
501       proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p);
502   }
503
504   if (err_ptr->err_pdu)
505     offset = err_ptr->err_pdu(tvb, pinfo, qsig_tree);
506   else 
507     if (tvb_length_remaining(tvb, offset) > 0) {
508       proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ERROR TYPE (QSIG)");
509       offset += tvb_length_remaining(tvb, offset);
510     }
511
512   return offset;
513 }
514
515 /*--- dissect_qsig_transit_counter_ie ---------------------------------------*/
516 static int
517 dissect_qsig_transit_counter_ie(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int length  _U_) {
518   proto_tree_add_item(tree, hf_qsig_tc, tvb, offset, 1, FALSE);
519   offset++;
520   return offset;
521 }
522 /*--- dissect_qsig_party_category_ie ----------------------------------------*/
523 static int 
524 dissect_qsig_party_category_ie(tvbuff_t *tvb, int offset, packet_info *pinfo  _U_, proto_tree *tree, int length  _U_) {
525   proto_tree_add_item(tree, hf_qsig_pc, tvb, offset, 1, FALSE);
526   offset++;
527   return offset;
528 }
529
530 /*--- dissect_qsig_ie -------------------------------------------------------*/
531 static void
532 dissect_qsig_ie(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int codeset) {
533   gint offset;
534   proto_item *ti, *ti_ie;
535   proto_tree *ie_tree;
536   guint8 ie_type, ie_len;
537
538   offset = 0;
539
540   ti = proto_tree_add_item_hidden(tree, proto_qsig, tvb, offset, -1, FALSE);
541
542   ie_type = tvb_get_guint8(tvb, offset);
543   ie_len = tvb_get_guint8(tvb, offset + 1);
544
545   ti_ie = proto_tree_add_text(tree, tvb, offset, -1, "%s",
546             val_to_str(ie_type, VALS(qsig_str_ie_type[codeset]), "unknown (0x%02X)"));
547   ie_tree = proto_item_add_subtree(ti_ie, ett_qsig_ie); 
548   proto_tree_add_item(ie_tree, *hf_qsig_ie_type_arr[codeset], tvb, offset, 1, FALSE);
549   proto_tree_add_item_hidden(ie_tree, hf_qsig_ie_type, tvb, offset, 1, FALSE);
550   proto_tree_add_item(ie_tree, hf_qsig_ie_len, tvb, offset + 1, 1, FALSE);
551   offset += 2;
552   if (tvb_length_remaining(tvb, offset) <= 0)
553     return;
554   switch ((codeset << 8) | ie_type) {
555     case CS4 | QSIG_IE_TRANSIT_COUNTER :
556       dissect_qsig_transit_counter_ie(tvb, offset, pinfo, ie_tree, ie_len);
557       break;
558     case CS5 | QSIG_IE_PARTY_CATEGORY :
559       dissect_qsig_party_category_ie(tvb, offset, pinfo, ie_tree, ie_len);
560       break;
561     default:
562       if (ie_len > 0) {
563         if (tree) proto_tree_add_item(ie_tree, hf_qsig_ie_data, tvb, offset, ie_len, FALSE);
564       }
565   }
566 }
567 /*--- dissect_qsig_ie_cs4 ---------------------------------------------------*/
568 static void
569 dissect_qsig_ie_cs4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
570   dissect_qsig_ie(tvb, pinfo, tree, 4);
571 }
572 /*--- dissect_qsig_ie_cs5 ---------------------------------------------------*/
573 static void
574 dissect_qsig_ie_cs5(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
575   dissect_qsig_ie(tvb, pinfo, tree, 5);
576 }
577
578 /*--- proto_register_qsig ---------------------------------------------------*/
579 void proto_register_qsig(void) {
580
581   /* List of fields */
582   static hf_register_info hf[] = {
583     { &hf_qsig_operation, { "Operation", "qsig.operation",
584                            FT_UINT8, BASE_DEC, VALS(qsig_str_operation), 0x0,
585                            "Operation", HFILL }},
586     { &hf_qsig_service,   { "Service", "qsig.service",
587                            FT_UINT8, BASE_DEC, VALS(qsig_str_service), 0x0,
588                            "Supplementary Service", HFILL }},
589     { &hf_qsig_error,     { "Error", "qsig.error",
590                            FT_UINT8, BASE_DEC, VALS(qsig_str_error), 0x0,
591                            "Error", HFILL }},
592     { &hf_qsig_ie_type, { "Type", "qsig.ie.type",
593                           FT_UINT8, BASE_HEX, NULL, 0x0,
594                           "Information Element Type", HFILL }},
595     { &hf_qsig_ie_type_cs4, { "Type", "qsig.ie.type.cs4",
596                           FT_UINT8, BASE_HEX, VALS(qsig_str_ie_type_cs4), 0x0,
597                           "Information Element Type (Codeset 4)", HFILL }},
598     { &hf_qsig_ie_type_cs5, { "Type", "qsig.ie.type.cs5",
599                           FT_UINT8, BASE_HEX, VALS(qsig_str_ie_type_cs5), 0x0,
600                           "Information Element Type (Codeset 5)", HFILL }},
601     { &hf_qsig_ie_len,  { "Length", "qsig.ie.len",
602                           FT_UINT8, BASE_DEC, NULL, 0x0,
603                           "Information Element Length", HFILL }},
604     { &hf_qsig_ie_data, { "Data", "qsig.ie.data",
605                           FT_BYTES, BASE_HEX, NULL, 0x0,
606                           "Data", HFILL }},
607     { &hf_qsig_tc,      { "Transit count", "qsig.tc",
608                           FT_UINT8, BASE_DEC, NULL, 0x1F,
609                           "Transit count", HFILL }},
610     { &hf_qsig_pc,      { "Party category", "qsig.pc",
611                           FT_UINT8, BASE_HEX, VALS(qsig_str_pc), 0x07,
612                           "Party category", HFILL }},
613 #include "packet-qsig-hfarr.c"
614   };
615
616   /* List of subtrees */
617   static gint *ett[] = {
618     &ett_qsig,
619     &ett_qsig_ie,
620 #include "packet-qsig-ettarr.c"
621   };
622
623   /* Register protocol and dissector */
624   proto_qsig = proto_register_protocol(PNAME, PSNAME, PFNAME);
625
626   /* Register fields and subtrees */
627   proto_register_field_array(proto_qsig, hf, array_length(hf));
628   proto_register_subtree_array(ett, array_length(ett));
629
630 }
631
632
633 /*--- proto_reg_handoff_qsig ------------------------------------------------*/
634 void proto_reg_handoff_qsig(void) {
635   int i;
636   dissector_handle_t qsig_arg_handle;
637   dissector_handle_t qsig_res_handle;
638   dissector_handle_t qsig_err_handle;
639   dissector_handle_t qsig_ie_handle;
640
641   data_handle = find_dissector("data");
642
643   qsig_arg_handle = new_create_dissector_handle(dissect_qsig_arg, proto_qsig);
644   qsig_res_handle = new_create_dissector_handle(dissect_qsig_res, proto_qsig);
645   for (i=0; i<(int)array_length(qsig_op_tab); i++) {
646     dissector_add("q932.ros.local.arg", qsig_op_tab[i].opcode, qsig_arg_handle);
647     dissector_add("q932.ros.local.res", qsig_op_tab[i].opcode, qsig_res_handle);
648   }
649   qsig_err_handle = new_create_dissector_handle(dissect_qsig_err, proto_qsig);
650   for (i=0; i<(int)array_length(qsig_err_tab); i++) {
651     dissector_add("q932.ros.local.err", qsig_err_tab[i].errcode, qsig_err_handle);
652   }
653
654   qsig_ie_handle = create_dissector_handle(dissect_qsig_ie_cs4, proto_qsig);
655   /* QSIG-TC - Transit counter */
656   dissector_add("q931.ie", CS4 | QSIG_IE_TRANSIT_COUNTER, qsig_ie_handle);
657
658   qsig_ie_handle = create_dissector_handle(dissect_qsig_ie_cs5, proto_qsig);
659   /* SSIG-BC - Party category */
660   dissector_add("q931.ie", CS5 | QSIG_IE_PARTY_CATEGORY, qsig_ie_handle);
661
662 }
663
664 /*---------------------------------------------------------------------------*/