Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-meta.c
1 /* Routines for 'Metadata' disassembly
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include <glib.h>
27
28 #include <epan/packet.h>
29 #include <wiretap/wtap.h>
30 #include <epan/expert.h>
31 #include <epan/wmem/wmem.h>
32
33 #include "packet-sscop.h"
34 #include "packet-gsm_a_common.h"
35
36 void proto_register_meta(void);
37 void proto_reg_handoff_meta(void);
38
39 /* schemas */
40 #define META_SCHEMA_PCAP        1
41 #define META_SCHEMA_DXT         2
42
43 /* protocols */
44 #define META_PROTO_DXT_ETHERNET        1
45 #define META_PROTO_DXT_ETHERNET_CRC   36
46 #define META_PROTO_DXT_ATM            41
47 #define META_PROTO_DXT_ERF_AAL5       49
48 #define META_PROTO_DXT_M3UA           61
49 #define META_PROTO_DXT_NBAP           69
50 #define META_PROTO_DXT_ATM_AAL2       76
51 #define META_PROTO_DXT_FP_HINT        82
52 #define META_PROTO_DXT_HDLC          106
53 #define META_PROTO_DXT_CONTAINER     127
54 #define META_PROTO_DXT_FP_CAPTURE    193
55 #define META_PROTO_DXT_UTRAN_CAPSULE 194
56
57 /* data types */
58 #define META_TYPE_NONE             0
59 #define META_TYPE_BOOLEAN          1
60 #define META_TYPE_UINT8            2
61 #define META_TYPE_UINT16           3
62 #define META_TYPE_UINT32           4
63 #define META_TYPE_UINT64           5
64 #define META_TYPE_STRING          16
65
66 /* item ids */
67 #define META_ID_NULL               0
68 #define META_ID_DIRECTION          1
69 #define META_ID_SIGNALING          2
70 #define META_ID_INCOMPLETE         3
71 #define META_ID_DECIPHERED         4
72 #define META_ID_PAYLOADCUT         5
73 #define META_ID_TIMESTAMP64        6
74 #define META_ID_AAL5PROTO          7
75 #define META_ID_PHYLINKID        256
76 #define META_ID_LOCALDEVID       257
77 #define META_ID_REMOTEDEVID      258
78 #define META_ID_TAPGROUPID       259
79 #define META_ID_IMSI            1024
80 #define META_ID_IMEI            1025
81 #define META_ID_CELL            1026
82 #define META_ID_TLLI            1027
83 #define META_ID_NSAPI           1028
84 #define META_ID_APN             1029
85 #define META_ID_RAT             1030
86 #define META_ID_CALLING         1031
87 #define META_ID_CALLED          1032
88
89 enum meta_direction {
90     META_DIR_UP,
91     META_DIR_DOWN
92 };
93
94 static int proto_meta = -1;
95 extern int proto_sscop;
96
97 /* fields */
98 static int hf_meta_schema = -1;
99 static int hf_meta_hdrlen = -1;
100 static int hf_meta_proto = -1;
101 static int hf_meta_reserved = -1;
102 static int hf_meta_item = -1;
103 static int hf_meta_item_id = -1;
104 static int hf_meta_item_type = -1;
105 static int hf_meta_item_len = -1;
106 static int hf_meta_item_data = -1;
107 /* specific fields */
108 static int hf_meta_item_direction = -1;
109 static int hf_meta_item_ts = -1;
110 static int hf_meta_item_phylinkid = -1;
111 static int hf_meta_item_nsapi = -1;
112 static int hf_meta_item_imsi_value = -1;
113 static int hf_meta_item_imsi_digits = -1;
114 static int hf_meta_item_imei_value = -1;
115 static int hf_meta_item_imei_digits = -1;
116 static int hf_meta_item_signaling = -1;
117 static int hf_meta_item_incomplete = -1;
118 static int hf_meta_item_deciphered = -1;
119 static int hf_meta_item_apn = -1;
120 static int hf_meta_item_rat = -1;
121 static int hf_meta_item_aal5proto = -1;
122 static int hf_meta_item_cell = -1;
123 static int hf_meta_item_localdevid = -1;
124 static int hf_meta_item_remotedevid = -1;
125 static int hf_meta_item_tapgroupid = -1;
126 static int hf_meta_item_tlli = -1;
127 static int hf_meta_item_calling = -1;
128 static int hf_meta_item_called = -1;
129
130 /* subtrees */
131 static gint ett_meta = -1;
132 static gint ett_meta_item = -1;
133 static gint ett_meta_cell = -1;
134 static gint ett_meta_imsi = -1;
135 static gint ett_meta_imei = -1;
136
137 static expert_field ei_meta_malformed = EI_INIT;
138 static expert_field ei_meta_invalid_header = EI_INIT;
139
140 /* default handle */
141 static dissector_handle_t data_handle;
142 static dissector_handle_t atm_untrunc_handle;
143 static dissector_handle_t sscf_nni_handle;
144 static dissector_handle_t alcap_handle;
145 static dissector_handle_t nbap_handle;
146 static dissector_handle_t ethwithfcs_handle;
147 static dissector_handle_t ethwithoutfcs_handle;
148 static dissector_handle_t fphint_handle;
149 static dissector_handle_t mtp2_handle;
150
151 static dissector_table_t meta_dissector_table;
152
153 static const value_string meta_schema_vals[] = {
154     { META_SCHEMA_PCAP,     "PCAP" },
155     { META_SCHEMA_DXT,      "DXT" },
156     { 0, NULL }
157 };
158
159 static const value_string meta_proto_vals[] = {
160     { META_PROTO_DXT_ETHERNET,      "Ethernet without FCS" },
161     { META_PROTO_DXT_ETHERNET_CRC,  "Ethernet with FCS" },
162     { META_PROTO_DXT_ATM,           "ATM" },
163     { META_PROTO_DXT_ERF_AAL5,      "ERF AAL5" },
164     /* XXX: META_PROTO_DXT_M3UA ? */
165     /* XXX: META_PROTO_DXT_NBAP ? */
166     { META_PROTO_DXT_ATM_AAL2,      "ATM AAL2" },
167     { META_PROTO_DXT_FP_HINT,       "FP Hint" },
168     { META_PROTO_DXT_HDLC,          "HDLC" },
169     { META_PROTO_DXT_CONTAINER,     "DXT CONTAINER" },
170     { META_PROTO_DXT_FP_CAPTURE,    "FP CAPTURE" },
171     { META_PROTO_DXT_UTRAN_CAPSULE, "UTRAN CAPSULE" },
172     { 0, NULL }
173 };
174 static value_string_ext meta_proto_vals_ext = VALUE_STRING_EXT_INIT(meta_proto_vals);
175
176 static const value_string meta_type_vals[] = {
177     { META_TYPE_NONE,       "NONE" },
178     { META_TYPE_BOOLEAN,    "BOOLEAN" },
179     { META_TYPE_UINT8,      "UINT8" },
180     { META_TYPE_UINT16,     "UINT16" },
181     { META_TYPE_UINT32,     "UINT32" },
182     { META_TYPE_UINT64,     "UINT64" },
183     { META_TYPE_STRING,     "STRING" },
184     { 0, NULL }
185 };
186
187 /* TODO: this must be on a per-schema basis! */
188 static const value_string meta_id_vals[] = {
189     { META_ID_NULL,         "NULL" },
190     { META_ID_DIRECTION,    "Direction" },
191     { META_ID_SIGNALING,    "Signaling" },
192     { META_ID_INCOMPLETE,   "Incomplete" },
193     { META_ID_DECIPHERED,   "Deciphered" },
194     { META_ID_PAYLOADCUT,   "Payload cutted" },
195     { META_ID_TIMESTAMP64,  "Timestamp" },
196     { META_ID_AAL5PROTO,    "AAL5 Protocol Type" },
197     { META_ID_PHYLINKID,    "Physical Link ID" },
198     { META_ID_LOCALDEVID,   "Local Device ID" },
199     { META_ID_REMOTEDEVID,  "Remote Device ID" },
200     { META_ID_TAPGROUPID,   "Tap Group ID" },
201     { META_ID_IMSI,         "IMSI" },
202     { META_ID_IMEI,         "IMEI" },
203     { META_ID_CELL,         "Mobile Cell" },
204     { META_ID_TLLI,         "TLLI" },
205     { META_ID_NSAPI,        "NSAPI" },
206     { META_ID_APN,          "APN" },
207     { META_ID_RAT,          "RAT" },
208     { META_ID_CALLING,      "Calling Station ID" },
209     { META_ID_CALLED,       "Called Station ID" },
210     { 0, NULL }
211 };
212 static value_string_ext meta_id_vals_ext = VALUE_STRING_EXT_INIT(meta_id_vals);
213
214 #define META_AAL5PROTO_MTP3     2
215 #define META_AAL5PROTO_NS       3
216 #define META_AAL5PROTO_ALCAP    5
217 #define META_AAL5PROTO_NBAP     6
218 static const value_string meta_aal5proto_vals[] = {
219     { META_AAL5PROTO_MTP3,  "SSCOP MTP3" },
220     { META_AAL5PROTO_ALCAP, "SSCOP ALCAP" },
221     { META_AAL5PROTO_NBAP,  "SSCOP NBAP" },
222     { META_AAL5PROTO_NS,    "GPRS NS" },
223     { 0, NULL }
224 };
225
226 static const value_string meta_direction_vals[] = {
227     { 0,    "Up" },
228     { 1,    "Down" },
229     { 0,    NULL }
230 };
231
232 static guint16 skip_item(proto_tree *meta_tree, tvbuff_t *tvb, packet_info *pinfo _U_, guint16 offs)
233 {
234     guint16     id;
235     guint8      type;
236     guint16     len, aligned_len, total_len;
237     proto_tree *item_tree;
238     proto_item *subti;
239
240     id          = tvb_get_letohs(tvb, offs); offs += 2;
241     type        = tvb_get_guint8(tvb, offs); offs++;
242     len         = tvb_get_guint8(tvb, offs); offs++;
243     aligned_len = (len + 3) & 0xfffc;
244     total_len   = aligned_len + 4; /* 4: id, type, len fields */
245
246     subti = proto_tree_add_item(meta_tree, hf_meta_item, tvb, offs - 4,
247         aligned_len + 4, ENC_NA);
248     item_tree = proto_item_add_subtree(subti, ett_meta_item);
249     proto_tree_add_uint(item_tree, hf_meta_item_id, tvb, offs - 4, 2, id);
250     proto_tree_add_uint(item_tree, hf_meta_item_type, tvb, offs - 2, 1, type);
251     proto_tree_add_uint(item_tree, hf_meta_item_len,
252         tvb, offs - 1, 1, len);
253     if (len > 0)
254         proto_tree_add_item(item_tree, hf_meta_item_data,
255             tvb, offs, len, ENC_NA);
256
257     return total_len;
258 }
259
260 /*
261 * offs: current offset in tvb
262 */
263 static guint16 evaluate_meta_item_pcap(proto_tree *meta_tree, tvbuff_t *tvb, packet_info *pinfo, guint16 offs)
264 {
265     guint16     id;
266     guint8      type;
267     guint16     len, aligned_len, total_len;
268     proto_tree *item_tree;
269     proto_item *subti;
270     /* field values */
271     guint8      dir;
272     guint64     ts;
273
274     id          = tvb_get_letohs(tvb, offs); offs += 2;
275     type        = tvb_get_guint8(tvb, offs); offs++;
276     len         = tvb_get_guint8(tvb, offs); offs++;
277     aligned_len = (len + 3) & 0xfffc;
278     total_len   = aligned_len + 4; /* 4: id, type, len fields */
279
280     switch (id) {
281         case META_ID_DIRECTION:
282             dir = tvb_get_guint8(tvb, offs);
283             pinfo->p2p_dir = dir == META_DIR_UP ? P2P_DIR_RECV : P2P_DIR_SENT;
284             proto_tree_add_uint(meta_tree, hf_meta_item_direction, tvb, offs, 1, dir);
285             break;
286         case META_ID_TIMESTAMP64:
287             ts = tvb_get_letoh64(tvb, offs);
288             proto_tree_add_uint64(meta_tree, hf_meta_item_ts, tvb, offs, 8, ts);
289             break;
290         case META_ID_SIGNALING:
291             proto_tree_add_boolean(meta_tree, hf_meta_item_signaling, tvb,
292                 offs, 0, 1);
293             break;
294         case META_ID_INCOMPLETE:
295             proto_tree_add_boolean(meta_tree, hf_meta_item_incomplete, tvb,
296                 offs, 0, 1);
297             break;
298         default:
299             subti = proto_tree_add_item(meta_tree, hf_meta_item, tvb, offs - 4,
300                 aligned_len + 4, ENC_NA);
301             item_tree = proto_item_add_subtree(subti, ett_meta_item);
302             proto_tree_add_uint(item_tree, hf_meta_item_id, tvb, offs - 4, 2, id);
303             proto_tree_add_uint(item_tree, hf_meta_item_type, tvb, offs - 2, 1, type);
304             proto_tree_add_uint(item_tree, hf_meta_item_len,
305                 tvb, offs - 1, 1, len);
306             if (len > 0)
307                 proto_tree_add_item(item_tree, hf_meta_item_data,
308                     tvb, offs, len, ENC_NA);
309     }
310     return total_len;
311 }
312
313 /*
314 * offs: current offset in tvb
315 */
316 static guint16 evaluate_meta_item_dxt(proto_tree *meta_tree, tvbuff_t *tvb, packet_info *pinfo, guint16 offs)
317 {
318     guint16             id;
319     guint8              type;
320     guint16             len, aligned_len, total_len;
321     proto_tree         *item_tree;
322     proto_item         *subti;
323     /* field values */
324     guint8              dir, nsapi, rat, aal5proto;
325     guint16             phylinkid, localdevid, remotedevid, tapgroupid;
326     guint32             tlli;
327     guint64             ts, imsi, imei, cell;
328     sscop_payload_info *p_sscop_info;
329     const gchar        *imsi_str, *imei_str;
330     proto_item         *cell_item, *imsi_item, *imei_item;
331     proto_tree         *cell_tree, *imsi_tree, *imei_tree;
332
333     id          = tvb_get_letohs(tvb, offs); offs += 2;
334     type        = tvb_get_guint8(tvb, offs); offs++;
335     len         = tvb_get_guint8(tvb, offs); offs++;
336     aligned_len = (len + 3) & 0xfffc;
337     total_len   = aligned_len + 4; /* 4: id, type, len fields */
338
339     switch (id) {
340         case META_ID_DIRECTION:
341             dir = tvb_get_guint8(tvb, offs);
342             pinfo->p2p_dir = (dir == META_DIR_UP ? P2P_DIR_RECV : P2P_DIR_SENT);
343             proto_tree_add_uint(meta_tree, hf_meta_item_direction, tvb, offs, 1, dir);
344             break;
345         case META_ID_TIMESTAMP64:
346             ts = tvb_get_letoh64(tvb, offs);
347             proto_tree_add_uint64(meta_tree, hf_meta_item_ts, tvb, offs, 8, ts);
348             break;
349         case META_ID_PHYLINKID:
350             phylinkid = tvb_get_letohs(tvb, offs);
351             pinfo->link_number = phylinkid;
352             proto_tree_add_uint(meta_tree, hf_meta_item_phylinkid, tvb,
353                 offs, 2, phylinkid);
354             break;
355         case META_ID_NSAPI:
356             nsapi = tvb_get_guint8(tvb, offs);
357             proto_tree_add_uint(meta_tree, hf_meta_item_nsapi, tvb,
358                 offs, 1, nsapi);
359             break;
360         case META_ID_IMSI:
361             imsi     = tvb_get_letoh64(tvb, offs);
362             imsi_str = tvb_bcd_dig_to_wmem_packet_str(tvb, offs, 8, NULL, FALSE);
363             imsi_item = proto_tree_add_string(meta_tree, hf_meta_item_imsi_digits, tvb,
364                 offs, 8, imsi_str);
365             imsi_tree = proto_item_add_subtree(imsi_item, ett_meta_imsi);
366             proto_tree_add_uint64(imsi_tree, hf_meta_item_imsi_value,
367                 tvb, offs, 8, imsi);
368             break;
369         case META_ID_IMEI:
370             imei     = tvb_get_letoh64(tvb, offs);
371             imei_str = tvb_bcd_dig_to_wmem_packet_str(tvb, offs, 8, NULL, FALSE);
372             imei_item = proto_tree_add_string(meta_tree, hf_meta_item_imei_digits, tvb,
373                 offs, 8, imei_str);
374             imei_tree = proto_item_add_subtree(imei_item, ett_meta_imei);
375             proto_tree_add_uint64(imei_tree, hf_meta_item_imei_value,
376                 tvb, offs, 8, imei);
377             break;
378         case META_ID_APN:
379             proto_tree_add_item(meta_tree, hf_meta_item_apn, tvb,
380                 offs, len, ENC_ASCII|ENC_NA);
381             break;
382         case META_ID_RAT:
383             rat = tvb_get_guint8(tvb, offs);
384             proto_tree_add_uint(meta_tree, hf_meta_item_rat, tvb,
385                 offs, 1, rat);
386             break;
387         case META_ID_CELL:
388             cell = tvb_get_ntoh64(tvb, offs);
389             cell_item = proto_tree_add_uint64_format(meta_tree, hf_meta_item_cell,
390                                                      tvb, offs, 8, cell, "Mobile Cell");
391             cell_tree = proto_item_add_subtree(cell_item, ett_meta_cell);
392             de_gmm_rai(tvb, cell_tree, pinfo, offs, 8, NULL, 0);
393             de_cell_id(tvb, cell_tree, pinfo, offs + 6, 2, NULL, 0);
394             break;
395         case META_ID_SIGNALING:
396             proto_tree_add_boolean(meta_tree, hf_meta_item_signaling, tvb,
397                                    offs, 0, 1);
398             break;
399         case META_ID_INCOMPLETE:
400             proto_tree_add_boolean(meta_tree, hf_meta_item_incomplete, tvb,
401                 offs, 0, 1);
402             break;
403         case META_ID_DECIPHERED:
404             proto_tree_add_boolean(meta_tree, hf_meta_item_deciphered, tvb,
405                 offs, 0, 1);
406             break;
407         case META_ID_AAL5PROTO:
408             aal5proto    = tvb_get_guint8(tvb, offs);
409             p_sscop_info = (sscop_payload_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_sscop, 0);
410             if (!p_sscop_info) {
411                 p_sscop_info = wmem_new0(wmem_file_scope(), sscop_payload_info);
412                 p_add_proto_data(wmem_file_scope(), pinfo, proto_sscop, 0, p_sscop_info);
413             }
414             switch (aal5proto) {
415                 case META_AAL5PROTO_MTP3:
416                     p_sscop_info->subdissector = sscf_nni_handle;
417                     /* hint for ATM dissector that this frame contains SSCOP */
418                     memset(&pinfo->pseudo_header->atm, 0, sizeof(pinfo->pseudo_header->atm));
419                     pinfo->pseudo_header->atm.type = TRAF_SSCOP;
420                     break;
421                 case META_AAL5PROTO_ALCAP:
422                     p_sscop_info->subdissector = alcap_handle;
423                     break;
424                 case META_AAL5PROTO_NBAP:
425                     p_sscop_info->subdissector = nbap_handle;
426                     break;
427                 case META_AAL5PROTO_NS:
428                     /* hint for ATM dissector that this frame contains GPRS NS */
429                     memset(&pinfo->pseudo_header->atm, 0, sizeof(pinfo->pseudo_header->atm));
430                     pinfo->pseudo_header->atm.type = TRAF_GPRS_NS;
431                     break;
432                 /* TODO: check for additional protos on Iu 802 LLC/SNAP ... */
433                 default:
434                     /* TODO: add warning */
435                     p_remove_proto_data(wmem_file_scope(), pinfo, proto_sscop, 0);
436             }
437             proto_tree_add_uint(meta_tree, hf_meta_item_aal5proto, tvb,
438                 offs, 1, aal5proto);
439             break;
440         case META_ID_LOCALDEVID:
441             localdevid = tvb_get_letohs(tvb, offs);
442             proto_tree_add_uint(meta_tree, hf_meta_item_localdevid, tvb,
443                 offs, 2, localdevid);
444             break;
445         case META_ID_REMOTEDEVID:
446             remotedevid = tvb_get_letohs(tvb, offs);
447             proto_tree_add_uint(meta_tree, hf_meta_item_remotedevid, tvb,
448                 offs, 2, remotedevid);
449             break;
450         case META_ID_TAPGROUPID:
451             tapgroupid = tvb_get_letohs(tvb, offs);
452             proto_tree_add_uint(meta_tree, hf_meta_item_tapgroupid, tvb,
453                 offs, 2, tapgroupid);
454             break;
455         case META_ID_TLLI:
456             tlli = tvb_get_letohs(tvb, offs);
457             proto_tree_add_uint(meta_tree, hf_meta_item_tlli, tvb,
458                 offs, 4, tlli);
459             break;
460         case META_ID_CALLING:
461             proto_tree_add_item(meta_tree, hf_meta_item_calling, tvb,
462                 offs, len, ENC_ASCII|ENC_NA);
463             break;
464         case META_ID_CALLED:
465             proto_tree_add_item(meta_tree, hf_meta_item_called, tvb,
466                 offs, len, ENC_ASCII|ENC_NA);
467             break;
468         default:
469             subti = proto_tree_add_item(meta_tree, hf_meta_item, tvb, offs - 4,
470                 aligned_len + 4, ENC_NA);
471             item_tree = proto_item_add_subtree(subti, ett_meta_item);
472             proto_tree_add_uint(item_tree, hf_meta_item_id, tvb, offs - 4, 2, id);
473             proto_tree_add_uint(item_tree, hf_meta_item_type, tvb, offs - 2, 1, type);
474             proto_tree_add_uint(item_tree, hf_meta_item_len,
475                 tvb, offs - 1, 1, len);
476             if (len > 0)
477                 proto_tree_add_item(item_tree, hf_meta_item_data,
478                     tvb, offs, len, ENC_NA);
479     }
480     return total_len;
481 }
482
483 /*
484  * offs: current offset within tvb
485  * header_length: length of meta header
486  */
487 static gint32 evaluate_meta_items(guint16 schema, tvbuff_t *tvb, packet_info *pinfo,
488     proto_tree *meta_tree, guint16 offs, gint32 header_length)
489 {
490     gint16 item_len;
491     gint32 total_len = 0;
492
493     while (total_len < header_length) {
494         switch (schema) {
495             case META_SCHEMA_DXT:
496                 item_len = evaluate_meta_item_dxt(meta_tree, tvb, pinfo, offs + total_len);
497                 break;
498             case META_SCHEMA_PCAP:
499                 item_len = evaluate_meta_item_pcap(meta_tree, tvb, pinfo, offs + total_len);
500                 break;
501             default:
502                 item_len = skip_item(meta_tree, tvb, pinfo, offs + total_len);
503         }
504         if (item_len < 4) { /* 4 is the minimum length of an item: id + type + length field */
505             expert_add_info_format(pinfo, meta_tree, &ei_meta_malformed,
506                 "Malformed Packet %s (wrong item encoding)", pinfo->current_proto);
507             return -1;
508         }
509         total_len += item_len;
510     }
511     return total_len;
512 }
513
514 static void
515 dissect_meta(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
516 {
517 #define META_HEADER_SIZE 8
518     guint16             schema, proto, hdrlen, reserved;
519     gint32              item_len;
520     guint32             aal2_ext, atm_hdr;
521     proto_tree         *meta_tree      = NULL;
522     proto_item         *ti             = NULL;
523     tvbuff_t           *next_tvb       = NULL;
524     dissector_handle_t  next_dissector = NULL;
525
526     col_set_str(pinfo->cinfo, COL_PROTOCOL, "META");
527
528     schema   = tvb_get_letohs(tvb, 0);
529     hdrlen   = tvb_get_letohs(tvb, 2);
530     proto    = tvb_get_letohs(tvb, 4);
531     reserved = tvb_get_letohs(tvb, 6);
532
533     if (tree) {
534         ti = proto_tree_add_item(tree, proto_meta, tvb, 0, hdrlen + 4, ENC_NA);
535         meta_tree = proto_item_add_subtree(ti, ett_meta);
536         proto_tree_add_uint(meta_tree, hf_meta_schema, tvb, 0, 2, schema);
537         proto_tree_add_uint(meta_tree, hf_meta_hdrlen, tvb, 2, 2, hdrlen);
538         proto_tree_add_uint(meta_tree, hf_meta_proto, tvb, 4, 2, proto);
539         proto_tree_add_uint(meta_tree, hf_meta_reserved, tvb, 6, 2, reserved);
540     }
541     item_len = evaluate_meta_items(schema, tvb, pinfo, meta_tree, META_HEADER_SIZE, hdrlen);
542
543     if (item_len < 0) {
544         /* evaluate_meta_items signalled an error */
545         return; /* stop parsing */
546     }
547
548     if (hdrlen != item_len) {
549         expert_add_info(pinfo, ti, &ei_meta_invalid_header);
550         return;
551     }
552
553     /* find next subdissector based on the chosen schema */
554     switch (schema) {
555         case META_SCHEMA_PCAP:
556             /* TODO */
557             break;
558         case META_SCHEMA_DXT:
559             switch (proto) {
560                 case META_PROTO_DXT_ETHERNET:
561                     next_dissector = ethwithoutfcs_handle;
562                     break;
563                 case META_PROTO_DXT_ETHERNET_CRC:
564                     next_dissector = ethwithfcs_handle;
565                     break;
566                 case META_PROTO_DXT_FP_HINT:
567                     next_dissector = fphint_handle;
568                     break;
569                 case META_PROTO_DXT_ATM:
570                     next_dissector = atm_untrunc_handle;
571                     pinfo->pseudo_header->atm.aal  = AAL_OAMCELL;
572                     pinfo->pseudo_header->atm.type = TRAF_UNKNOWN;
573                     break;
574                 case META_PROTO_DXT_ATM_AAL2:
575                     aal2_ext = tvb_get_ntohl(tvb, item_len + META_HEADER_SIZE); item_len += 4;
576                     atm_hdr  = tvb_get_ntohl(tvb, item_len + META_HEADER_SIZE); item_len += 4;
577                     memset(&pinfo->pseudo_header->atm, 0, sizeof(pinfo->pseudo_header->atm));
578                     pinfo->pseudo_header->atm.aal = AAL_2;
579                     /* pinfo->pseudo_header->atm.flags = pinfo->p2p_dir; */
580                     pinfo->pseudo_header->atm.vpi  = ((atm_hdr & 0x0ff00000) >> 20);
581                     pinfo->pseudo_header->atm.vci  = ((atm_hdr & 0x000ffff0) >>  4);
582                     pinfo->pseudo_header->atm.aal2_cid = aal2_ext & 0x000000ff;
583                     pinfo->pseudo_header->atm.type = TRAF_UMTS_FP;
584                     next_dissector = atm_untrunc_handle;
585                     break;
586                 case META_PROTO_DXT_ERF_AAL5:
587                     atm_hdr = tvb_get_ntohl(tvb, item_len + META_HEADER_SIZE); item_len += 4;
588                     pinfo->pseudo_header->atm.vpi = ((atm_hdr & 0x0ff00000) >> 20);
589                     pinfo->pseudo_header->atm.vci = ((atm_hdr & 0x000ffff0) >>  4);
590                     pinfo->pseudo_header->atm.aal = AAL_5;
591                     next_dissector = atm_untrunc_handle;
592                     break;
593                 case META_PROTO_DXT_HDLC:
594                     next_dissector = mtp2_handle;
595                     next_tvb = tvb_new_subset(tvb, item_len + META_HEADER_SIZE,
596                         tvb_reported_length(tvb)-item_len-META_HEADER_SIZE-2, -1);
597                     break;
598                 default:
599                     next_dissector =
600                         dissector_get_uint_handle(meta_dissector_table, proto);
601             }
602     }
603     if (!next_tvb)
604         next_tvb = tvb_new_subset_remaining(tvb, item_len + META_HEADER_SIZE);
605
606     call_dissector(next_dissector ? next_dissector : data_handle,
607         next_tvb, pinfo, tree);
608 }
609
610 void
611 proto_register_meta(void)
612 {
613     static hf_register_info hf[] = {
614         /* metadata header */
615         { &hf_meta_schema,
616           { "Schema", "meta.schema",
617             FT_UINT16, BASE_DEC, VALS(meta_schema_vals), 0,
618             NULL, HFILL }
619         },
620         { &hf_meta_hdrlen,
621           { "Header Length", "meta.hdrlen",
622             FT_UINT16, BASE_DEC, NULL, 0,
623             NULL, HFILL }
624         },
625         { &hf_meta_proto,
626           { "Protocol", "meta.proto",
627             FT_UINT16, BASE_DEC | BASE_EXT_STRING, &meta_proto_vals_ext, 0,
628             NULL, HFILL }
629         },
630         { &hf_meta_reserved,
631           { "Reserved", "meta.reserved",
632             FT_UINT16, BASE_HEX, NULL, 0,
633             NULL, HFILL }
634         },
635
636         /* general meta item */
637         { &hf_meta_item,
638           { "Unknown Item", "meta.item",
639             FT_NONE, BASE_NONE, NULL, 0,
640             NULL, HFILL }
641         },
642         { &hf_meta_item_id,
643           { "Item ID", "meta.item.id",
644             FT_UINT16, BASE_HEX | BASE_EXT_STRING, &meta_id_vals_ext, 0x0,
645             NULL, HFILL }
646         },
647         { &hf_meta_item_type,
648           { "Item Type", "meta.item.type",
649             FT_UINT8, BASE_HEX, VALS(meta_type_vals), 0x0,
650             NULL, HFILL }
651         },
652         { &hf_meta_item_len,
653           { "Item Length", "meta.item.len",
654             FT_UINT8, BASE_DEC, NULL, 0,
655             NULL, HFILL }
656         },
657         { &hf_meta_item_data,
658           { "Item Data", "meta.item.data",
659             FT_BYTES, BASE_NONE, NULL, 0x0,
660             NULL, HFILL }
661         },
662
663         /* specific meta items */
664         { &hf_meta_item_direction,
665           { "Direction", "meta.direction",
666             FT_UINT8, BASE_DEC, VALS(meta_direction_vals), 0,
667             NULL, HFILL }
668         },
669         { &hf_meta_item_ts,
670           { "Timestamp", "meta.timestamp",
671             FT_UINT64, BASE_DEC, NULL, 0,
672             NULL, HFILL }
673         },
674         { &hf_meta_item_phylinkid,
675           { "Physical Link ID", "meta.phylinkid",
676             FT_UINT16, BASE_DEC, NULL, 0,
677             NULL, HFILL }
678         },
679         { &hf_meta_item_nsapi,
680           { "NSAPI", "meta.nsapi",
681             FT_UINT8, BASE_DEC, NULL, 0,
682             NULL, HFILL }
683         },
684         { &hf_meta_item_imsi_digits,
685           { "IMSI digits", "meta.imsi_digits",
686             FT_STRINGZ, BASE_NONE, NULL, 0,
687             NULL, HFILL }
688         },
689         { &hf_meta_item_imsi_value,
690           { "IMSI value", "meta.imsi_value",
691             FT_UINT64, BASE_HEX, NULL, 0,
692             NULL, HFILL }
693         },
694         { &hf_meta_item_imei_digits,
695           { "IMEI digits", "meta.imei_digits",
696             FT_STRINGZ, BASE_NONE, NULL, 0,
697             NULL, HFILL }
698         },
699         { &hf_meta_item_imei_value,
700           { "IMEI value", "meta.imei_value",
701             FT_UINT64, BASE_HEX, NULL, 0,
702             NULL, HFILL }
703         },
704         { &hf_meta_item_signaling,
705           { "Signaling", "meta.signaling",
706             FT_BOOLEAN, BASE_NONE, NULL, 0,
707             NULL, HFILL }
708         },
709         { &hf_meta_item_incomplete,
710           { "Incomplete", "meta.incomplete",
711             FT_BOOLEAN, BASE_NONE, NULL, 0,
712             NULL, HFILL }
713         },
714         { &hf_meta_item_deciphered,
715           { "Deciphered", "meta.deciphered",
716             FT_BOOLEAN, BASE_NONE, NULL, 0,
717             NULL, HFILL }
718         },
719         { &hf_meta_item_apn,
720           { "APN", "meta.apn",
721             FT_STRINGZ, BASE_NONE, NULL, 0,
722             NULL, HFILL }
723         },
724         { &hf_meta_item_rat,
725           { "RAT", "meta.rat",
726             FT_UINT8, BASE_DEC, NULL, 0,
727             NULL, HFILL }
728         },
729         { &hf_meta_item_aal5proto,
730           { "AAL5 Protocol Type", "meta.aal5proto",
731             FT_UINT8, BASE_DEC, VALS(meta_aal5proto_vals), 0,
732             NULL, HFILL }
733         },
734         { &hf_meta_item_cell,
735           { "Mobile Cell", "meta.cell",
736             FT_UINT64, BASE_HEX, NULL, 0,
737             NULL, HFILL }
738         },
739
740         { &hf_meta_item_localdevid,
741           { "Local Device ID", "meta.localdevid",
742             FT_UINT16, BASE_DEC, NULL, 0,
743             NULL, HFILL }
744         },
745         { &hf_meta_item_remotedevid,
746           { "Remote Device ID", "meta.remotedevid",
747             FT_UINT16, BASE_DEC, NULL, 0,
748             NULL, HFILL }
749         },
750         { &hf_meta_item_tapgroupid,
751           { "Tap Group ID", "meta.tapgroupid",
752             FT_UINT16, BASE_DEC, NULL, 0,
753             NULL, HFILL }
754         },
755         { &hf_meta_item_tlli,
756           { "TLLI", "meta.tlli",
757             FT_UINT32, BASE_DEC, NULL, 0,
758             NULL, HFILL }
759         },
760         { &hf_meta_item_calling,
761           { "Calling Station ID", "meta.calling",
762             FT_STRINGZ, BASE_NONE, NULL, 0,
763             NULL, HFILL }
764         },
765         { &hf_meta_item_called,
766           { "Called Station ID", "meta.called",
767             FT_STRINGZ, BASE_NONE, NULL, 0,
768             NULL, HFILL }
769         },
770     };
771
772     static gint *ett[] = {
773         &ett_meta,
774         &ett_meta_item,
775         &ett_meta_cell,
776         &ett_meta_imsi,
777         &ett_meta_imei
778     };
779
780     static ei_register_info ei[] = {
781         { &ei_meta_malformed, { "meta.malformed", PI_MALFORMED, PI_ERROR, "Malformed data", EXPFILL }},
782         { &ei_meta_invalid_header, { "meta.invalid_header_length", PI_MALFORMED, PI_ERROR, "Invalid Header Length", EXPFILL }},
783     };
784
785     expert_module_t* expert_meta;
786
787     proto_meta = proto_register_protocol("Metadata", "META", "meta");
788     register_dissector("meta", dissect_meta, proto_meta);
789
790     proto_register_field_array(proto_meta, hf, array_length(hf));
791     proto_register_subtree_array(ett, array_length(ett));
792     expert_meta = expert_register_protocol(proto_meta);
793     expert_register_field_array(expert_meta, ei, array_length(ei));
794
795     meta_dissector_table = register_dissector_table("meta.proto",
796             "META protocol", FT_UINT16, BASE_DEC);
797 }
798
799 void
800 proto_reg_handoff_meta(void)
801 {
802 #if 0   /* enable once WTAP_ENCAP_META exists */
803     dissector_handle_t meta_handle;
804
805     meta_handle          = find_dissector("meta");
806     dissector_add_uint("wtap_encap", WTAP_ENCAP_META, meta_handle);
807 #endif
808     data_handle          = find_dissector("data");
809     alcap_handle         = find_dissector("alcap");
810     atm_untrunc_handle   = find_dissector("atm_untruncated");
811     nbap_handle          = find_dissector("nbap");
812     sscf_nni_handle      = find_dissector("sscf-nni");
813     ethwithfcs_handle    = find_dissector("eth_withfcs");
814     ethwithoutfcs_handle = find_dissector("eth_withoutfcs");
815     fphint_handle        = find_dissector("fp_hint");
816     mtp2_handle          = find_dissector("mtp2");
817 }