UATs could be put into "categories". The categories were defined only
[metze/wireshark/wip.git] / epan / dissectors / packet-dmp.c
1 /* packet-dmp.c
2  *
3  * Routines for STANAG 4406 Direct Message Profile packet disassembly.
4  * A protocol for optimised transfer of time-critical short messages
5  * for use with a reliable bearer service.  Checksum and retransmission
6  * mechanisms are activated when using unreliable bearer services.
7  *
8  * Copyright 2006, Stig Bjorlykke <stig@bjorlykke.org>, Thales Norway AS
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.,
28  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29  *
30  * Ref:  http://jcs.dtic.mil/j6/cceb/acps/acp123/
31  */
32
33 /*
34  * TODO:
35  * - Dissect extended Restrictive security categories
36  * - Add Transmission/Retransmission statistics
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <string.h>
44 #include <math.h>
45
46 #include <epan/packet.h>
47 #include <epan/address.h>
48 #include <epan/addr_resolv.h>
49 #include <epan/to_str.h>
50 #include <epan/prefs.h>
51 #include <epan/emem.h>
52 #include <epan/expert.h>
53 #include <epan/crc16-tvb.h>
54 #include <epan/asn1.h>
55 #include <epan/strutil.h>
56 #include <epan/uat.h>
57
58 #include "packet-p1.h"
59 #include "packet-p22.h"
60
61 #define PNAME  "Direct Message Profile"
62 #define PSNAME "DMP"
63 #define PFNAME "dmp"
64
65 /* Default UDP Port Number */
66 #define DEFAULT_DMP_PORT_RANGE "5031"
67
68 /* Protocol Identifier */
69 #define PROT_NAT 0x0D
70 #define PROT_DMP 0x1D
71
72 /* Versions supported */
73 #define DMP_VERSION_1  1
74 #define DMP_VERSION_2  2
75
76 /* Message Type (dmp.msg_type) */
77 #define STANAG   0x0
78 #define IPM      0x1
79 #define REPORT   0x2
80 #define NOTIF    0x3
81 #define ACK      0x4
82
83 /* Message Identifier Type (dmp.msg_id_type) */
84 #define ONLY_DMP_ID  0x0
85 #define X400_MSG_ID  0x1
86 #define NAT_MSG_ID   0x2
87
88 /* Report Type (dmp.report_type) */
89 #define DR       0x0
90 #define NDR      0x1
91
92 /* Notification Type (dmp.notif_type) */
93 #define RN       0x0
94 #define NRN      0x1
95 #define ON       0x2
96
97 /* Address Encoding (dmp.addr_enc) */
98 #define DIRECT_ADDR   0x0
99 #define EXTENDED_ADDR 0x1
100
101 /* Address type (internal values) */
102 #define ORIGINATOR   1
103 #define P1_ADDRESS   2
104 #define P2_ADDRESS   3
105 #define ORIG_P2_ADDRESS   4
106
107 /* Extended Address Form (dmp_addr_form) */
108 #define P1_DIRECT             0x0
109 #define P2_DIRECT             0x1
110 #define P1_EXTENDED           0x2
111 #define P2_EXTENDED           0x3
112 #define P1_P2_DIRECT          0x4
113 #define P1_DIRECT_P2_EXTENDED 0x5
114 #define P1_EXTENDED_P2_DIRECT 0x6
115 #define P1_P2_EXTENDED        0x7
116
117 /* Extended Address Type */
118 #define ASN1_BER 0x0
119 #define ASN1_PER 0x1
120
121 /* Security Policy (dmp_sec_pol) */
122 #define NATO              0x4
123 #define NATIONAL          0x5
124 #define EXTENDED_NATIONAL 0x6
125 #define EXTENDED_MISSION  0x7
126
127 #define SEC_CAT_EXT_NONE        0x0
128 #define SEC_CAT_EXT_PERMISSIVE  0x1
129 #define SEC_CAT_EXT_RESTRICTIVE 0x2
130
131 /* Body Format (dmp.body_format) */
132 #define FREE_TEXT         0x0
133 #define FREE_TEXT_SUBJECT 0x1
134 #define STRUCTURED        0x2
135
136 /* Encoded Information Types */
137 #define EIT_BILATERAL     0x3
138
139 /* Compression Algorithm */
140 #define ALGORITHM_NONE    0x0
141 #define ALGORITHM_ZLIB    0x1
142
143 /* Type of structured id to print */
144 #define STRUCT_ID_NONE     0
145 #define STRUCT_ID_UINT8    1
146 #define STRUCT_ID_UINT16   2
147 #define STRUCT_ID_UINT32   3
148 #define STRUCT_ID_UINT64   4
149 #define STRUCT_ID_STRING   5
150 #define STRUCT_ID_ZSTRING  6
151
152 #define NAT_DECODE_NONE    0
153 #define NAT_DECODE_DMP     1
154 #define NAT_DECODE_THALES  2
155
156 #define IPM_MODIFIER_X400  0
157
158 /* Internal values for not present and reserved time values */
159 #define DMP_TIME_NOT_PRESENT  -1
160 #define DMP_TIME_RESERVED     -2
161
162 #define ILLEGAL_FORMAT "<Illegal format>"
163
164 /* Maximum lengths */
165 #define MAX_SIC_LEN         30
166
167 void proto_reg_handoff_dmp (void);
168
169 static int proto_dmp = -1;
170
171 static int hf_dmp_id = -1;
172 static int hf_mts_id = -1;
173 static int hf_ipm_id = -1;
174
175 static int hf_envelope = -1;
176 static int hf_envelope_protocol_id = -1;
177 static int hf_envelope_version = -1;
178 static int hf_envelope_version_value = -1;
179 static int hf_envelope_hop_count = -1;
180 static int hf_envelope_hop_count_value = -1;
181 static int hf_envelope_rec_present = -1;
182 static int hf_envelope_addr_enc = -1;
183 static int hf_envelope_checksum = -1;
184 static int hf_envelope_extensions = -1;
185 static int hf_envelope_msg_id_type = -1;
186 static int hf_envelope_msg_id_length = -1;
187 static int hf_envelope_mts_id_length = -1;
188 static int hf_envelope_ipm_id_modifier = -1;
189 static int hf_envelope_ipm_id_length = -1;
190 static int hf_envelope_mts_id = -1;
191 static int hf_envelope_ipm_id = -1;
192 static int hf_envelope_type = -1;
193 static int hf_envelope_msg_id = -1;
194 static int hf_envelope_msg_id_12bit = -1;
195 static int hf_envelope_subm_time = -1;
196 static int hf_envelope_subm_time_value = -1;
197 static int hf_envelope_time_diff_present = -1;
198 static int hf_envelope_time_diff = -1;
199 static int hf_envelope_time_diff_value = -1;
200 static int hf_envelope_flags = -1;
201 static int hf_envelope_content_id_discarded = -1;
202 static int hf_envelope_recip_reassign_prohib = -1;
203 static int hf_envelope_dl_expansion_prohib = -1;
204 static int hf_envelope_recipients = -1;
205 static int hf_envelope_ext_recipients = -1;
206
207 static int hf_thales_ipm_id_modifier = -1;
208
209 static int hf_extensions = -1;
210 static int hf_extension = -1;
211 static int hf_extension_header = -1;
212 static int hf_extension_more = -1;
213 static int hf_extension_length = -1;
214 static int hf_extension_data = -1;
215
216 static int hf_message_content = -1;
217 static int hf_report_content = -1;
218 static int hf_notif_content = -1;
219
220 static int hf_addr_recipient = -1;
221 static int hf_addr_originator = -1;
222 static int hf_addr_reporting_name = -1;
223 static int hf_addr_dl_expanded = -1;
224 static int hf_addr_int_rec = -1;
225 static int hf_addr_dir_addr_ext = -1;
226 static int hf_addr_dir_rec_no = -1;
227 static int hf_addr_dir_rec_no1 = -1;
228 static int hf_addr_dir_rec_no2 = -1;
229 static int hf_addr_dir_rec_no3 = -1;
230 static int hf_addr_dir_rec_no_generated = -1;
231 static int hf_addr_dir_rep_req1 = -1;
232 static int hf_addr_dir_rep_req2 = -1;
233 static int hf_addr_dir_rep_req3 = -1;
234 static int hf_addr_dir_not_req1 = -1;
235 static int hf_addr_dir_not_req2 = -1;
236 static int hf_addr_dir_not_req3 = -1;
237 static int hf_addr_dir_action = -1;
238 static int hf_addr_dir_address = -1;
239 static int hf_addr_dir_address1 = -1;
240 static int hf_addr_dir_address2 = -1;
241 static int hf_addr_dir_address3 = -1;
242 static int hf_addr_dir_address_generated = -1;
243
244 static int hf_addr_ext_form = -1;
245 static int hf_addr_ext_form_orig_v1 = -1;
246 static int hf_addr_ext_form_orig = -1;
247 static int hf_addr_ext_action = -1;
248 static int hf_addr_ext_rep_req = -1;
249 static int hf_addr_ext_not_req = -1;
250 static int hf_addr_ext_rec_ext = -1;
251 static int hf_addr_ext_rec_no = -1;
252 static int hf_addr_ext_rec_no1 = -1;
253 static int hf_addr_ext_rec_no2 = -1;
254 static int hf_addr_ext_rec_no_generated = -1;
255 static int hf_addr_ext_address = -1;
256 static int hf_addr_ext_type = -1;
257 static int hf_addr_ext_type_ext = -1;
258 static int hf_addr_ext_length = -1;
259 static int hf_addr_ext_length1 = -1;
260 static int hf_addr_ext_length2 = -1;
261 static int hf_addr_ext_length_generated = -1;
262 static int hf_addr_ext_asn1_ber = -1;
263 static int hf_addr_ext_asn1_per = -1;
264 static int hf_addr_ext_unknown = -1;
265
266 static int hf_message_body = -1;
267 static int hf_message_st_type = -1;
268 static int hf_message_precedence = -1;
269 static int hf_message_importance = -1;
270 static int hf_message_body_format = -1;
271 static int hf_message_sec_class_val = -1;
272 static int hf_message_sec_pol = -1;
273 static int hf_message_heading_flags = -1;
274 static int hf_message_auth_users = -1;
275 static int hf_message_subject_disc = -1;
276 static int hf_message_national_policy_id = -1;
277 static int hf_message_mission_policy_id = -1;
278 static int hf_message_sec_label = -1;
279 static int hf_message_sec_cat_nat = -1;
280 static int hf_message_sec_cat_val = -1;
281 static int hf_message_sec_cat_cl = -1;
282 static int hf_message_sec_cat_cs = -1;
283 static int hf_message_sec_cat_ex = -1;
284 static int hf_message_sec_cat_ne = -1;
285 static int hf_message_sec_cat_permissive = -1;
286 static int hf_message_sec_cat_country_code = -1;
287 static int hf_message_sec_cat_restrictive = -1;
288 static int hf_message_sec_cat_extended = -1;
289 static int hf_message_sec_cat_bit0 = -1;
290 static int hf_message_sec_cat_bit1 = -1;
291 static int hf_message_sec_cat_bit2 = -1;
292 static int hf_message_sec_cat_bit3 = -1;
293 static int hf_message_sec_cat_bit4 = -1;
294 static int hf_message_sec_cat_bit5 = -1;
295 static int hf_message_sec_cat_bit6 = -1;
296 static int hf_message_sec_cat_bit7 = -1;
297 static int hf_message_exp_time = -1;
298 static int hf_message_exp_time_val = -1;
299 static int hf_message_dtg = -1;
300 static int hf_message_dtg_sign = -1;
301 static int hf_message_dtg_val = -1;
302 static int hf_message_sic = -1;
303 static int hf_message_sic_key = -1;
304 static int hf_message_sic_key_values = -1;
305 static int hf_message_sic_key_type = -1;
306 static int hf_message_sic_key_chars = -1;
307 static int hf_message_sic_key_num = -1;
308 static int hf_message_sic_bitmap = -1;
309 static int hf_message_sic_bits = -1;
310 static int hf_message_sic_bits_any = -1;
311 static int hf_message_subj_id = -1;
312 static int hf_message_subj_mts_id = -1;
313 static int hf_message_subj_ipm_id = -1;
314
315 static int hf_message_subject = -1;
316 static int hf_message_eit = -1;
317 static int hf_message_compr = -1;
318 static int hf_message_body_data = -1;
319 static int hf_message_body_plain = -1;
320 static int hf_message_bodyid_uint8 = -1;
321 static int hf_message_bodyid_uint16 = -1;
322 static int hf_message_bodyid_uint32 = -1;
323 static int hf_message_bodyid_uint64 = -1;
324 static int hf_message_bodyid_string = -1;
325 static int hf_message_bodyid_zstring = -1;
326 static int hf_message_body_structured = -1;
327 static int hf_message_body_uncompr = -1;
328 static int hf_message_body_uncompressed = -1;
329
330 static int hf_delivery_report = -1;
331 static int hf_non_delivery_report = -1;
332 static int hf_report_type = -1;
333 static int hf_report_info_present_dr = -1;
334 static int hf_report_addr_enc_dr = -1;
335 static int hf_report_del_time = -1;
336 static int hf_report_del_time_val = -1;
337 static int hf_report_addr_enc_ndr = -1;
338 static int hf_report_reason = -1;
339 static int hf_report_info_present_ndr = -1;
340 static int hf_report_diagn = -1;
341 static int hf_report_suppl_info_len = -1;
342 static int hf_report_suppl_info = -1;
343
344 static int hf_receipt_notif = -1;
345 static int hf_non_receipt_notif = -1;
346 static int hf_other_notif = -1;
347 static int hf_notif_type = -1;
348 static int hf_notif_rec_time = -1;
349 static int hf_notif_rec_time_val = -1;
350 static int hf_notif_suppl_info_len = -1;
351 static int hf_notif_suppl_info = -1;
352 static int hf_notif_non_rec_reason = -1;
353 static int hf_notif_discard_reason = -1;
354 static int hf_notif_on_type = -1;
355 static int hf_notif_acp127 = -1;
356 static int hf_notif_acp127recip = -1;
357
358 static int hf_ack = -1;
359 static int hf_ack_reason = -1;
360 static int hf_ack_diagnostic = -1;
361 static int hf_ack_recips = -1;
362
363 static int hf_checksum = -1;
364 static int hf_checksum_good = -1;
365 static int hf_checksum_bad = -1;
366
367 static int hf_analysis_ack_time = -1;
368 static int hf_analysis_total_time = -1;
369 static int hf_analysis_retrans_time = -1;
370 static int hf_analysis_total_retrans_time = -1;
371 static int hf_analysis_msg_num = -1;
372 static int hf_analysis_msg_missing = -1;
373 static int hf_analysis_retrans_no = -1;
374 static int hf_analysis_ack_num = -1;
375 static int hf_analysis_ack_missing = -1;
376 static int hf_analysis_ack_dup_no = -1;
377 static int hf_analysis_rep_num = -1;
378 static int hf_analysis_rep_time = -1;
379 static int hf_analysis_not_num = -1;
380 static int hf_analysis_not_time = -1;
381 static int hf_analysis_msg_resend_from = -1;
382 static int hf_analysis_rep_resend_from = -1;
383 static int hf_analysis_not_resend_from = -1;
384 static int hf_analysis_ack_resend_from = -1;
385
386 static int hf_reserved_0x01 = -1;
387 static int hf_reserved_0x02 = -1;
388 static int hf_reserved_0x04 = -1;
389 static int hf_reserved_0x07 = -1;
390 static int hf_reserved_0x08 = -1;
391 static int hf_reserved_0x0F = -1;
392 static int hf_reserved_0x1F = -1;
393 static int hf_reserved_0x20 = -1;
394 static int hf_reserved_0x40 = -1;
395 static int hf_reserved_0xC0 = -1;
396 static int hf_reserved_0xE0 = -1;
397 static int hf_reserved_0x8000 = -1;
398
399 static gint ett_dmp = -1;
400 static gint ett_envelope = -1;
401 static gint ett_envelope_version = -1;
402 static gint ett_envelope_hop_count = -1;
403 static gint ett_envelope_rec_present = -1;
404 static gint ett_envelope_addr_enc = -1;
405 static gint ett_envelope_checksum = -1;
406 static gint ett_envelope_extensions = -1;
407 static gint ett_envelope_msg_id_type = -1;
408 static gint ett_envelope_msg_id = -1;
409 static gint ett_envelope_mts_id_length = -1;
410 static gint ett_envelope_ipm_id_length = -1;
411 static gint ett_envelope_cont_type = -1;
412 static gint ett_envelope_subm_time = -1;
413 static gint ett_envelope_time_diff = -1;
414 static gint ett_envelope_flags = -1;
415 static gint ett_envelope_recipients = -1;
416 static gint ett_envelope_ext_recipients = -1;
417 static gint ett_envelope_addresses = -1;
418
419 static gint ett_address = -1;
420 static gint ett_address_direct = -1;
421 static gint ett_address_rec_no = -1;
422 static gint ett_address_extended = -1;
423 static gint ett_address_ext_form = -1;
424 static gint ett_address_ext_rec_no = -1;
425 static gint ett_address_ext_action = -1;
426 static gint ett_address_ext_rep_req = -1;
427 static gint ett_address_ext_not_req = -1;
428 static gint ett_address_ext_type = -1;
429 static gint ett_address_ext_length = -1;
430
431 static gint ett_extensions = -1;
432 static gint ett_extension = -1;
433 static gint ett_extension_header = -1;
434
435 static gint ett_content = -1;
436
437 static gint ett_message = -1;
438 static gint ett_message_st_type = -1;
439 static gint ett_message_reserved = -1;
440 static gint ett_message_precedence = -1;
441 static gint ett_message_importance = -1;
442 static gint ett_message_body_format = -1;
443 static gint ett_message_sec_class = -1;
444 static gint ett_message_sec_pol = -1;
445 static gint ett_message_sec_cat = -1;
446 static gint ett_message_heading_flags = -1;
447 static gint ett_message_exp_time = -1;
448 static gint ett_message_dtg = -1;
449 static gint ett_message_sic = -1;
450 static gint ett_message_sic_key = -1;
451 static gint ett_message_sic_bitmap = -1;
452 static gint ett_message_sic_bits = -1;
453 static gint ett_message_eit = -1;
454 static gint ett_message_compr = -1;
455 static gint ett_message_body_reserved = -1;
456 static gint ett_message_body = -1;
457 static gint ett_message_body_uncompr = -1;
458
459 static gint ett_report = -1;
460 static gint ett_report_type = -1;
461 static gint ett_report_info_present_dr = -1;
462 static gint ett_report_info_present_ndr = -1;
463 static gint ett_report_addr_enc_dr = -1;
464 static gint ett_report_addr_enc_ndr = -1;
465 static gint ett_report_reserved = -1;
466 static gint ett_report_del_time = -1;
467 static gint ett_report_reason = -1;
468 static gint ett_report_suppl_info = -1;
469 static gint ett_report_diagn = -1;
470
471 static gint ett_notif = -1;
472 static gint ett_notif_type = -1;
473 static gint ett_notif_rec_time = -1;
474 static gint ett_notif_suppl_info = -1;
475 static gint ett_notif_acp127recip = -1;
476
477 static gint ett_ack = -1;
478 static gint ett_ack_recips = -1;
479
480 static gint ett_checksum = -1;
481
482 static gint ett_analysis = -1;
483
484 static dissector_handle_t dmp_handle;
485
486 typedef struct _dmp_id_key {
487   guint   id;
488   address src;
489   address dst;
490 } dmp_id_key;
491
492 typedef struct _dmp_id_val {
493   gint     msg_type;                   /* Message type                   */
494   guint    prev_msg_id;                /* Previous message package num   */
495   guint    msg_id;                     /* Message package num            */
496   guint    ack_id;                     /* Acknowledgement package num    */
497   guint    rep_id;                     /* Report package num             */
498   guint    not_id;                     /* Notification package num       */
499   nstime_t msg_time;                   /* Message receive time           */
500   nstime_t first_msg_time;             /* First message receive time     */
501   nstime_t prev_msg_time;              /* Previous message receive time  */
502   nstime_t rep_not_msg_time;           /* Report or Notification time    */
503   guint32  msg_resend_count;           /* Message resend counter         */
504   guint32  ack_resend_count;           /* Acknowledgement resend counter */
505 } dmp_id_val;
506
507 static GHashTable *dmp_id_hash_table = NULL;
508 static GHashTable *dmp_long_id_hash_table = NULL;
509
510 /* Global values used in several functions */
511 static struct dmp_data {
512   gint     version;
513   gint     prot_id;
514   gint     addr_enc;
515   gint     checksum;
516   gint     msg_type;
517   gint     st_type;
518   gint     prec;
519   gint     body_format;
520   gint     notif_type;
521   guchar  *struct_id;
522   gint32   subm_time;
523   guint8   msg_id_type;
524   guint8   mts_id_length;
525   proto_item *mts_id_item;
526   guint8   ack_reason;
527   guint16  msg_id;
528   guint16  subj_id;
529   gboolean extensions;
530   gboolean dr;
531   gboolean ndr;
532   gboolean notif_req;
533   gboolean ack_rec_present;
534   dmp_id_val *id_val;
535 } dmp;
536
537 /* User definable values */
538 static range_t *global_dmp_port_range;
539 static gint     dmp_nat_decode = NAT_DECODE_DMP;
540 static gint     dmp_local_nation = 0;
541 static gboolean use_seq_ack_analysis = TRUE;
542 static gboolean dmp_align = FALSE;
543 static gboolean dmp_subject_as_id = FALSE;
544 static gint     dmp_struct_format = STRUCT_ID_NONE;
545 static guint    dmp_struct_offset = 0;
546 static guint    dmp_struct_length = 1;
547
548 typedef struct _dmp_security_class_t {
549   guint nation;
550   guint sec_class;
551   char *name;
552 } dmp_security_class_t;
553
554 static dmp_security_class_t *dmp_security_classes;
555 static guint num_dmp_security_classes;
556
557 static const true_false_string addr_enc = {
558   "Use Extended Encoding", "Use Direct Encoding"
559 };
560
561 static const true_false_string dtg_sign = {
562   "Future", "Past"
563 };
564
565 static const true_false_string report_type = {
566   "Non-Delivery Report", "Delivery Report"
567 };
568
569 static const value_string version_vals[] = {
570   { 0x0, "1"       },
571   { 0x1, "2"       },
572   { 0x2, "Unknown" },
573   { 0x3, "Unknown" },
574   { 0x4, "Unknown" },
575   { 0x5, "Unknown" },
576   { 0x6, "Unknown" },
577   { 0x7, "Unknown" },
578   { 0,   NULL } };
579
580 static const value_string type_vals[] = {
581   { 0x0, "Message"          },
582   { 0x1, "Message (E-Mail)" },
583   { 0x2, "Report"           },
584   { 0x3, "Notification"     },
585   { 0x4, "Acknowledgement"  },
586   { 0x5, "Unknown Content"  },
587   { 0x6, "Unknown Content"  },
588   { 0x7, "Unknown Content"  },
589   { 0,   NULL } };
590
591 static const value_string msg_id_type_vals[] = {
592   { 0x0, "DMP Identifiers only"      },
593   { 0x1, "X.400 Message Identifiers" },
594   { 0x2, "Nationally-defined"        },
595   { 0x3, "Reserved"                  },
596   { 0,   NULL } };
597
598 static const value_string msg_id_length_vals[] = {
599   { 0x0, "Full (16 bits)"  },
600   { 0x1, "Short (12 bits)" },
601   { 0,   NULL } };
602
603 static const value_string report_vals[] = {
604   { 0x0, "No Report"           },
605   { 0x1, "Non-Delivery Report" },
606   { 0x2, "Delivery Report"     },
607   { 0x3, "Reserved"            },
608   { 0,   NULL } };
609
610 static const value_string report_vals_ext[] = {
611   { 0x0, "No Report"                 },
612   { 0x1, "Non-Delivery Report"       },
613   { 0x2, "Delivery Report"           },
614   { 0x3, "Recipient Number Extended" },
615   { 0,   NULL } };
616
617 /* Note the space in front of these values */
618 static const value_string report_vals_short[] = {
619   { 0x1, " NDR" },
620   { 0x2, " DR"  },
621   { 0,   NULL } };
622
623 static const value_string notif_vals[] = {
624   { 0x0, "No Notification"          },
625   { 0x1, "Non-Receipt Notification" },
626   { 0x2, "Receipt Notification"     },
627   { 0x3, "Reserved"                 },
628   { 0,   NULL } };
629
630 static const value_string notif_vals_ext[] = {
631   { 0x0, "No Notification"          },
632   { 0x1, "Non-Receipt Notification" },
633   { 0x2, "Receipt Notification"     },
634   { 0x3, "Direct Address Extended"  },
635   { 0,   NULL } };
636
637 /* Note the space in front of these values */
638 static const value_string notif_vals_short[] = {
639   { 0x1, " NRN" },
640   { 0x2, " RN"  },
641   { 0,   NULL } };
642
643 static const value_string notif_type [] = {
644   { 0x0, "Receipt Notification (RN)"      },
645   { 0x1, "Non-Receipt Notification (NRN)" },
646   { 0x2, "Other Notification (ON)"        },
647   { 0x3, "Unknown Notification"           },
648   { 0,   NULL } };
649
650 /* Note the space behind these values */
651 static const value_string addr_type_str [] = {
652   { ORIGINATOR,      ""          },
653   { P1_ADDRESS,      "P1 "       },
654   { P2_ADDRESS,      "P22/P772 " },
655   { ORIG_P2_ADDRESS, "P22 "      },
656   { 0,          NULL } };
657
658 static const value_string addr_form [] = {
659   { 0x0, "P1 Direct"                       },
660   { 0x1, "P22/P772 Direct"                 },
661   { 0x2, "P1 Extended"                     },
662   { 0x3, "P22/P772 Extended"               },
663   { 0x4, "P1 and P22/P772 Direct"          },
664   { 0x5, "P1 Direct and P22/P772 Extended" },
665   { 0x6, "P1 Extended and P22/P772 Direct" },
666   { 0x7, "P1 and P22/P772 Extended"        },
667   { 0,   NULL } };
668
669 static const value_string addr_form_orig_v1 [] = {
670   { 0x0, "Direct"                             },
671   { 0x1, "Reserved"                           },
672   { 0x2, "Extended"                           },
673   { 0x3, "Reserved"                           },
674   { 0x4, "Reserved"                           },
675   { 0x5, "Reserved"                           },
676   { 0x6, "Reserved"                           },
677   { 0x7, "Reserved"                           },
678   { 0,   NULL } };
679
680 static const value_string addr_form_orig [] = {
681   { 0x0, "Direct"                             },
682   { 0x1, "Reserved"                           },
683   { 0x2, "Extended"                           },
684   { 0x3, "Reserved"                           },
685   { 0x4, "Originator and P2 Direct"           },
686   { 0x5, "Originator Direct and P2 Extended"  },
687   { 0x6, "Originator Extended and P2 Direct"  },
688   { 0x7, "Originator and P2 Extended"         },
689   { 0,   NULL } };
690
691 static const value_string ext_addr_type [] = {
692   { 0x0, "ASN.1 BER-encoded OR-name" },
693   { 0x1, "ASN.1 PER-encoded OR-name" },
694   { 0x2, "Reserved" },
695   { 0x3, "Reserved" },
696   { 0x4, "Reserved" },
697   { 0x5, "Reserved" },
698   { 0x6, "Reserved" },
699   { 0x7, "Address Length Extended" },
700   { 0,   NULL } };
701
702 static const value_string ext_addr_type_ext [] = {
703   { 0x0, "ASN.1 BER-encoded OR-name" },
704   { 0x1, "ASN.1 PER-encoded OR-name" },
705   { 0x2, "Reserved" },
706   { 0x3, "Reserved" },
707   { 0x4, "Reserved" },
708   { 0x5, "Reserved" },
709   { 0x6, "Reserved" },
710   { 0x7, "Reserved" },
711   { 0,   NULL } };
712
713 static const value_string ext_addr_type_short [] = {
714   { 0x0, "OR-name (BER)" },
715   { 0x1, "OR-name (PER)" },
716   { 0x2, "Reserved" },
717   { 0x3, "Reserved" },
718   { 0x4, "Reserved" },
719   { 0x5, "Reserved" },
720   { 0x6, "Reserved" },
721   { 0x7, "Reserved" },
722   { 0,   NULL } };
723
724 static const value_string message_type_vals[] = {
725   { 0x0, "Operation" },
726   { 0x1, "Project"   },
727   { 0x2, "Exercise"  },
728   { 0x3, "Drill"     },
729   { 0,   NULL } };
730
731 static const value_string precedence[] = {
732   { 0x0, "Deferred"  },
733   { 0x1, "Routine"   },
734   { 0x2, "Priority"  },
735   { 0x3, "Immediate" },
736   { 0x4, "Flash"     },
737   { 0x5, "Override"  },
738   { 0x6, "Priority, Info Precedence: Routine"   },
739   { 0x7, "Immediate, Info Precedence: Routine"  },
740   { 0,   NULL } };
741
742 static const value_string importance[] = {
743   { 0x0, "Low"      },
744   { 0x1, "Reserved" },
745   { 0x2, "Normal"   },
746   { 0x3, "Reserved" },
747   { 0x4, "High"     },
748   { 0x5, "Reserved" },
749   { 0x6, "Reserved" },
750   { 0x7, "Reserved" },
751   { 0,   NULL } };
752
753 static const value_string sec_class[] = {
754   { 0x0, "Unmarked"     },
755   { 0x1, "Unclassified" },
756 /* { 0x2, "Reserved"     }, */
757   { 0x3, "Restricted"   },
758 /* { 0x4, "Reserved"     }, */
759   { 0x5, "Confidential" },
760   { 0x6, "Secret"       },
761   { 0x7, "Top secret"   },
762   { 0,   NULL } };
763
764 static const value_string sec_pol[] = {
765   { 0x0, "Network defined"                   },
766   { 0x1, "Network defined"                   },
767   { 0x2, "Network defined"                   },
768   { 0x3, "Network defined"                   },
769   { 0x4, "NATO"                              },
770   { 0x5, "National (nation of local server)" },
771   { 0x6, "Extended, National"                },
772   { 0x7, "Extended, Mission Defined"         },
773   { 0,   NULL } };
774
775 #define MAX_NATIONAL_VALUES 56
776 /* Will be built in build_national_strings() */
777 static value_string nat_pol_id[MAX_NATIONAL_VALUES+1];
778
779 /* For name we use the ISO 3166-1 Alfa-3 value for the country,
780  * for description we use the Country Name and
781  * for value we use the DMP value for National Policy Identifier.
782  */
783 static enum_val_t dmp_national_values[MAX_NATIONAL_VALUES+1] = {
784   { "???",  "None", 0x00 },
785   { "alb",  "Albania", 0x1B },
786   { "arm",  "Armenia", 0x20 },
787   { "aut",  "Austria", 0x21 },
788   { "aze",  "Azerbaijan", 0x22 },
789   { "blr",  "Belarus", 0x23 },
790   { "bel",  "Belgium", 0x01 },
791   { "bih",  "Bosnia and Hercegowina", 0x24 },
792   { "bgr",  "Bulgaria", 0x02 },
793   { "can",  "Canada", 0x03 },
794   { "hrv",  "Croatia", 0x1C },
795   { "cze",  "Czech Republic", 0x04 },
796   { "dnk",  "Denmark", 0x05 },
797   { "est",  "Estonia", 0x06 },
798   { "eapc", "Euro-Atlantic Partnership Council (EAPC)", 0x3A },
799   { "eu",   "European Union (EU)", 0x3B },
800   { "fin",  "Finland", 0x25 },
801   { "mkd",  "Former Yugoslav Republic of Macedonia", 0x26 },
802   { "fra",  "France", 0x07 },
803   { "geo",  "Georgia", 0x27 },
804   { "deu",  "Germany", 0x08 },
805   { "grc",  "Greece", 0x09 },
806   { "hun",  "Hungary", 0x0A },
807   { "isl",  "Iceland", 0x0B },
808   { "isaf", "International Security Assistance Force (ISAF)", 0x3C },
809   { "irl",  "Ireland", 0x28 },
810   { "ita",  "Italy", 0x0C },
811   { "kaz",  "Kazakhstan", 0x29 },
812   { "kgz",  "Kyrgyztan", 0x2A },
813   { "lva",  "Latvia", 0x0D },
814   { "ltu",  "Lithuania", 0x0E },
815   { "lux",  "Luxembourg", 0x0F },
816   { "mlt",  "Malta", 0x2B },
817   { "mda",  "Moldova", 0x2C },
818   { "mne",  "Montenegro", 0x2D },
819   { "nld",  "Netherlands", 0x10 },
820   { "nor",  "Norway", 0x11 },
821   { "pfp",  "Partnership for Peace (PfP)", 0x3D },
822   { "pol",  "Poland", 0x12 },
823   { "ptr",  "Portugal", 0x13 },
824   { "rou",  "Romania", 0x14 },
825   { "rus",  "Russian Federation", 0x2E },
826   { "srb",  "Serbia", 0x2F },
827   { "svk",  "Slovakia", 0x15 },
828   { "svn",  "Slovenia", 0x16 },
829   { "esp",  "Spain", 0x17 },
830   { "swe",  "Sweden", 0x30 },
831   { "che",  "Switzerland", 0x31 },
832   { "tjk",  "Tajikistan", 0x32 },
833   { "tur",  "Turkey", 0x18 },
834   { "tkm",  "Turkmenistan", 0x33 },
835   { "gbr",  "United Kingdom", 0x19 },
836   { "usa",  "United States", 0x1A },
837   { "ukr",  "Ukraine", 0x34 },
838   { "uzb",  "Uzbekistan", 0x35 },
839   { "weu",  "Western European Union (WEU)", 0x3E },
840   { NULL, NULL, 0 }
841 };
842
843 static const value_string ext_sec_cat[] = {
844   { 0x0, "Not present"                  },
845   { 0x1, "Permissive category follows"  },
846   { 0x2, "Restrictive category follows" },
847   { 0x3, "Reserved"                     },
848   { 0,   NULL } };
849
850 static const value_string sic_key_type[] = {
851   { 0xc, "2 or more 3-character SICs"      },
852   { 0xd, "1 or more 3-to-8 character SICs" },
853   { 0,   NULL } };
854
855 static const true_false_string sic_key_chars = {
856   "Any", "[A-Z0-9] only"
857 };
858
859 static const value_string sic_key_num[] = {
860   { 0, "1"  },
861   { 1, "2"  },
862   { 2, "3"  },
863   { 3, "4"  },
864   { 4, "5"  },
865   { 5, "6"  },
866   { 6, "7"  },
867   { 7, "8"  },
868   { 0, NULL } };
869
870
871 static const value_string sic_bit_vals[] = {
872   { 0,   "length:6, bytes:4" },
873   { 1,   "length:6, bytes:4" },
874   { 2,   "length:6, bytes:4" },
875   { 3,   "length:6, bytes:4" },
876   { 4,   "length:6, bytes:4" },
877   { 5,   "length:6, bytes:4" },
878   { 6,   "length:6, bytes:4" },
879   { 7,   "length:6, bytes:4" },
880   { 8,   "length:6, bytes:4" },
881   { 9,   "reserved"          },
882   { 10,  "length:5, bytes:4" },
883   { 11,  "length:8, bytes:6" },
884   { 12,  "length:4, bytes:3" },
885   { 13,  "length:4, bytes:3" },
886   { 14,  "length:7, bytes:5" },
887   { 15,  "length:7, bytes:5" },
888   { 0,   NULL } };
889
890 static const value_string sic_bit_any_vals[] = {
891   { 0,   "length:5, bytes:4" },
892   { 1,   "length:5, bytes:4" },
893   { 2,   "length:5, bytes:4" },
894   { 3,   "length:5, bytes:4" },
895   { 4,   "length:5, bytes:4" },
896   { 5,   "length:5, bytes:4" },
897   { 6,   "length:5, bytes:4" },
898   { 7,   "length:5, bytes:4" },
899   { 8,   "length:5, bytes:4" },
900   { 9,   "length:8, bytes:7" },
901   { 10,  "length:4, bytes:4" },
902   { 11,  "length:7, bytes:6" },
903   { 12,  "length:6, bytes:5" },
904   { 13,  "length:6, bytes:5" },
905   { 14,  "length:6, bytes:5" },
906   { 15,  "length:6, bytes:5" },
907   { 0,   NULL } };
908
909 static const value_string body_format_vals[] = {
910   { 0x0, "Free text"                    },
911   { 0x1, "Free text including subject"  },
912   { 0x2, "Structured"                   },
913   { 0x3, "Reserved"                     },
914   { 0,   NULL } };
915
916 static const value_string eit_vals[] = {
917   { 0x0, "Empty"                             },
918   { 0x1, "IA5-text"                          },
919   { 0x2, "General text"                      },
920   { 0x3, "Bilaterally defined (binary data)" },
921   { 0x4, "AdatP-3"                           },
922   { 0x5, "Reserved"                          },
923   { 0x6, "Reserved"                          },
924   { 0x7, "Reserved"                          },
925   { 0,   NULL } };
926
927 static const value_string compression_vals[] = {
928   { 0x0, "No compression"  },
929   { 0x1, "ZLib compressed" },
930   { 0x2, "Reserved"        },
931   { 0x3, "Reserved"        },
932   { 0,   NULL } };
933
934 static const value_string ack_reason [] = {
935   { 0x00, "Successful, positive acknowledgement" },
936   { 0x01, "Unspecified error"                    },
937   { 0x02, "Checksum incorrect"                   },
938   { 0,    NULL } };
939
940 static const value_string non_del_reason [] = {
941   { 0x3D, "Unknown reason"                     },
942   { 0x3E, "Reason code greater than 0x3c (60)" },
943   { 0x3F, "Reserved"                           },
944   { 0,    NULL } };
945
946 static const value_string non_del_diagn [] = {
947   { 0x7C, "Diagnostic not specified"                },
948   { 0x7D, "Unknown diagnostic"                      },
949   { 0x7E, "Diagnostic code greater than 0x7b (123)" },
950   { 0x7F, "Reserved"                                },
951   { 0,    NULL } };
952
953 static const value_string discard_reason [] = {
954   { 0xFE, "Discard Reason absent" },
955   { 0xFF, "Reserved"              },
956   { 0,    NULL } };
957
958 static const value_string on_type [] = {
959   { 0x00, "acp127-nn" },
960   { 0x01, "acp127-pn" },
961   { 0x02, "acp127-tn" },
962   { 0,    NULL } };
963
964 static const value_string ack_msg_type [] = {
965   { STANAG, " (message)" },
966   { IPM,    " (e-mail)"  },
967   { REPORT, " (report)"  },
968   { NOTIF,  " (notif)"   },
969   { ACK,    " (ack)"     },
970   { 0,      NULL } };
971
972 static enum_val_t struct_id_options[] = {
973   { "none",    "None",                        STRUCT_ID_NONE     },
974   { "1byte",   "1 Byte value",                STRUCT_ID_UINT8    },
975   { "2byte",   "2 Byte value",                STRUCT_ID_UINT16   },
976   { "4byte",   "4 Byte value",                STRUCT_ID_UINT32   },
977   { "8byte",   "8 Byte value",                STRUCT_ID_UINT64   },
978   { "fstring", "Fixed text string",           STRUCT_ID_STRING   },
979   { "zstring", "Zero terminated text string", STRUCT_ID_ZSTRING  },
980   { NULL,      NULL,                          0                  }
981 };
982
983 static enum_val_t national_decoding[] = {
984   { "none",    "None (raw data)", NAT_DECODE_NONE   },
985   { "dmp",     "As for regular",  NAT_DECODE_DMP    },
986   { "thales",  "Thales XOmail",   NAT_DECODE_THALES },
987   { NULL,      NULL, 0 }
988 };
989
990 static const value_string ipm_id_modifier[] = {
991   { 0x0,  "X.400 IPM Identifier" },
992   { 0x1,  "Nationally-defined"   },
993   { 0x2,  "Nationally-defined"   },
994   { 0x3,  "Nationally-defined"   },
995   { 0, NULL }
996 };
997
998 static const value_string thales_ipm_id_modifier[] = {
999   { 0x0,  "X.400 IPM Identifier" },
1000   { 0x1,  "3 or 5 digits"        },
1001   { 0x2,  "4 digits"             },
1002   { 0x3,  "5 digits"             },
1003   { 0, NULL }
1004 };
1005
1006 UAT_VS_DEF(dmp_security_class, nation, dmp_security_class_t, 0, "None")
1007 UAT_DEC_CB_DEF(dmp_security_class, sec_class, dmp_security_class_t)
1008 UAT_CSTRING_CB_DEF(dmp_security_class, name, dmp_security_class_t)
1009
1010 static void *
1011 dmp_class_copy_cb(void *dest, const void *orig, size_t len _U_)
1012 {
1013   dmp_security_class_t *u = (dmp_security_class_t *)dest;
1014   const dmp_security_class_t *o = (const dmp_security_class_t *)orig;
1015
1016   u->nation = o->nation;
1017   u->sec_class = o->sec_class;
1018   u->name = g_strdup(o->name);
1019
1020   return dest;
1021 }
1022
1023 static void
1024 dmp_class_free_cb(void *r)
1025 {
1026   dmp_security_class_t *u = (dmp_security_class_t *)r;
1027
1028   g_free(u->name);
1029 }
1030
1031 static gchar *dmp_national_sec_class (guint nation, guint dmp_sec_class)
1032 {
1033   guint i;
1034
1035   for (i = 0; i < num_dmp_security_classes; i++) {
1036     dmp_security_class_t *u = &(dmp_security_classes[i]);
1037
1038     if (u->nation == nation && u->sec_class == dmp_sec_class) {
1039       return u->name;
1040     }
1041   }
1042
1043   return NULL;
1044 }
1045
1046 static void build_national_strings (void)
1047 {
1048   gint i = 0;
1049
1050   /*
1051   ** We use values from dmp_national_values to build value_string for nat_pol_id.
1052   */
1053   while (dmp_national_values[i].name && i < MAX_NATIONAL_VALUES) {
1054     nat_pol_id[i].value  = dmp_national_values[i].value;
1055     nat_pol_id[i].strptr = dmp_national_values[i].description;
1056     i++;
1057   }
1058   nat_pol_id[i].value = 0;
1059   nat_pol_id[i].strptr = NULL;
1060 }
1061
1062 static const gchar *get_nat_pol_id_short (gint nation)
1063 {
1064   gint i = 0;
1065   while (dmp_national_values[i].name) {
1066     if (dmp_national_values[i].value == nation) {
1067       return dmp_national_values[i].name;
1068     }
1069     i++;
1070   }
1071
1072   return "???";
1073 }
1074
1075 static const gchar *msg_type_to_str (void)
1076 {
1077   const gchar *msg_type;
1078   gboolean     have_msg = FALSE;
1079
1080   switch (dmp.msg_type) {
1081
1082   case STANAG:
1083     /* Include message type and precedence */
1084     msg_type = ep_strdup_printf ("%s (%s) [%s]",
1085                 val_to_str (dmp.msg_type, type_vals, "Unknown"),
1086                 val_to_str (dmp.st_type, message_type_vals, "Unknown"),
1087                 (dmp.prec == 0x6 || dmp.prec == 0x7) ?
1088                 val_to_str (dmp.prec-4, precedence, "Unknown") :
1089                 val_to_str (dmp.prec, precedence, "Unknown"));
1090     break;
1091
1092   case IPM:
1093     /* Include importance */
1094     msg_type = ep_strdup_printf ("%s [%s]",
1095                 val_to_str (dmp.msg_type, type_vals, "Unknown"),
1096                 val_to_str (dmp.prec, importance, "Unknown"));
1097     break;
1098
1099   case REPORT:
1100     /* Include report types included */
1101     msg_type = ep_strdup_printf ("Report (%s%s%s)",
1102                 dmp.dr ? "DR" : "", (dmp.dr && dmp.ndr) ? " and " : "",
1103                 dmp.ndr ? "NDR" : "");
1104     break;
1105
1106   case NOTIF:
1107     msg_type = val_to_str (dmp.notif_type, notif_type, "Unknown");
1108     break;
1109
1110   case ACK:
1111     /* If we have msg_time we have a matching packet */
1112     have_msg = (dmp.id_val &&
1113                 (dmp.id_val->msg_time.secs>0 || dmp.id_val->msg_time.nsecs>0));
1114     msg_type = ep_strdup_printf ( "Acknowledgement%s%s",
1115                 have_msg ? val_to_str (dmp.id_val->msg_type, ack_msg_type,
1116                                        " (unknown:%d)") : "",
1117                 dmp.ack_reason ? " [negative]" : "");
1118     break;
1119
1120   default:
1121     msg_type = "Unknown";
1122     break;
1123   }
1124
1125   return msg_type;
1126 }
1127
1128 static const gchar *non_del_reason_str (guint32 value)
1129 {
1130   if (value < 0x3D) {
1131     /* Standard values according to P1 */
1132     return val_to_str (value, p1_NonDeliveryReasonCode_vals, "Unknown");
1133   } else {
1134     return val_to_str (value, non_del_reason, "Unknown");
1135   }
1136 }
1137
1138 static const gchar *non_del_diagn_str (guint32 value)
1139 {
1140   if (value < 0x7C) {
1141     /* Standard values according to P1 */
1142     return val_to_str (value, p1_NonDeliveryDiagnosticCode_vals, "Unknown");
1143   } else {
1144     return val_to_str (value, non_del_diagn, "Unknown");
1145   }
1146 }
1147
1148 static const gchar *nrn_reason_str (guint32 value)
1149 {
1150   /* Standard values according to P22 */
1151   return val_to_str (value, p22_NonReceiptReasonField_vals, "Reserved");
1152 }
1153
1154 static const gchar *discard_reason_str (guint32 value)
1155 {
1156   if (value < 0xFE) {
1157     /* Standard values according to P22 */
1158     return val_to_str (value, p22_DiscardReasonField_vals, "Reserved");
1159   } else {
1160     return val_to_str (value, discard_reason, "Unknown");
1161   }
1162 }
1163
1164 /* Ref chapter 6.2.8.10 TimeDifference */
1165 static gint32 dmp_dec_time_diff (guint8 dmp_time_diff)
1166 {
1167   gint32 time_diff = 0;
1168
1169   if (dmp_time_diff <= 0x01) {
1170     /* Reserved - low value */
1171     time_diff = DMP_TIME_RESERVED;
1172   } else if (dmp_time_diff <= 0x1D) {
1173     /* Number of 2-second units (2-58 seconds) */
1174     time_diff = dmp_time_diff * 2;
1175   } else if (dmp_time_diff <= 0x91) {
1176     /* Number of 15-second units (1 min - 29 min 45 sec) */
1177     time_diff = (dmp_time_diff - 0x1D + 3) * 15;
1178   } else if (dmp_time_diff  <= 0xDF) {
1179     /* Number of 5-minute units (30 min - 6 hours 55 min) */
1180     time_diff = (dmp_time_diff - 0x91 + 5) * 5*60;
1181   } else if (dmp_time_diff <= 0xF7) {
1182     /* Number of 30-minute units (7 hours - 18 hours 30 min) */
1183     time_diff = (dmp_time_diff - 0xDF + 7) * 30*60;
1184   } else {
1185     /* Reserved - high value */
1186     time_diff = DMP_TIME_RESERVED;
1187   }
1188
1189   return time_diff;
1190 }
1191
1192 /*
1193  * Ref chapter 6.3.7.2.10 ExpiryTime
1194  * and chapter 6.3.9.2.2  DeliveryTime
1195  */
1196 static gint32 dmp_dec_exp_del_time (guint8 timev, gboolean expiry_time)
1197 {
1198   gint32 time_value = 0;
1199
1200   if (expiry_time && (timev == 0x00)) {
1201     /* No expiry time */
1202     time_value = DMP_TIME_NOT_PRESENT;
1203   } else if (timev <= 0x1D) {
1204     /* Number of 2-second units (2-58 seconds) */
1205     time_value = timev * 2;
1206   } else if (timev <= 0x91) {
1207     /* Number of 15-second units (1 min - 29 min 45 sec) */
1208     time_value = (timev - 0x1D + 3) * 15;
1209   } else if (timev <= 0xBB) {
1210     /* Number of 5-minute units (30 min - 3 hours 55 min) */
1211     time_value = (timev - 0x91 + 5) * 5*60;
1212   } else if (timev <= 0xE3) {
1213     /* Number of 30-minute units (4 hours - 23 hours 30 min) */
1214     time_value = (timev - 0xBB + 7) * 30*60;
1215   } else if (timev < 0xFF) {
1216     /* Number of 2-hour units (24 - 78 hours) */
1217     time_value = (timev - 0xE3 + 11) * 2*3600;
1218   } else {
1219     /* Reserved */
1220     time_value = DMP_TIME_RESERVED;
1221   }
1222
1223   return time_value;
1224 }
1225
1226 static gint32 dmp_dec_exp_time (guint8 expiry_time)
1227 {
1228   return dmp_dec_exp_del_time (expiry_time, TRUE);
1229 }
1230
1231 static gint32 dmp_dec_del_time (guint8 delivery_time)
1232 {
1233   return dmp_dec_exp_del_time (delivery_time, FALSE);
1234 }
1235
1236 /* Ref chapter 6.3.7.2.11 DTG */
1237 static gint32 dmp_dec_dtg (guint32 dtg)
1238 {
1239   gint32 value;
1240
1241   if (dtg == 0x00) {
1242     /* Not present */
1243     value = DMP_TIME_NOT_PRESENT;
1244   } else if (dtg <= 0x3C) {
1245     /* Number of minutes (0-59 min) */
1246     value = (dtg - 1) * 60;
1247   } else if (dtg <= 0x64) {
1248     /* Number of 15-minute units (1 hour - 10 hours 45 min) */
1249     value = (dtg - 0x3C + 3) * 15 * 60;
1250   } else if (dtg < 0x7F) {
1251     /* Number of hours (11-36 hours) */
1252     value = (dtg - 0x64 + 10) * 3600;
1253   } else {
1254     /* Reserved */
1255     value = DMP_TIME_RESERVED;
1256   }
1257
1258   return value;
1259 }
1260
1261 /*
1262  * Ref chapter 7.10.11.1 Submission time
1263  *
1264  * start_time                 (current time)
1265  * delta1     = E             (encoded submission time)
1266  * delta2     = C             (encoded current time)
1267  * 0x01C2     = Pn + 15min    (maximum point for S1)
1268  * 0x7E38     = Pn+1 - 15min  (minimum point for S3)
1269  * 0x7FF8     = Pn+1          (length of P (period))
1270  */
1271 static gint32 dmp_dec_subm_time (guint16 delta1, gint32 start_time)
1272 {
1273   gint32  subm_time = start_time;
1274   guint16 delta2;
1275
1276   delta2 = (guint16) ((subm_time / 2) % 0x7FF8);
1277
1278   if ((delta1 < 0x01C2) && (delta2 >= delta1 + 0x7E38)) {
1279     subm_time += 2 * (0x7FF8 - delta2 + delta1);
1280   } else if ((delta1 >= 0x01C2) && (delta2 < delta1 - 0x01C2)) {
1281     subm_time -= 2 * (0x7FF8 - delta1 + delta2);
1282   } else {
1283     subm_time -= 2 * (delta2 - delta1);
1284   }
1285
1286   return subm_time;
1287 }
1288
1289 /* Ref chapter 6.3.7.2.12 SIC */
1290 static gboolean dmp_dec_xbyte_sic (guint64 bin, gchar *sic,
1291                                    guint8 no_char, gboolean any)
1292 {
1293   gboolean failure = FALSE;
1294   gdouble  multiplier;
1295   guint8   i;
1296   guint64  p, tmp;
1297
1298   if (no_char >= MAX_SIC_LEN) {
1299     /* Illegal length */
1300     g_snprintf (sic, MAX_SIC_LEN, "Illegal length: %d", no_char);
1301     return TRUE;
1302   }
1303
1304   if (any) {
1305     multiplier = 74.0;
1306   } else {
1307     multiplier = 36.0;
1308   }
1309
1310   for (i = 0; i < no_char; i++) {
1311     p = (guint64) pow (multiplier, no_char - 1 - i);
1312     tmp = bin / p;
1313     bin -= tmp * p;
1314     sic[i] = (gchar) tmp;
1315     if (sic[i] <= 9) {
1316       sic[i] += '0';
1317     } else if (sic[i] <= 35) {
1318       sic[i] += ('A' - 10);
1319     } else if (!any) {
1320       sic[i] = '*';
1321       failure = TRUE;
1322     } else if (sic[i] <= 61) {
1323       sic[i] += ('a' - 36);
1324     } else if (sic[i] == 62) {
1325       sic[i] = '\'';
1326     } else if (sic[i] == 63) {
1327       sic[i] = '(';
1328     } else if (sic[i] == 64) {
1329       sic[i] = ')';
1330     } else if (sic[i] == 65) {
1331       sic[i] = '+';
1332     } else if (sic[i] == 66) {
1333       sic[i] = ',';
1334     } else if (sic[i] == 67) {
1335       sic[i] = '-';
1336     } else if (sic[i] == 68) {
1337       sic[i] = '.';
1338     } else if (sic[i] == 69) {
1339       sic[i] = '/';
1340     } else if (sic[i] == 70) {
1341       sic[i] = ':';
1342     } else if (sic[i] == 71) {
1343       sic[i] = '=';
1344     } else if (sic[i] == 72) {
1345       sic[i] = '?';
1346     } else if (sic[i] == 73) {
1347       sic[i] = ' ';
1348     } else {
1349       sic[i] = '*';
1350       failure = TRUE;
1351     }
1352   }
1353   sic[i] = '\0';
1354
1355   return failure;
1356 }
1357
1358 static guint dmp_id_hash (gconstpointer k)
1359 {
1360   dmp_id_key *dmpx=(dmp_id_key *)k;
1361   return dmpx->id;
1362 }
1363
1364 static gint dmp_id_hash_equal (gconstpointer k1, gconstpointer k2)
1365 {
1366   dmp_id_key *dmp1=(dmp_id_key *)k1;
1367   dmp_id_key *dmp2=(dmp_id_key *)k2;
1368   if (dmp1->id != dmp2->id)
1369     return 0;
1370
1371   return (ADDRESSES_EQUAL (&dmp1->src, &dmp2->src) &&
1372           ADDRESSES_EQUAL (&dmp1->dst, &dmp2->dst));
1373 }
1374
1375 static void register_dmp_id (packet_info *pinfo, guint8 reason)
1376 {
1377   dmp_id_val *dmp_data = NULL, *pkg_data = NULL;
1378   dmp_id_key *dmp_key = NULL;
1379   nstime_t    msg_time;
1380   guint       msg_id = 0;
1381
1382   if (pinfo->flags.in_error_pkt) {
1383     /* No analysis of error packets */
1384     return;
1385   }
1386
1387   nstime_set_zero(&msg_time);
1388
1389   dmp_key = se_new (dmp_id_key);
1390
1391   if (!pinfo->fd->flags.visited &&
1392       (dmp.msg_type == REPORT || dmp.msg_type == NOTIF))
1393   {
1394     /* Try to match corresponding message */
1395     dmp_key->id = (guint) dmp.subj_id;
1396     SE_COPY_ADDRESS(&dmp_key->src, &(pinfo->dst));
1397     SE_COPY_ADDRESS(&dmp_key->dst, &(pinfo->src));
1398
1399     dmp_data = (dmp_id_val *) g_hash_table_lookup (dmp_id_hash_table, dmp_key);
1400
1401     if (dmp_data) {
1402       /* Found message */
1403       if (dmp_data->prev_msg_id > 0) {
1404         msg_id = dmp_data->prev_msg_id;
1405       } else {
1406         msg_id = dmp_data->msg_id;
1407       }
1408       msg_time = dmp_data->msg_time;
1409     }
1410   }
1411
1412   if (dmp.msg_type == ACK) {
1413     dmp_key->id = (guint) dmp.subj_id;
1414     SE_COPY_ADDRESS(&dmp_key->src, &(pinfo->dst));
1415     SE_COPY_ADDRESS(&dmp_key->dst, &(pinfo->src));
1416   } else {
1417     dmp_key->id = (guint) dmp.msg_id;
1418     SE_COPY_ADDRESS(&dmp_key->src, &(pinfo->src));
1419     SE_COPY_ADDRESS(&dmp_key->dst, &(pinfo->dst));
1420   }
1421
1422   dmp_data = (dmp_id_val *) g_hash_table_lookup (dmp_id_hash_table, dmp_key);
1423
1424   if (!pinfo->fd->flags.visited) {
1425     if (dmp_data) {
1426       if (dmp.msg_type == ACK) {
1427         /* Only save this data if positive ack */
1428         if (reason == 0) {
1429           if (dmp_data->ack_id == 0) {
1430             /* Only save reference to first ACK */
1431             dmp_data->ack_id = pinfo->fd->num;
1432           } else {
1433             /* Only count when resending */
1434             dmp_data->ack_resend_count++;
1435           }
1436         }
1437       } else {
1438         /* Message resent */
1439         dmp_data->msg_resend_count++;
1440         dmp_data->prev_msg_id = pinfo->fd->num;
1441         dmp_data->prev_msg_time = dmp_data->msg_time;
1442         dmp_data->msg_time = pinfo->fd->abs_ts;
1443       }
1444     } else {
1445       /* New message */
1446       dmp_data = se_new0 (dmp_id_val);
1447       dmp_data->msg_type = dmp.msg_type;
1448
1449       if (dmp.msg_type == ACK) {
1450         /* No matching message for this ack */
1451         dmp_data->ack_id = pinfo->fd->num;
1452       } else {
1453         dmp_data->first_msg_time = pinfo->fd->abs_ts;
1454         dmp_data->msg_time = pinfo->fd->abs_ts;
1455
1456         if (dmp.msg_type == REPORT) {
1457           dmp_data->rep_id = pinfo->fd->num;
1458           dmp_data->msg_id = msg_id;
1459           dmp_data->rep_not_msg_time = msg_time;
1460         } else if (dmp.msg_type == NOTIF) {
1461           dmp_data->not_id = pinfo->fd->num;
1462           dmp_data->msg_id = msg_id;
1463           dmp_data->rep_not_msg_time = msg_time;
1464         } else {
1465           dmp_data->msg_id = pinfo->fd->num;
1466         }
1467
1468         g_hash_table_insert (dmp_id_hash_table, dmp_key, dmp_data);
1469       }
1470     }
1471
1472     pkg_data = se_new (dmp_id_val);
1473     *pkg_data = *dmp_data;
1474     p_add_proto_data (pinfo->fd, proto_dmp, pkg_data);
1475   } else {
1476     /* Fetch last values from data saved in packet */
1477     pkg_data = (dmp_id_val *)p_get_proto_data (pinfo->fd, proto_dmp);
1478
1479     if (dmp_data && pkg_data && dmp.msg_type != ACK && pkg_data->ack_id == 0) {
1480       pkg_data->ack_id = dmp_data->ack_id;
1481     }
1482   }
1483
1484   DISSECTOR_ASSERT (pkg_data);
1485   dmp.id_val = pkg_data;
1486 }
1487
1488 static void dmp_add_seq_ack_analysis (tvbuff_t *tvb, packet_info *pinfo,
1489                                       proto_tree *dmp_tree, gint offset)
1490 {
1491   proto_tree *analysis_tree = NULL;
1492   proto_item *en = NULL, *eh = NULL;
1493   nstime_t    ns;
1494
1495   if (dmp.msg_type > ACK || (dmp.msg_type < ACK && !dmp.checksum) ||
1496       dmp.id_val == NULL || pinfo->flags.in_error_pkt)
1497   {
1498     /* No need for seq/ack analysis */
1499     return;
1500   }
1501
1502   en = proto_tree_add_text (dmp_tree, tvb, 0, 0, "SEQ/ACK analysis");
1503   PROTO_ITEM_SET_GENERATED (en);
1504   analysis_tree = proto_item_add_subtree (en, ett_analysis);
1505
1506   if ((dmp.msg_type == STANAG) || (dmp.msg_type == IPM) ||
1507       (dmp.msg_type == REPORT) || (dmp.msg_type == NOTIF)) {
1508     if (dmp.id_val->ack_id) {
1509       en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_num, tvb,
1510                                 0, 0, dmp.id_val->ack_id);
1511       PROTO_ITEM_SET_GENERATED (en);
1512       if (!dmp.checksum) {
1513         proto_item_append_text (en, " (unexpected)");
1514         expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1515                                 "Unexpected ACK");
1516       }
1517     } else if (dmp.checksum && !dmp.id_val->msg_resend_count) {
1518       en = proto_tree_add_item (analysis_tree, hf_analysis_ack_missing, tvb, offset, 0, ENC_NA);
1519       if (pinfo->fd->flags.visited) {
1520         /* We do not know this on first visit and we do not want to
1521            add a entry in the "Expert Severity Info" for this note */
1522         expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1523                                 "Acknowledgement missing");
1524         PROTO_ITEM_SET_GENERATED (en);
1525       }
1526     }
1527
1528     if (dmp.msg_type == REPORT) {
1529       if (dmp.id_val->msg_id) {
1530         en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_num,
1531                                   tvb, 0, 0, dmp.id_val->msg_id);
1532         PROTO_ITEM_SET_GENERATED (en);
1533
1534         nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->rep_not_msg_time);
1535         en = proto_tree_add_time (analysis_tree, hf_analysis_rep_time,
1536                                   tvb, 0, 0, &ns);
1537         PROTO_ITEM_SET_GENERATED (en);
1538       } else {
1539         en = proto_tree_add_item (analysis_tree, hf_analysis_msg_missing, tvb, 0, 0, ENC_NA);
1540         PROTO_ITEM_SET_GENERATED (en);
1541
1542         expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1543                                 "Message missing");
1544       }
1545     } else if (dmp.msg_type == NOTIF) {
1546       if (dmp.id_val->msg_id) {
1547         en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_num,
1548                                   tvb, 0, 0, dmp.id_val->msg_id);
1549         PROTO_ITEM_SET_GENERATED (en);
1550
1551         nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->rep_not_msg_time);
1552         en = proto_tree_add_time (analysis_tree, hf_analysis_not_time,
1553                                   tvb, 0, 0, &ns);
1554         PROTO_ITEM_SET_GENERATED (en);
1555       } else {
1556         en = proto_tree_add_item (analysis_tree, hf_analysis_msg_missing, tvb, 0, 0, ENC_NA);
1557         PROTO_ITEM_SET_GENERATED (en);
1558
1559         expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1560                                 "Message missing");
1561       }
1562     }
1563
1564     if (dmp.id_val->msg_resend_count) {
1565       en = proto_tree_add_uint (analysis_tree, hf_analysis_retrans_no,
1566                                 tvb, 0, 0, dmp.id_val->msg_resend_count);
1567       PROTO_ITEM_SET_GENERATED (en);
1568
1569       expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1570                               "Retransmission #%d",
1571                               dmp.id_val->msg_resend_count);
1572
1573       if (dmp.msg_type == REPORT) {
1574         en = proto_tree_add_uint (analysis_tree, hf_analysis_rep_resend_from,
1575                                   tvb, 0, 0, dmp.id_val->rep_id);
1576       } else if (dmp.msg_type == NOTIF) {
1577         en = proto_tree_add_uint (analysis_tree, hf_analysis_not_resend_from,
1578                                   tvb, 0, 0, dmp.id_val->not_id);
1579       } else {
1580         en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_resend_from,
1581                                   tvb, 0, 0, dmp.id_val->msg_id);
1582       }
1583       PROTO_ITEM_SET_GENERATED (en);
1584
1585       nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->prev_msg_time);
1586       en = proto_tree_add_time (analysis_tree, hf_analysis_retrans_time,
1587                                 tvb, 0, 0, &ns);
1588       PROTO_ITEM_SET_GENERATED (en);
1589
1590       nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->first_msg_time);
1591       eh = proto_tree_add_time (analysis_tree, hf_analysis_total_retrans_time,
1592                                 tvb, 0, 0, &ns);
1593       PROTO_ITEM_SET_GENERATED (eh);
1594
1595       if (dmp.id_val->first_msg_time.secs == dmp.id_val->prev_msg_time.secs &&
1596           dmp.id_val->first_msg_time.nsecs == dmp.id_val->prev_msg_time.nsecs) {
1597         /* Time values does not differ, hide the total time */
1598         PROTO_ITEM_SET_HIDDEN (eh);
1599       }
1600     }
1601   } else if (dmp.msg_type == ACK) {
1602     if (dmp.id_val->msg_type != ACK) {
1603       if (dmp.id_val->msg_type == REPORT) {
1604         en = proto_tree_add_uint (analysis_tree, hf_analysis_rep_num,
1605                                   tvb, 0, 0, dmp.id_val->rep_id);
1606       } else if (dmp.id_val->msg_type == NOTIF) {
1607         en = proto_tree_add_uint (analysis_tree, hf_analysis_not_num,
1608                                   tvb, 0, 0, dmp.id_val->not_id);
1609       } else {
1610         en = proto_tree_add_uint (analysis_tree, hf_analysis_msg_num,
1611                                   tvb, 0, 0, dmp.id_val->msg_id);
1612       }
1613       PROTO_ITEM_SET_GENERATED (en);
1614
1615       nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->msg_time);
1616       en = proto_tree_add_time (analysis_tree, hf_analysis_ack_time,
1617                                 tvb, 0, 0, &ns);
1618       PROTO_ITEM_SET_GENERATED (en);
1619
1620       nstime_delta (&ns, &pinfo->fd->abs_ts, &dmp.id_val->first_msg_time);
1621       eh = proto_tree_add_time (analysis_tree, hf_analysis_total_time,
1622                                 tvb, 0, 0, &ns);
1623       PROTO_ITEM_SET_GENERATED (eh);
1624
1625       if (dmp.id_val->first_msg_time.secs == dmp.id_val->msg_time.secs &&
1626           dmp.id_val->first_msg_time.nsecs == dmp.id_val->msg_time.nsecs) {
1627         /* Time values does not differ, hide the total time */
1628         PROTO_ITEM_SET_HIDDEN (eh);
1629       } else {
1630         /* Different times, add a reference to the message we have ack'ed */
1631         proto_item_append_text (en, " (from frame %d)",
1632                                 dmp.id_val->prev_msg_id);
1633       }
1634     } else {
1635       en = proto_tree_add_item (analysis_tree, hf_analysis_msg_missing, tvb, 0, 0, ENC_NA);
1636       PROTO_ITEM_SET_GENERATED (en);
1637
1638       expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1639                               "Message missing");
1640     }
1641
1642     if (dmp.id_val->ack_resend_count) {
1643       en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_dup_no,
1644                                 tvb, 0, 0, dmp.id_val->ack_resend_count);
1645       PROTO_ITEM_SET_GENERATED (en);
1646
1647       expert_add_info_format (pinfo, en, PI_SEQUENCE, PI_NOTE,
1648                               "Dup ACK #%d", dmp.id_val->ack_resend_count);
1649
1650       en = proto_tree_add_uint (analysis_tree, hf_analysis_ack_resend_from,
1651                                 tvb, 0, 0, dmp.id_val->ack_id);
1652       PROTO_ITEM_SET_GENERATED (en);
1653     }
1654   }
1655 }
1656
1657 static gchar *dissect_7bit_string (tvbuff_t *tvb, gint offset, gint length)
1658 {
1659   guchar *encoded = tvb_get_ephemeral_string (tvb, offset, length);
1660   guchar *decoded = ep_alloc0 ((size_t)(length * 1.2) + 1);
1661   guchar  rest = 0, bits = 1;
1662   gint    len = 0, i;
1663
1664   for (i = 0; i < length; i++) {
1665     decoded[len++] = encoded[i] >> bits | rest;
1666     rest = (encoded[i] << (7 - bits) & 0x7F);
1667     if (bits == 7) {
1668       decoded[len++] = rest;
1669       bits = 1;
1670       rest = 0;
1671     } else {
1672       bits++;
1673     }
1674   }
1675
1676   return (gchar *) decoded;
1677 }
1678
1679 static gchar *dissect_thales_mts_id (tvbuff_t *tvb, gint offset, gint length)
1680 {
1681   /* Thales XOmail uses this format: "MTA-NAME/000000000000" */
1682   if (length >= 7 && length <= 22) {
1683     return ep_strdup_printf ("%s/%08X%04X",
1684                              dissect_7bit_string (tvb, offset, length - 6),
1685                              tvb_get_ntohl (tvb, offset + length - 6),
1686                              tvb_get_ntohs (tvb, offset + length - 2));
1687   }
1688
1689   return ILLEGAL_FORMAT;
1690 }
1691
1692 static gchar *dissect_thales_ipm_id (tvbuff_t *tvb, gint offset, gint length, gint modifier)
1693 {
1694   /* Thales XOmail uses this format: "<prefix>0000 YYMMDDhhmmssZ" */
1695   if (length >= 6 && length <= 20 && modifier >= 0 && modifier <= 2) {
1696     guint number = tvb_get_ntohs (tvb, offset + length - 6);
1697     guint8 number_len = modifier + 2;
1698     time_t time = tvb_get_ntohl(tvb, offset + length - 4);
1699     struct tm *tmp = gmtime(&time);
1700
1701     if (modifier == 1 && number >= 1024) {
1702       /* The number is in the range 65536-99999 */
1703       number_len = 5;
1704       number += (65536 - 1024);
1705     }
1706
1707     return ep_strdup_printf ("%s%0*d %02d%02d%02d%02d%02d%02dZ",
1708                              (length == 6) ? "" : dissect_7bit_string (tvb, offset, length - 6),
1709                              number_len, number,
1710                              tmp->tm_year % 100, tmp->tm_mon + 1, tmp->tm_mday,
1711                              tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
1712   }
1713
1714   return ILLEGAL_FORMAT;
1715 }
1716
1717 /* Ref chapter 6.3.7.2.12 SIC */
1718 static gint dissect_dmp_sic (tvbuff_t *tvb, packet_info *pinfo,
1719                              proto_tree *message_tree, gint offset)
1720 {
1721   proto_tree *sic_tree = NULL, *bitmap_tree = NULL, *key_tree = NULL;
1722   proto_item *sf = NULL, *bf = NULL, *kf = NULL;
1723   guint64     value;
1724   guint8      key, bitmap, no, i, length = 0;
1725   gboolean    any, no_sic = FALSE, failure = FALSE;
1726   gint        bytes = 0, boffset = offset;
1727   gchar      *sic = NULL;
1728
1729   key = tvb_get_guint8 (tvb, offset);
1730   sic = ep_alloc (MAX_SIC_LEN);
1731
1732   if (key <= 0xB6) {
1733     /* 2 bytes, single 3-character SIC, characters [A-Z0-9] only */
1734
1735     value = tvb_get_ntohs (tvb, offset);
1736     failure = dmp_dec_xbyte_sic (value, sic, 3, FALSE);
1737     sf = proto_tree_add_string_format (message_tree, hf_message_sic, tvb,
1738                                        offset, 2, sic,
1739                                        "SIC: %s [A-Z0-9 only]%s", sic,
1740                                        failure ? " (invalid)": "");
1741     if (failure) {
1742       expert_add_info_format (pinfo, sf, PI_UNDECODED, PI_NOTE, "Illegal SIC");
1743     }
1744     offset += 2;
1745
1746   } else if (key <= 0xBD) {
1747     /* 3 bytes, single 3-character SIC, any valid character */
1748
1749     value = tvb_get_ntohl (tvb, offset);
1750     value = (value >> 8) & 0x48FFFF;
1751     failure = dmp_dec_xbyte_sic (value, sic, 3, TRUE);
1752     sf = proto_tree_add_string_format (message_tree, hf_message_sic, tvb,
1753                                        offset, 3, sic,
1754                                        "SIC: %s [any character]%s", sic,
1755                                        failure ? " (invalid)": "");
1756     if (failure) {
1757       expert_add_info_format (pinfo, sf, PI_UNDECODED, PI_NOTE, "Illegal SIC");
1758     }
1759     offset += 3;
1760
1761   } else if (key <= 0xBF) {
1762     /* Reserved (not used) */
1763     g_snprintf (sic, MAX_SIC_LEN, "Reserved");
1764     no_sic = TRUE;
1765
1766   } else if (key <= 0xCF) {
1767     /* 2 or more 3-character SICs */
1768
1769     sf = proto_tree_add_item (message_tree, hf_message_sic_key, tvb, offset, 1, ENC_NA);
1770     sic_tree = proto_item_add_subtree (sf, ett_message_sic);
1771
1772     kf = proto_tree_add_item (sic_tree, hf_message_sic_key_values, tvb, offset, 1, ENC_BIG_ENDIAN);
1773     key_tree = proto_item_add_subtree (kf, ett_message_sic_key);
1774
1775     proto_tree_add_item (key_tree, hf_message_sic_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1776     proto_tree_add_item (key_tree, hf_message_sic_key_chars, tvb, offset, 1, ENC_BIG_ENDIAN);
1777     proto_tree_add_item (key_tree, hf_message_sic_key_num, tvb, offset, 1, ENC_BIG_ENDIAN);
1778     offset += 1;
1779
1780     any = (key & 0x08);
1781     no = (key & 0x07) + 1;
1782     for (i = 0; i < no; i++) {
1783       if (any) {
1784         value = tvb_get_ntohl (tvb, offset);
1785         value = (value >> 8) & 0x48FFFF;
1786         bytes = 3;
1787       } else {
1788         value = tvb_get_ntohs (tvb, offset);
1789         bytes = 2;
1790       }
1791       failure = dmp_dec_xbyte_sic (value, sic, 3, any);
1792       bf = proto_tree_add_string_format (sic_tree, hf_message_sic, tvb,
1793                                          offset, bytes, sic,
1794                                          "SIC %d: %s%s", i + 1, sic,
1795                                          failure ? " (invalid)": "");
1796       if (failure) {
1797         expert_add_info_format (pinfo, bf, PI_UNDECODED, PI_NOTE,
1798                                 "Illegal SIC");
1799       }
1800       offset += bytes;
1801     }
1802     proto_item_append_text (sf, ": %d (3 %s character)", no,
1803                             any ? "any" : "[A-Z0-9]");
1804
1805   } else if (key <= 0xDF) {
1806     /* 1 or more 3 to 8 character SICs */
1807
1808     sf = proto_tree_add_item (message_tree, hf_message_sic_key, tvb, offset, 1, ENC_NA);
1809     sic_tree = proto_item_add_subtree (sf, ett_message_sic);
1810
1811     kf = proto_tree_add_item (sic_tree, hf_message_sic_key_values, tvb, offset, 1, ENC_BIG_ENDIAN);
1812     key_tree = proto_item_add_subtree (kf, ett_message_sic_key);
1813
1814     proto_tree_add_item (key_tree, hf_message_sic_key_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1815     proto_tree_add_item (key_tree, hf_message_sic_key_chars, tvb, offset, 1, ENC_BIG_ENDIAN);
1816     proto_tree_add_item (key_tree, hf_message_sic_key_num, tvb, offset, 1, ENC_BIG_ENDIAN);
1817     offset += 1;
1818
1819     bitmap = tvb_get_guint8 (tvb, offset);
1820     bf = proto_tree_add_uint_format (sic_tree, hf_message_sic_bitmap, tvb,
1821                                      offset, 1, bitmap,
1822                                      "Length Bitmap: 0x%2.2x", bitmap);
1823     bitmap_tree = proto_item_add_subtree (bf, ett_message_sic_bitmap);
1824     proto_tree_add_item (bitmap_tree, hf_message_sic_bitmap, tvb, offset, 1, ENC_BIG_ENDIAN);
1825
1826     any = (key & 0x08);
1827     no = (key & 0x07) + 1;
1828     offset += 1;
1829
1830     for (i = 0; i < no; i++) {
1831       if (bitmap & (1 << (7 - i))) {
1832         /* 4 - 8 character */
1833         key = tvb_get_guint8 (tvb, offset);
1834         if (any) {
1835           /* Any valid characters */
1836           if ((key & 0xF0) == 0xA0) {        /* bit 7-4: 1010 */
1837             length = 4;
1838             bytes = 4;
1839             value = tvb_get_ntohl (tvb, offset) & 0x0FFFFFFF;
1840           } else if ((key & 0xC0) == 0xC0) { /* bit 7-4: 11xx */
1841             length = 6;
1842             bytes = 5;
1843             value = ((guint64)key & 0x3F)<<32|tvb_get_ntohl (tvb, offset + 1);
1844           } else if ((key & 0xF0) == 0xB0) { /* bit 7-4: 1011 */
1845             length = 7;
1846             bytes = 6;
1847             value = ((guint64)tvb_get_ntohs (tvb, offset) & 0x0FFF) << 32 |
1848               tvb_get_ntohl (tvb, offset + 2);
1849           } else if ((key & 0xF0) == 0x90) { /* bit 7-4: 1001 */
1850             length = 8;
1851             bytes = 7;
1852             value = ((guint64)(tvb_get_ntohl (tvb, offset)>>8) & 0x0FFF)<<32 |
1853               tvb_get_ntohl (tvb, offset + 3);
1854           } else {                           /* bit 7-4: 0xxx or 1000 */
1855             length = 5;
1856             bytes = 4;
1857             value = tvb_get_ntohl (tvb, offset);
1858           }
1859         } else {
1860           /* Characterts [A-Z0-9] only */
1861           if ((key & 0xE0) == 0xC0) {        /* bit 7-4: 110x */
1862             length = 4;
1863             bytes = 3;
1864             value = (tvb_get_ntohl (tvb, offset) >> 8) & 0x1FFFFF;
1865           } else if ((key & 0xF0) == 0xA0) { /* bit 7-4: 1010 */
1866             length = 5;
1867             bytes = 4;
1868             value = tvb_get_ntohl (tvb, offset) & 0x0FFFFFFF;
1869           } else if ((key & 0xE0) == 0xE0) { /* bit 7-4: 111x */
1870             length = 7;
1871             bytes = 5;
1872             value = ((guint64)key & 0x1F)<<32 | tvb_get_ntohl (tvb, offset +1);
1873           } else if ((key & 0xF0) == 0xB0) { /* bit 7-4: 1011 */
1874             length = 8;
1875             bytes = 6;
1876             value = ((guint64)tvb_get_ntohs (tvb, offset) & 0x0FFF) << 32 |
1877               tvb_get_ntohl (tvb, offset + 2);
1878           } else {                           /* bit 7-4: 0xxx or 1000 */
1879             length = 6;
1880             bytes = 4;
1881             value = tvb_get_ntohl (tvb, offset);
1882           }
1883         }
1884       } else {
1885         /* 3 character */
1886         if (any) {
1887           value = (tvb_get_ntohl (tvb, offset) >> 8) & 0x48FFFF;
1888           length = 3;
1889           bytes = 3;
1890         } else {
1891           value = tvb_get_ntohs (tvb, offset);
1892           length = 3;
1893           bytes = 2;
1894         }
1895       }
1896       failure = dmp_dec_xbyte_sic (value, sic, length, any);
1897       bf = proto_tree_add_string_format (sic_tree, hf_message_sic, tvb,
1898                                          offset, bytes, sic,
1899                                          "SIC %d: %s (%d bytes: %" G_GINT64_MODIFIER "x)%s",
1900                                          i + 1, sic, bytes, value,
1901                                          failure ? " (invalid)": "");
1902       if (bitmap & (1 << (7 - i))) {
1903         /* Only if 4 - 8 character */
1904         bitmap_tree = proto_item_add_subtree (bf, ett_message_sic_bits);
1905         if (any) {
1906           proto_tree_add_item (bitmap_tree, hf_message_sic_bits_any, tvb, offset, 1, ENC_BIG_ENDIAN);
1907         } else {
1908           proto_tree_add_item (bitmap_tree, hf_message_sic_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
1909         }
1910       }
1911       if (failure) {
1912         expert_add_info_format (pinfo, bf, PI_UNDECODED, PI_NOTE,
1913                                 "Illegal SIC");
1914       }
1915       offset += bytes;
1916     }
1917     proto_item_append_text (sf, ": %d (3-to-8 %s character)", no,
1918                             any ? "any" : "[A-Z0-9]");
1919
1920   } else if (key == 0xFE) {
1921     /* No SIC */
1922     g_snprintf (sic, MAX_SIC_LEN, "Not present");
1923     no_sic = TRUE;
1924
1925   } else {
1926     /* Resered (not used) */
1927     g_snprintf (sic, MAX_SIC_LEN, "Reserved");
1928     no_sic = TRUE;
1929   }
1930
1931   if (no_sic) {
1932     /* Not added any SIC, dump text value */
1933     sf = proto_tree_add_string (message_tree, hf_message_sic, tvb, offset, 1, sic);
1934     offset += 1;
1935   }
1936
1937   proto_item_set_len (sf, offset - boffset);
1938
1939   return offset;
1940 }
1941
1942 /* Ref chapter 5.2.7.1 Direct Originator Encoding */
1943 static gint dissect_dmp_direct_addr (tvbuff_t *tvb, packet_info *pinfo,
1944                                      proto_tree *field_tree, proto_item *tf,
1945                                      gint offset, gint rec_no,
1946                                      gint rec_ofs, gint addr_type)
1947 {
1948   proto_tree *addr_tree = NULL;
1949   proto_item *en = NULL;
1950   gint        dir_addr;
1951   guint8      value;
1952
1953   value = tvb_get_guint8 (tvb, offset);
1954   dir_addr = (value & 0x7F);
1955   if (value & 0x80) {
1956     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address1, tvb,
1957                                      offset, 1, value,
1958                                      "%sDirect Address (bits 6-0): %d",
1959                                      val_to_str (addr_type, addr_type_str, ""),
1960                                      value & 0x7F);
1961     addr_tree = proto_item_add_subtree (en, ett_address_direct);
1962     proto_tree_add_item (addr_tree, hf_addr_dir_addr_ext, tvb, offset, 1, ENC_BIG_ENDIAN);
1963     proto_tree_add_item (addr_tree, hf_addr_dir_address1, tvb, offset, 1, ENC_BIG_ENDIAN);
1964     offset += 1;
1965
1966     /* Extended 1 */
1967     value = tvb_get_guint8 (tvb, offset);
1968     dir_addr |= ((value & 0x3F) << 7);
1969     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address2, tvb,
1970                                      offset, 1, value,
1971                                      "%sDirect Address (bits 12-7): %d",
1972                                      val_to_str (addr_type, addr_type_str, ""),
1973                                      value & 0x3F);
1974     addr_tree = proto_item_add_subtree (en, ett_address_direct);
1975     proto_tree_add_item (addr_tree, hf_addr_dir_addr_ext, tvb, offset, 1, ENC_BIG_ENDIAN);
1976     en = proto_tree_add_item (addr_tree, hf_reserved_0x40, tvb, offset, 1, ENC_BIG_ENDIAN);
1977     if (value & 0x40) {
1978       expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
1979                               "Reserved value");
1980     }
1981     proto_tree_add_item (addr_tree, hf_addr_dir_address2, tvb, offset, 1, ENC_BIG_ENDIAN);
1982     offset += 1;
1983
1984     if (value & 0x80) {
1985       /* Extended 2 */
1986       value = tvb_get_guint8 (tvb, offset);
1987       dir_addr |= ((value & 0x3F) << 13);
1988       en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address3, tvb,
1989                                        offset, 1, value,
1990                                        "%sDirect Address (bits 18-13): %d",
1991                                        val_to_str (addr_type,addr_type_str,""),
1992                                        value & 0x3F);
1993       addr_tree = proto_item_add_subtree (en, ett_address_direct);
1994       en = proto_tree_add_item (addr_tree, hf_reserved_0xC0, tvb, offset, 1, ENC_BIG_ENDIAN);
1995       if (value & 0xC0) {
1996         expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
1997                                 "Reserved value");
1998       }
1999       proto_tree_add_item (addr_tree, hf_addr_dir_address3, tvb, offset, 1, ENC_BIG_ENDIAN);
2000       offset += 1;
2001     }
2002
2003     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address_generated,
2004                                      tvb, offset, 0, dir_addr,
2005                                      "%sDirect Address: %d",
2006                                      val_to_str (addr_type, addr_type_str, ""),
2007                                      dir_addr);
2008     PROTO_ITEM_SET_GENERATED (en);
2009   } else {
2010     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address, tvb,
2011                                      offset, 1, value,
2012                                      "%sDirect Address: %d",
2013                                      val_to_str (addr_type, addr_type_str, ""),
2014                                      value & 0x7F);
2015     addr_tree = proto_item_add_subtree (en, ett_address_direct);
2016     proto_tree_add_item (addr_tree, hf_addr_dir_addr_ext, tvb, offset, 1, ENC_BIG_ENDIAN);
2017     proto_tree_add_item (addr_tree, hf_addr_dir_address1, tvb, offset, 1, ENC_BIG_ENDIAN);
2018     offset += 1;
2019   }
2020
2021   if (rec_no != -1) {
2022     proto_item_append_text (tf, " %d", rec_no);
2023     if (rec_ofs != -1) {
2024       proto_item_append_text (tf, " (offset from previous: %d)", rec_ofs);
2025     }
2026   }
2027   proto_item_append_text (tf, ", %sDirect Address: %d",
2028                           val_to_str (addr_type, addr_type_str, ""), dir_addr);
2029
2030   return offset;
2031 }
2032
2033 /* Ref 5.3.14 Extended Address */
2034 static gint dissect_dmp_ext_addr (tvbuff_t *tvb, packet_info *pinfo,
2035                                   proto_tree *field_tree, proto_item *tf,
2036                                   gint offset, gint rec_no, gint rec_ofs,
2037                                   gint addr_type)
2038 {
2039   proto_tree *addr_tree = NULL, *ext_tree = NULL;
2040   proto_item *en = NULL, *ef = NULL;
2041   gint        type, length;
2042   guint8      value;
2043   gint        boffset = offset;
2044   gboolean    addr_length_extended = FALSE;
2045   asn1_ctx_t  asn1_ctx;
2046
2047   asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
2048
2049   value = tvb_get_guint8 (tvb, offset);
2050   type = (value & 0xE0) >> 5;
2051   length = (value & 0x1F);
2052   ef = proto_tree_add_none_format (field_tree, hf_addr_ext_address, tvb,
2053                                    offset, -1, "%sExtended Address",
2054                                    val_to_str (addr_type, addr_type_str, ""));
2055   ext_tree = proto_item_add_subtree (ef, ett_address_extended);
2056
2057   en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_type, tvb,
2058                                    offset, 1, value, "Address Type: %s",
2059                                    val_to_str (type, ext_addr_type,
2060                                                "Reserved"));
2061   addr_tree = proto_item_add_subtree (en, ett_address_ext_type);
2062   proto_tree_add_item (addr_tree, hf_addr_ext_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2063
2064   if (value & 0x80) {
2065     addr_length_extended = TRUE;
2066     en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_length1, tvb,
2067                                      offset, 1, value,
2068                                      "Address Length (bits 4-0): %d", length);
2069     addr_tree = proto_item_add_subtree (en, ett_address_ext_length);
2070     proto_tree_add_item (addr_tree, hf_addr_ext_length1, tvb, offset, 1, ENC_BIG_ENDIAN);
2071     offset += 1;
2072
2073     /* Extended */
2074     value = tvb_get_guint8 (tvb, offset);
2075     type = ((value & 0xE0) >> 5);
2076     length |= ((value & 0x1F) << 5);
2077
2078     en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_type_ext, tvb,
2079                                      offset, 1, value, "Address Type Ext: %s",
2080                                      val_to_str (type, ext_addr_type_ext,
2081                                                  "Reserved"));
2082     addr_tree = proto_item_add_subtree (en, ett_address_ext_type);
2083     proto_tree_add_item (addr_tree, hf_addr_ext_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2084
2085     en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_length2, tvb,
2086                                      offset, 1, value,
2087                                      "Address Length (bits 9-5): %d",
2088                                      value & 0x1F);
2089     addr_tree = proto_item_add_subtree (en, ett_address_ext_length);
2090     proto_tree_add_item (addr_tree, hf_addr_ext_length2, tvb, offset, 1, ENC_BIG_ENDIAN);
2091     offset += 1;
2092   } else {
2093     en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_length, tvb,
2094                                      offset, 1, value, "Address Length: %d",
2095                                      length);
2096     addr_tree = proto_item_add_subtree (en, ett_address_ext_length);
2097     proto_tree_add_item (addr_tree, hf_addr_ext_length1, tvb, offset, 1, ENC_BIG_ENDIAN);
2098     offset += 1;
2099   }
2100
2101   if (type == ASN1_BER) {
2102     tvbuff_t *next_tvb = tvb_new_subset(tvb, offset, length, length);
2103
2104     dissect_p1_ORName (FALSE, next_tvb, 0, &asn1_ctx, ext_tree,
2105                          hf_addr_ext_asn1_ber);
2106   } else if (type == ASN1_PER) {
2107     proto_tree_add_item (ext_tree, hf_addr_ext_asn1_per, tvb, offset, length, ENC_NA);
2108   } else {
2109     proto_tree_add_item (ext_tree, hf_addr_ext_unknown, tvb, offset, length, ENC_NA);
2110   }
2111   offset += length;
2112
2113   if (addr_length_extended) {
2114     en = proto_tree_add_uint_format (ext_tree, hf_addr_ext_length_generated,
2115                                      tvb, offset, 0, length,
2116                                      "Address Length: %d", length);
2117     PROTO_ITEM_SET_GENERATED (en);
2118   }
2119
2120   proto_item_append_text (ef, ", Type: %s, Length: %d",
2121                           val_to_str (type, ext_addr_type, "Reserved"),
2122                           length);
2123
2124   if (rec_no != -1) {
2125     proto_item_append_text (tf, " %d", rec_no);
2126     if (rec_ofs != -1) {
2127       proto_item_append_text (tf, " (offset from previous: %d)", rec_ofs);
2128     }
2129   }
2130   proto_item_append_text (tf, ", %sExtended Address Type: %s",
2131                           val_to_str (addr_type, addr_type_str, ""),
2132                           val_to_str (type, ext_addr_type_short, "Reserved"));
2133
2134   proto_item_set_len (ef, offset - boffset);
2135
2136   return offset;
2137 }
2138
2139 /* Ref chapter 5.2.8.1 Extended Originator Encoding */
2140 static gint dissect_dmp_originator (tvbuff_t *tvb, packet_info *pinfo,
2141                                     proto_tree *envelope_tree, gint offset)
2142 {
2143   proto_tree *field_tree = NULL, *rec_tree = NULL;
2144   proto_item *en = NULL, *tf = NULL;
2145   guint8      value, dmp_addr_form;
2146   gint        boffset = offset;
2147   gboolean    p2_addr = FALSE;
2148
2149   tf = proto_tree_add_item (envelope_tree, hf_addr_originator, tvb, offset, -1, ENC_NA);
2150   field_tree = proto_item_add_subtree (tf, ett_address);
2151
2152   if (dmp.addr_enc == DIRECT_ADDR) {
2153     offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree, tf,
2154                                       offset, -1, -1, ORIGINATOR);
2155   } else {
2156     value = tvb_get_guint8 (tvb, offset);
2157     dmp_addr_form = (value & 0xE0) >> 5;
2158
2159     if (dmp.version == DMP_VERSION_1 && !(dmp.prot_id == PROT_NAT && dmp_nat_decode == NAT_DECODE_THALES)) {
2160       en = proto_tree_add_uint_format (field_tree, hf_addr_ext_form_orig_v1, tvb,
2161                                        offset, 1, value,
2162                                        "Address Form: %s",
2163                                        val_to_str (dmp_addr_form,
2164                                                    addr_form_orig_v1, "Reserved"));
2165       rec_tree = proto_item_add_subtree (en, ett_address_ext_form);
2166       proto_tree_add_item (rec_tree, hf_addr_ext_form_orig_v1, tvb, offset, 1, ENC_BIG_ENDIAN);
2167     } else {
2168       en = proto_tree_add_uint_format (field_tree, hf_addr_ext_form_orig, tvb,
2169                                        offset, 1, value,
2170                                        "Address Form: %s",
2171                                        val_to_str (dmp_addr_form,
2172                                                    addr_form_orig, "Reserved"));
2173       rec_tree = proto_item_add_subtree (en, ett_address_ext_form);
2174       proto_tree_add_item (rec_tree, hf_addr_ext_form_orig, tvb, offset, 1, ENC_BIG_ENDIAN);
2175     }
2176
2177     en = proto_tree_add_item (rec_tree, hf_reserved_0x1F, tvb, offset, 1, ENC_BIG_ENDIAN);
2178     if (value & 0x1F) {
2179       expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
2180                               "Reserved value");
2181     }
2182     offset += 1;
2183
2184     if (dmp.version == DMP_VERSION_1 && !(dmp.prot_id == PROT_NAT && dmp_nat_decode == NAT_DECODE_THALES)) {
2185       switch (dmp_addr_form) {
2186
2187       case P1_DIRECT:
2188         offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree,
2189                                           tf, offset, -1, -1,
2190                                           ORIGINATOR);
2191         break;
2192
2193       case P1_EXTENDED:
2194         offset = dissect_dmp_ext_addr (tvb, pinfo, field_tree, tf, offset, -1,
2195                                        -1, ORIGINATOR);
2196         break;
2197
2198       default:
2199         proto_item_append_text (tf, " (invalid address form)");
2200         break;
2201
2202       }
2203     } else {
2204       switch (dmp_addr_form) {
2205
2206       case P1_DIRECT:
2207       case P1_P2_DIRECT:
2208       case P1_DIRECT_P2_EXTENDED:
2209         offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree,
2210                                           tf, offset, -1, -1,
2211                                           ORIGINATOR);
2212         break;
2213
2214       case P1_EXTENDED:
2215       case P1_EXTENDED_P2_DIRECT:
2216       case P1_P2_EXTENDED:
2217         offset = dissect_dmp_ext_addr (tvb, pinfo, field_tree, tf, offset, -1,
2218                                        -1, ORIGINATOR);
2219         break;
2220
2221       default:
2222         proto_item_append_text (tf, " (invalid address form)");
2223         break;
2224
2225       }
2226
2227       switch (dmp_addr_form) {
2228
2229       case P1_P2_DIRECT:
2230       case P1_EXTENDED_P2_DIRECT:
2231         offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree,
2232                                           tf, offset, -1, -1,
2233                                           ORIG_P2_ADDRESS);
2234         p2_addr = TRUE;
2235         break;
2236
2237       case P1_DIRECT_P2_EXTENDED:
2238       case P1_P2_EXTENDED:
2239         offset = dissect_dmp_ext_addr (tvb, pinfo, field_tree, tf, offset, -1,
2240                                        -1, ORIG_P2_ADDRESS);
2241         p2_addr = TRUE;
2242         break;
2243
2244       }
2245     }
2246
2247     if (p2_addr) {
2248       if (dmp.msg_type == NOTIF) {
2249         en = proto_tree_add_boolean (field_tree, hf_addr_int_rec, tvb,
2250                                      offset, 0, TRUE);
2251       } else {
2252         en = proto_tree_add_boolean (field_tree, hf_addr_dl_expanded, tvb,
2253                                      offset, 0, TRUE);
2254       }
2255       PROTO_ITEM_SET_GENERATED (en);
2256     }
2257   }
2258   proto_item_set_len (tf, offset - boffset);
2259
2260   return offset;
2261 }
2262
2263 static void dmp_add_recipient_info (proto_item *tf, guint8 rep_req,
2264                                     guint8 not_req, gboolean action)
2265 {
2266   if (rep_req || not_req) {
2267     proto_item_append_text (tf, ", Request:");
2268   }
2269   if (rep_req) {
2270     proto_item_append_text (tf, "%s",
2271                             val_to_str (rep_req, report_vals_short, ""));
2272   }
2273   if (not_req) {
2274     dmp.notif_req = TRUE;
2275     proto_item_append_text (tf, "%s",
2276                             val_to_str (not_req, notif_vals_short, ""));
2277   }
2278   if (action) {
2279     if (dmp.msg_type == STANAG) {
2280       proto_item_append_text (tf, " (Action)");
2281     } else if (dmp.msg_type == IPM) {
2282       proto_item_append_text (tf, " (To)");
2283     }
2284   } else {
2285     if (dmp.msg_type == STANAG) {
2286       proto_item_append_text (tf, " (Info)");
2287     } else if (dmp.msg_type == IPM) {
2288       proto_item_append_text (tf, " (Cc)");
2289     }
2290   }
2291 }
2292
2293 /* Ref chapter 5.2.7 Direct Recipient Encoding */
2294 static gint dissect_dmp_direct_encoding (tvbuff_t *tvb, packet_info *pinfo,
2295                                          proto_tree *field_tree, proto_item *tf,
2296                                          gint offset, guint *prev_rec_no)
2297 {
2298
2299   proto_tree *addr_tree = NULL, *rec_tree = NULL;
2300   proto_item *en = NULL;
2301   guint8      rep_req = 0, not_req = 0, value;
2302   gint        rec_no, rec_ofs = -1, dir_addr;
2303   gboolean    action = FALSE, dir_addr_extended = FALSE;
2304
2305   value = tvb_get_guint8 (tvb, offset);
2306   rec_no = (value & 0xF0) >> 4;
2307   rep_req = (value & 0x0C) >> 2;
2308   not_req = (value & 0x03);
2309
2310   if (rep_req == 0x03) {
2311     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_rec_no1,
2312                                      tvb, offset, 1, value,
2313                                      "Recipient Number (bits 3-0): %d"
2314                                      " (offset from previous)",
2315                                      (value & 0xF0) >> 4);
2316   } else {
2317     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_rec_no,
2318                                      tvb, offset, 1, value,
2319                                      "Recipient Number Offset: %d"
2320                                      " (offset from previous)",
2321                                      (value & 0xF0) >> 4);
2322   }
2323   rec_tree = proto_item_add_subtree (en, ett_address_rec_no);
2324   proto_tree_add_item (rec_tree, hf_addr_dir_rec_no1, tvb, offset, 1, ENC_BIG_ENDIAN);
2325   proto_tree_add_item (rec_tree, hf_addr_dir_rep_req1, tvb, offset, 1, ENC_BIG_ENDIAN);
2326   proto_tree_add_item (rec_tree, hf_addr_dir_not_req1, tvb, offset, 1, ENC_BIG_ENDIAN);
2327   offset += 1;
2328
2329   value = tvb_get_guint8 (tvb, offset);
2330   dir_addr = (value & 0x7F);
2331   action = (value & 0x80);
2332   if (not_req == 0x03) {
2333     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address1,
2334                                      tvb, offset, 1, value,
2335                                      "Direct Address (bits 6-0): %d",
2336                                      value & 0x7F);
2337   } else {
2338     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address,
2339                                      tvb, offset, 1, value,
2340                                      "Direct Address: %d",
2341                                      value & 0x7F);
2342   }
2343   addr_tree = proto_item_add_subtree (en, ett_address_direct);
2344   proto_tree_add_item (addr_tree, hf_addr_dir_action, tvb, offset, 1, ENC_BIG_ENDIAN);
2345   proto_tree_add_item (addr_tree, hf_addr_dir_address1, tvb, offset, 1, ENC_BIG_ENDIAN);
2346   offset += 1;
2347
2348   if (rep_req == 0x03) {
2349     /* Extended Recipient Number 1 */
2350     value = tvb_get_guint8 (tvb, offset);
2351     rec_no |= ((value & 0x3F) << 4);
2352     rec_ofs = rec_no;
2353     rep_req = (value & 0xC0) >> 6;
2354
2355     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_rec_no2,
2356                                      tvb, offset, 1, value,
2357                                      "Recipient Number (bits 9-4): %d"
2358                                      " (offset from previous)",
2359                                      value & 0x3F);
2360     rec_tree = proto_item_add_subtree (en, ett_address_rec_no);
2361     proto_tree_add_item (rec_tree, hf_addr_dir_rep_req2, tvb, offset, 1, ENC_BIG_ENDIAN);
2362     proto_tree_add_item (rec_tree, hf_addr_dir_rec_no2, tvb, offset, 1, ENC_BIG_ENDIAN);
2363     offset += 1;
2364
2365     if (rep_req == 0x03) {
2366       /* Extended Recipient Number 2 */
2367       value = tvb_get_guint8 (tvb, offset);
2368       rec_no |= ((value & 0x1F) << 10);
2369       rec_ofs = rec_no;
2370       rep_req = (value & 0xC0) >> 6;
2371
2372       en = proto_tree_add_uint_format (field_tree, hf_addr_dir_rec_no3,
2373                                        tvb, offset, 1, value,
2374                                        "Recipient Number (bits 14-10): %d"
2375                                        " (offset from previous)",
2376                                        value & 0x1F);
2377       rec_tree = proto_item_add_subtree (en, ett_address_rec_no);
2378       proto_tree_add_item (rec_tree, hf_addr_dir_rep_req3, tvb, offset, 1, ENC_BIG_ENDIAN);
2379       en = proto_tree_add_item (rec_tree, hf_reserved_0x20, tvb, offset, 1, ENC_BIG_ENDIAN);
2380       if (value & 0x20) {
2381         expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
2382                                 "Reserved value");
2383       }
2384       proto_tree_add_item (rec_tree, hf_addr_dir_rec_no3, tvb, offset, 1, ENC_BIG_ENDIAN);
2385       offset += 1;
2386     }
2387   }
2388
2389   if (not_req == 0x03) {
2390     /* Extended Direct Address 1 */
2391     dir_addr_extended = TRUE;
2392     value = tvb_get_guint8 (tvb, offset);
2393     dir_addr |= ((value & 0x3F) << 7);
2394     not_req = (value & 0xC0) >> 6;
2395
2396     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address2, tvb,
2397                                      offset, 1, value,
2398                                      "Direct Address (bits 12-7): %d",
2399                                      value & 0x3F);
2400     addr_tree = proto_item_add_subtree (en, ett_address_direct);
2401     proto_tree_add_item (addr_tree, hf_addr_dir_not_req2, tvb, offset, 1, ENC_BIG_ENDIAN);
2402     proto_tree_add_item (addr_tree, hf_addr_dir_address2, tvb, offset, 1, ENC_BIG_ENDIAN);
2403     offset += 1;
2404
2405     if (not_req == 0x03) {
2406       /* Extended Direct Address 2 */
2407       value = tvb_get_guint8 (tvb, offset);
2408       dir_addr |= ((value & 0x3F) << 13);
2409       not_req = (value & 0xC0) >> 6;
2410
2411       en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address3, tvb,
2412                                        offset, 1, value,
2413                                        "Direct Address (bits 18-13): %d",
2414                                        value & 0x3F);
2415       addr_tree = proto_item_add_subtree (en, ett_address_direct);
2416       proto_tree_add_item (addr_tree, hf_addr_dir_not_req3, tvb, offset, 1, ENC_BIG_ENDIAN);
2417       proto_tree_add_item (addr_tree, hf_addr_dir_address3, tvb, offset, 1, ENC_BIG_ENDIAN);
2418       offset += 1;
2419     }
2420   }
2421
2422   rec_no += *prev_rec_no;
2423   if (dmp.version == DMP_VERSION_1 && !(dmp.prot_id == PROT_NAT && dmp_nat_decode == NAT_DECODE_THALES)) {
2424     rec_no++;
2425   }
2426   *prev_rec_no = rec_no;
2427
2428   en = proto_tree_add_uint_format (field_tree, hf_addr_dir_rec_no_generated,
2429                                    tvb, offset, 0, rec_no,
2430                                    "Recipient Number: %d", rec_no);
2431   if (rec_no > 32767) {
2432     proto_item_append_text (en, " (maximum 32767)");
2433     expert_add_info_format (pinfo, en, PI_MALFORMED, PI_WARN,
2434                             "Recipient number too big");
2435   }
2436   PROTO_ITEM_SET_GENERATED (en);
2437
2438   if (dir_addr_extended) {
2439     en = proto_tree_add_uint_format (field_tree, hf_addr_dir_address_generated,
2440                                      tvb, offset, 0, dir_addr,
2441                                      "Direct Address: %d", dir_addr);
2442     PROTO_ITEM_SET_GENERATED (en);
2443   }
2444
2445   proto_item_append_text (tf, " %d", rec_no);
2446   if (rec_ofs != -1) {
2447     proto_item_append_text (tf, " (offset from previous: %d)", rec_ofs);
2448   }
2449
2450   proto_item_append_text (tf, ", Direct Address: %d", dir_addr);
2451   dmp_add_recipient_info (tf, rep_req, not_req, action);
2452
2453   return offset;
2454 }
2455
2456 /* Ref 5.2.8.2 Extended Recipient Encoding */
2457 static gint dissect_dmp_ext_encoding (tvbuff_t *tvb, packet_info *pinfo,
2458                                       proto_tree *field_tree,
2459                                       proto_item *tf, gint offset,
2460                                       guint *prev_rec_no)
2461 {
2462   proto_tree *addr_tree = NULL;
2463   proto_item *en = NULL;
2464   guint8      rep_req = 0, not_req = 0;
2465   guint8      value, dmp_addr_form;
2466   gboolean    action = FALSE;
2467   gint        rec_no, rec_ofs = -1;
2468
2469   value = tvb_get_guint8 (tvb, offset);
2470   dmp_addr_form = (value & 0xE0) >> 5;
2471   action = (value & 0x10);
2472   en = proto_tree_add_uint_format (field_tree, hf_addr_ext_form, tvb,
2473                                    offset, 1, value,
2474                                    "Address Form: %s",
2475                                    val_to_str (dmp_addr_form,
2476                                                addr_form, "Reserved"));
2477   addr_tree = proto_item_add_subtree (en, ett_address_ext_form);
2478   proto_tree_add_item (addr_tree, hf_addr_ext_form, tvb, offset, 1, ENC_BIG_ENDIAN);
2479
2480   en = proto_tree_add_boolean_format (field_tree, hf_addr_ext_action, tvb,
2481                                       offset, 1, value, "Action: %s",
2482                                       action ? "Yes" : "No");
2483   addr_tree = proto_item_add_subtree (en, ett_address_ext_action);
2484   proto_tree_add_item (addr_tree, hf_addr_ext_action, tvb, offset, 1, ENC_BIG_ENDIAN);
2485
2486   rep_req = (value & 0x0C) >> 2;
2487   en = proto_tree_add_uint_format (field_tree, hf_addr_ext_rep_req, tvb,
2488                                    offset, 1, value,
2489                                    "Report Request: %s",
2490                                    val_to_str ((value & 0x0C) >> 2,
2491                                                report_vals, "Reserved"));
2492   addr_tree = proto_item_add_subtree (en, ett_address_ext_rep_req);
2493   proto_tree_add_item (addr_tree, hf_addr_ext_rep_req, tvb, offset, 1, ENC_BIG_ENDIAN);
2494
2495   not_req = (value & 0x03);
2496   en = proto_tree_add_uint_format (field_tree, hf_addr_ext_not_req, tvb,
2497                                    offset, 1, value,
2498                                    "Notification Request: %s",
2499                                    val_to_str (value & 0x03,
2500                                                notif_vals, "Reserved"));
2501   addr_tree = proto_item_add_subtree (en, ett_address_ext_not_req);
2502   proto_tree_add_item (addr_tree, hf_addr_ext_not_req, tvb, offset, 1, ENC_BIG_ENDIAN);
2503   offset += 1;
2504
2505   value = tvb_get_guint8 (tvb, offset);
2506   rec_no = (value & 0x7F);
2507   if (value & 0x80) {
2508     en = proto_tree_add_uint_format (field_tree, hf_addr_ext_rec_no1, tvb,
2509                                      offset, 1, value,
2510                                      "Recipient Number (bits 6-0): %d"
2511                                      " (offset from previous)",
2512                                      value & 0x7F);
2513     addr_tree = proto_item_add_subtree (en, ett_address_ext_rec_no);
2514     proto_tree_add_item (addr_tree, hf_addr_ext_rec_ext, tvb, offset, 1, ENC_BIG_ENDIAN);
2515     proto_tree_add_item (addr_tree, hf_addr_ext_rec_no1, tvb, offset, 1, ENC_BIG_ENDIAN);
2516     offset += 1;
2517
2518     /* Extended */
2519     value = tvb_get_guint8 (tvb, offset);
2520     rec_no |= (value << 7);
2521     rec_ofs = rec_no;
2522     en = proto_tree_add_uint_format (field_tree, hf_addr_ext_rec_no2, tvb,
2523                                      offset, 1, value,
2524                                      "Recipient Number (bits 14-7): %d"
2525                                      " (offset from previous)", value);
2526     addr_tree = proto_item_add_subtree (en, ett_address_ext_rec_no);
2527     proto_tree_add_item (addr_tree, hf_addr_ext_rec_no2, tvb, offset, 1, ENC_BIG_ENDIAN);
2528     offset += 1;
2529
2530   } else {
2531     en = proto_tree_add_uint_format (field_tree, hf_addr_ext_rec_no, tvb,
2532                                      offset, 1, value,
2533                                      "Recipient Number Offset: %d"
2534                                      " (offset from previous)",
2535                                      value & 0x7F);
2536     addr_tree = proto_item_add_subtree (en, ett_address_ext_rec_no);
2537     proto_tree_add_item (addr_tree, hf_addr_ext_rec_ext, tvb, offset, 1, ENC_BIG_ENDIAN);
2538     proto_tree_add_item (addr_tree, hf_addr_ext_rec_no1, tvb, offset, 1, ENC_BIG_ENDIAN);
2539     offset += 1;
2540
2541   }
2542
2543   rec_no += *prev_rec_no;
2544   if (dmp.version == DMP_VERSION_1 && !(dmp.prot_id == PROT_NAT && dmp_nat_decode == NAT_DECODE_THALES)) {
2545     rec_no++;
2546   }
2547   *prev_rec_no = rec_no;
2548
2549   en = proto_tree_add_uint_format (field_tree, hf_addr_ext_rec_no_generated,
2550                                    tvb, offset, 0, rec_no,
2551                                    "Recipient Number: %d", rec_no);
2552   if (rec_no > 32767) {
2553     proto_item_append_text (en, " (maximum 32767)");
2554     expert_add_info_format (pinfo, en, PI_MALFORMED, PI_WARN,
2555                             "Recipient number too big");
2556   }
2557   PROTO_ITEM_SET_GENERATED (en);
2558
2559   switch (dmp_addr_form) {
2560
2561   case P1_DIRECT:
2562   case P1_P2_DIRECT:
2563   case P1_DIRECT_P2_EXTENDED:
2564     offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree, tf, offset,
2565                                       rec_no, rec_ofs, P1_ADDRESS);
2566     break;
2567
2568   case P1_EXTENDED:
2569   case P1_EXTENDED_P2_DIRECT:
2570   case P1_P2_EXTENDED:
2571     offset = dissect_dmp_ext_addr (tvb, pinfo, field_tree, tf, offset,
2572                                    rec_no, rec_ofs, P1_ADDRESS);
2573     break;
2574
2575   }
2576
2577   switch (dmp_addr_form) {
2578
2579   case P2_DIRECT:
2580   case P1_P2_DIRECT:
2581   case P1_EXTENDED_P2_DIRECT:
2582     offset = dissect_dmp_direct_addr (tvb, pinfo, field_tree, tf, offset,
2583                                       rec_no, rec_ofs, P2_ADDRESS);
2584     break;
2585
2586   case P2_EXTENDED:
2587   case P1_DIRECT_P2_EXTENDED:
2588   case P1_P2_EXTENDED:
2589     offset = dissect_dmp_ext_addr (tvb, pinfo, field_tree, tf, offset,
2590                                    rec_no, rec_ofs, P2_ADDRESS);
2591     break;
2592
2593   }
2594
2595   dmp_add_recipient_info (tf, rep_req, not_req, action);
2596
2597   return offset;
2598 }
2599
2600 /* Ref chapter 5.2 Address encoding */
2601 static gint dissect_dmp_address (tvbuff_t *tvb, packet_info *pinfo,
2602                                  proto_tree *envelope_tree,
2603                                  gint offset, guint *prev_rec_no,
2604                                  gboolean reporting_name)
2605 {
2606   proto_tree *field_tree = NULL;
2607   proto_item *tf = NULL;
2608   gint        boffset = offset;
2609
2610   if (reporting_name) {
2611     tf = proto_tree_add_item (envelope_tree, hf_addr_reporting_name, tvb, offset, -1, ENC_NA);
2612   } else {
2613     tf = proto_tree_add_none_format (envelope_tree, hf_addr_recipient, tvb,
2614                                      offset, -1, "Recipient Number");
2615   }
2616   field_tree = proto_item_add_subtree (tf, ett_address);
2617
2618   if (dmp.addr_enc == DIRECT_ADDR) {
2619     offset = dissect_dmp_direct_encoding (tvb, pinfo, field_tree, tf,
2620                                           offset, prev_rec_no);
2621   } else {
2622     offset = dissect_dmp_ext_encoding (tvb, pinfo, field_tree, tf, offset,
2623                                        prev_rec_no);
2624   }
2625
2626   proto_item_set_len (tf, offset - boffset);
2627
2628   return offset;
2629 }
2630
2631 /* Ref chapter 6.2.9 Acknowledgement */
2632 static gint dissect_dmp_ack (tvbuff_t *tvb, packet_info *pinfo,
2633                              proto_tree *dmp_tree, gint offset)
2634 {
2635   proto_tree *ack_tree = NULL, *recip_tree = NULL;
2636   proto_item *en = NULL, *rt = NULL;
2637   proto_item *hidden_item;
2638   guint       prev_rec_no = 0;
2639   gint        rec_len, rec_no = 0;
2640   gint        boffset = offset;
2641
2642   en = proto_tree_add_item (dmp_tree, hf_ack, tvb, offset, 4, ENC_NA);
2643   ack_tree = proto_item_add_subtree (en, ett_ack);
2644
2645   dmp.ack_reason = tvb_get_guint8 (tvb, offset);
2646   proto_item_append_text (en, ", Reason: %s",
2647                           val_to_str (dmp.ack_reason, ack_reason, "Reserved"));
2648
2649   rt = proto_tree_add_item (ack_tree, hf_ack_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
2650   if (dmp.ack_reason != 0) {
2651     expert_add_info_format (pinfo, rt, PI_RESPONSE_CODE, PI_NOTE, "ACK reason: %s",
2652                             val_to_str (dmp.ack_reason, ack_reason, "Reserved"));
2653   }
2654   offset += 1;
2655
2656   proto_tree_add_item (ack_tree, hf_ack_diagnostic, tvb, offset, 1, ENC_BIG_ENDIAN);
2657   offset += 1;
2658
2659   /* Subject Message Identifier */
2660   dmp.subj_id = tvb_get_ntohs (tvb, offset);
2661   proto_tree_add_item (ack_tree, hf_message_subj_id, tvb, offset, 2, ENC_BIG_ENDIAN);
2662   hidden_item = proto_tree_add_item (ack_tree, hf_dmp_id, tvb, offset, 2, ENC_BIG_ENDIAN);
2663   PROTO_ITEM_SET_HIDDEN (hidden_item);
2664   offset += 2;
2665
2666   if (use_seq_ack_analysis) {
2667     register_dmp_id (pinfo, dmp.ack_reason);
2668   }
2669
2670   if (dmp.ack_rec_present) {
2671     /* Recipient List */
2672     rec_len = tvb_length (tvb);
2673     if (dmp.checksum) {
2674       rec_len -= 2;
2675     }
2676     if (offset < rec_len) {
2677       rt = proto_tree_add_item (ack_tree, hf_ack_recips, tvb, offset, -1, ENC_NA);
2678       recip_tree = proto_item_add_subtree (rt, ett_ack_recips);
2679       while (offset < rec_len) {
2680         offset = dissect_dmp_address (tvb, pinfo, recip_tree, offset,
2681                                       &prev_rec_no, FALSE);
2682         rec_no++;
2683       }
2684       proto_item_append_text (rt, ", No Recipients: %d", rec_no);
2685       proto_item_set_len (rt, offset - boffset - 4);
2686       proto_item_set_len (en, offset - boffset);
2687     }
2688   }
2689
2690   return offset;
2691 }
2692
2693 static gint dissect_mts_identifier (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
2694                                     gint offset, gboolean subject)
2695 {
2696   proto_item *hidden_item;
2697   gchar      *mts_id;
2698
2699   if (dmp.msg_id_type == X400_MSG_ID || dmp_nat_decode == NAT_DECODE_DMP) {
2700     mts_id = dissect_7bit_string (tvb, offset, dmp.mts_id_length);
2701   } else if (dmp_nat_decode == NAT_DECODE_THALES) {
2702     mts_id = dissect_thales_mts_id (tvb, offset, dmp.mts_id_length);
2703   } else {
2704     mts_id = tvb_bytes_to_str (tvb, offset, dmp.mts_id_length);
2705   }
2706   proto_item_append_text (dmp.mts_id_item, " (%zu bytes decompressed)", strlen (mts_id));
2707   mts_id = format_text (mts_id, strlen (mts_id));
2708   if (subject) {
2709     proto_tree_add_string (tree, hf_message_subj_mts_id, tvb, offset, dmp.mts_id_length, mts_id);
2710     hidden_item = proto_tree_add_string (tree, hf_mts_id, tvb, offset, dmp.mts_id_length, mts_id);
2711     /* Read from hash, for analysis */
2712     dmp.subj_id = GPOINTER_TO_UINT (g_hash_table_lookup (dmp_long_id_hash_table, mts_id));
2713   } else {
2714     proto_tree_add_string (tree, hf_envelope_mts_id, tvb, offset, dmp.mts_id_length, mts_id);
2715     hidden_item = proto_tree_add_string (tree, hf_mts_id, tvb, offset, dmp.mts_id_length, mts_id);
2716     /* Insert into hash, for analysis */
2717     g_hash_table_insert (dmp_long_id_hash_table, g_strdup (mts_id), GUINT_TO_POINTER ((guint)dmp.msg_id));
2718   }
2719   PROTO_ITEM_SET_HIDDEN (hidden_item);
2720   offset += dmp.mts_id_length;
2721
2722   return offset;
2723 }
2724
2725 static gint dissect_ipm_identifier (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
2726                                     gint offset, gboolean subject)
2727 {
2728   proto_tree *field_tree;
2729   proto_item *tf, *hidden_item;
2730   gchar      *ipm_id;
2731   gint        length, modifier, ipm_id_length;
2732
2733   length = tvb_get_guint8 (tvb, offset);
2734   modifier = (length & 0xC0) >> 6;
2735   ipm_id_length = length & 0x3F;
2736
2737   tf = proto_tree_add_uint_format (tree, hf_envelope_ipm_id_length,
2738                                    tvb, offset, 1, ipm_id_length,
2739                                    "IPM Identifier Length: %u",
2740                                    ipm_id_length);
2741   field_tree = proto_item_add_subtree (tf, ett_envelope_ipm_id_length);
2742   if ((dmp.msg_id_type == NAT_MSG_ID || modifier != IPM_MODIFIER_X400) && dmp_nat_decode == NAT_DECODE_THALES) {
2743     proto_tree_add_item (field_tree, hf_thales_ipm_id_modifier, tvb, offset, 1, ENC_BIG_ENDIAN);
2744   } else {
2745     proto_tree_add_item (field_tree, hf_envelope_ipm_id_modifier, tvb, offset, 1, ENC_BIG_ENDIAN);
2746   }
2747   proto_tree_add_item (field_tree, hf_envelope_ipm_id_length, tvb, offset, 1, ENC_BIG_ENDIAN);
2748   offset += 1;
2749
2750   if (modifier == IPM_MODIFIER_X400 || dmp_nat_decode == NAT_DECODE_DMP) {
2751     ipm_id = dissect_7bit_string (tvb, offset, ipm_id_length);
2752   } else if (dmp_nat_decode == NAT_DECODE_THALES) {
2753     ipm_id = dissect_thales_ipm_id (tvb, offset, ipm_id_length, modifier);
2754   } else {
2755     ipm_id = tvb_bytes_to_str (tvb, offset, ipm_id_length);
2756   }
2757   proto_item_append_text (tf, " (%zu bytes decompressed)", strlen (ipm_id));
2758   ipm_id = format_text (ipm_id, strlen (ipm_id));
2759   if (subject) {
2760     proto_tree_add_string (tree, hf_message_subj_ipm_id, tvb, offset, ipm_id_length, ipm_id);
2761     hidden_item = proto_tree_add_string (tree, hf_ipm_id, tvb, offset, ipm_id_length, ipm_id);
2762     /* Read from hash, for analysis */
2763     dmp.subj_id = GPOINTER_TO_UINT (g_hash_table_lookup (dmp_long_id_hash_table, ipm_id));
2764   } else {
2765     proto_tree_add_string (tree, hf_envelope_ipm_id, tvb, offset, ipm_id_length, ipm_id);
2766     hidden_item = proto_tree_add_string (tree, hf_ipm_id, tvb, offset, ipm_id_length, ipm_id);
2767     /* Insert into hash, for analysis */
2768     g_hash_table_insert (dmp_long_id_hash_table, g_strdup (ipm_id), GUINT_TO_POINTER ((guint)dmp.msg_id));
2769   }
2770   PROTO_ITEM_SET_HIDDEN (hidden_item);
2771   offset += ipm_id_length;
2772
2773   return offset;
2774 }
2775
2776 /* Ref chapter 6.2.7 Envelope structure */
2777 static gint dissect_dmp_envelope (tvbuff_t *tvb, packet_info *pinfo,
2778                                   proto_tree *dmp_tree, gint offset)
2779 {
2780   proto_tree *envelope_tree = NULL;
2781   proto_tree *field_tree = NULL;
2782   proto_item *en = NULL, *tf = NULL, *vf = NULL;
2783   proto_item *hidden_item;
2784   guint8      envelope, time_diff;
2785   guint16     subm_time, no_rec, value16;
2786   gint32      secs = 0;
2787   gchar      *env_flags = NULL;
2788   guint       prev_rec_no = 0;
2789   gint        boffset = offset, i;
2790   gboolean    using_short_id = FALSE;
2791
2792   en = proto_tree_add_item (dmp_tree, hf_envelope, tvb, offset, 10, ENC_NA);
2793   envelope_tree = proto_item_add_subtree (en, ett_envelope);
2794
2795   envelope = tvb_get_guint8 (tvb, offset);
2796   dmp.prot_id = (envelope & 0xF8) >> 3;
2797   dmp.version = (envelope & 0x07) + 1;
2798
2799   /* Protocol Version */
2800   tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_version,
2801                                    tvb, offset, 1, dmp.version,
2802                                    "Protocol Version: %d", dmp.version);
2803
2804   field_tree = proto_item_add_subtree (tf, ett_envelope_version);
2805   vf = proto_tree_add_item (field_tree, hf_envelope_protocol_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2806   if (dmp.prot_id == PROT_NAT) {
2807     proto_item_append_text (vf, " (national version of DMP)");
2808     proto_item_append_text (tf, " (national)");
2809   } else if (dmp.prot_id == PROT_DMP) {
2810     proto_item_append_text (vf, " (correct)");
2811   } else {
2812     proto_item_append_text (vf, " (incorrect, should be 0x1d)");
2813   }
2814   vf = proto_tree_add_item (field_tree, hf_envelope_version_value, tvb, offset, 1, ENC_BIG_ENDIAN);
2815   offset += 1;
2816
2817   if (dmp.version > DMP_VERSION_2) {
2818     /* Unsupported DMP Version */
2819     proto_item_append_text (vf, " (unsupported)");
2820     proto_item_append_text (tf, " (unsupported)");
2821     expert_add_info_format (pinfo, vf, PI_UNDECODED, PI_ERROR,
2822                             "Unsupported DMP Version: %d", dmp.version);
2823     return offset;
2824   }
2825
2826   envelope = tvb_get_guint8 (tvb, offset);
2827   dmp.addr_enc = ((envelope & 0x10) >> 4);
2828   dmp.checksum = ((envelope & 0x08) >> 3);
2829   dmp.msg_type = (envelope & 0x07);
2830
2831   if (dmp.msg_type != ACK) {
2832     /* Hop count */
2833     tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_hop_count,
2834                                      tvb, offset, 1, envelope,
2835                                      "Hop Count: %d", (envelope & 0xE0) >> 5);
2836     field_tree = proto_item_add_subtree (tf, ett_envelope_hop_count);
2837     proto_tree_add_item (field_tree, hf_envelope_hop_count_value, tvb, offset, 1, ENC_BIG_ENDIAN);
2838   } else {
2839     if (dmp.version >= DMP_VERSION_2) {
2840       /* Extensions Present */
2841       dmp.extensions = (envelope & 0x80);
2842       tf = proto_tree_add_boolean_format (envelope_tree, hf_envelope_extensions,
2843                                           tvb, offset, 1, envelope,
2844                                           "Extensions: %s",
2845                                           (envelope & 0x80) ? "Present" : "Absent");
2846       field_tree = proto_item_add_subtree (tf, ett_envelope_extensions);
2847       proto_tree_add_item (field_tree, hf_envelope_extensions, tvb, offset, 1, ENC_BIG_ENDIAN);
2848     }
2849
2850     /* Recipient Present */
2851     dmp.ack_rec_present = (envelope & 0x20);
2852     tf = proto_tree_add_boolean_format (envelope_tree,hf_envelope_rec_present,
2853                                         tvb, offset, 1, envelope,
2854                                         "Recipient Present: %s",
2855                                         (envelope & 0x20) ? "Present" : "Absent");
2856     field_tree = proto_item_add_subtree (tf, ett_envelope_rec_present);
2857     proto_tree_add_item (field_tree, hf_envelope_rec_present, tvb, offset, 1, ENC_BIG_ENDIAN);
2858   }
2859
2860   /* Address Encoding */
2861   tf = proto_tree_add_boolean_format (envelope_tree, hf_envelope_addr_enc,
2862                                       tvb, offset, 1, envelope,
2863                                       "Address Encoding: %s",
2864                                       (envelope & 0x10) ?
2865                                       addr_enc.true_string :
2866                                       addr_enc.false_string);
2867   field_tree = proto_item_add_subtree (tf, ett_envelope_addr_enc);
2868   proto_tree_add_item (field_tree, hf_envelope_addr_enc, tvb, offset, 1, ENC_BIG_ENDIAN);
2869
2870   /* Checksum Present */
2871   tf = proto_tree_add_boolean_format (envelope_tree, hf_envelope_checksum,
2872                                       tvb, offset, 1, envelope,
2873                                       "Checksum: %s",
2874                                       (envelope & 0x08) ? "Used" : "Not used");
2875   field_tree = proto_item_add_subtree (tf, ett_envelope_checksum);
2876   proto_tree_add_item (field_tree, hf_envelope_checksum, tvb, offset, 1, ENC_BIG_ENDIAN);
2877
2878   /* Content Type */
2879   tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_type,
2880                                    tvb, offset, 1, envelope,
2881                                    "Content Type: %s (%d)",
2882                                    val_to_str (envelope & 0x07,
2883                                                type_vals, "Unknown"),
2884                                    envelope & 0x07);
2885   field_tree = proto_item_add_subtree (tf, ett_envelope_cont_type);
2886   proto_tree_add_item (field_tree, hf_envelope_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2887
2888   proto_item_append_text (en, ", Checksum %s", (envelope >> 3) & 0x01 ? "Used" : "Not used");
2889   offset += 1;
2890
2891   if (dmp.msg_type >= ACK) {
2892     proto_item_set_len (en, offset - boffset);
2893     return offset;
2894   }
2895
2896   if (dmp.version >= DMP_VERSION_2) {
2897     envelope = tvb_get_guint8 (tvb, offset);
2898     /* Extensions Present */
2899     tf = proto_tree_add_boolean_format (envelope_tree, hf_envelope_extensions,
2900                                         tvb, offset, 1, envelope,
2901                                         "Extensions: %s",
2902                                         (envelope & 0x80) ? "Present" : "Absent");
2903     field_tree = proto_item_add_subtree (tf, ett_envelope_extensions);
2904     proto_tree_add_item (field_tree, hf_envelope_extensions, tvb, offset, 1, ENC_BIG_ENDIAN);
2905     dmp.extensions = (envelope & 0x80);
2906
2907     /* Message Identifier Type */
2908     dmp.msg_id_type = (envelope & 0x60) >> 5;
2909     tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_msg_id_type,
2910                                      tvb, offset, 1, envelope,
2911                                      "Message Identifier Type: %s (%d)",
2912                                      val_to_str (dmp.msg_id_type, msg_id_type_vals, "Unknown"),
2913                                      dmp.msg_id_type);
2914     field_tree = proto_item_add_subtree (tf, ett_envelope_msg_id_type);
2915     proto_tree_add_item (field_tree, hf_envelope_msg_id_type, tvb, offset, 1, ENC_BIG_ENDIAN);
2916
2917     if (dmp.msg_id_type == X400_MSG_ID || dmp.msg_id_type == NAT_MSG_ID) {
2918       /* MTS Identifier Length */
2919       dmp.mts_id_length = (envelope & 0x1F);
2920       dmp.mts_id_item = proto_tree_add_uint_format (envelope_tree, hf_envelope_mts_id_length,
2921                                                     tvb, offset, 1, envelope,
2922                                                     "MTS Identifier Length: %u",
2923                                                     dmp.mts_id_length);
2924       field_tree = proto_item_add_subtree (dmp.mts_id_item, ett_envelope_mts_id_length);
2925       proto_tree_add_item (field_tree, hf_envelope_mts_id_length, tvb, offset, 1, ENC_BIG_ENDIAN);
2926       offset += 1;
2927     } else {
2928       proto_tree_add_item (field_tree, hf_envelope_msg_id_length, tvb, offset, 1, ENC_BIG_ENDIAN);
2929       if (envelope & 0x10) {
2930         /* Using Short Identifier (12 bits) */
2931         using_short_id = TRUE;
2932       } else {
2933         tf = proto_tree_add_item (field_tree, hf_reserved_0x0F, tvb, offset, 1, ENC_BIG_ENDIAN);
2934         if (envelope & 0x0F) {
2935           expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN, "Reserved value");
2936         }
2937         offset += 1;
2938       }
2939     }
2940   }
2941
2942   /* Message Identifier */
2943   dmp.msg_id = tvb_get_ntohs (tvb, offset);
2944   if (using_short_id) {
2945     dmp.msg_id &= 0x0FFF;
2946   }
2947   tf = proto_tree_add_uint (envelope_tree, hf_envelope_msg_id, tvb, offset, 2, dmp.msg_id);
2948   hidden_item = proto_tree_add_uint (envelope_tree, hf_dmp_id, tvb, offset, 2, dmp.msg_id);
2949   if (using_short_id) {
2950     field_tree = proto_item_add_subtree (tf, ett_envelope_msg_id);
2951     proto_tree_add_item (field_tree, hf_envelope_msg_id_12bit, tvb, offset, 2, ENC_BIG_ENDIAN);
2952   } else if (dmp.version >= DMP_VERSION_2 && dmp.msg_id_type == ONLY_DMP_ID && dmp.msg_id < 4096) {
2953     expert_add_info_format (pinfo, tf, PI_PROTOCOL, PI_NOTE, "Id < 4096 - should use ShortId");
2954   }
2955   PROTO_ITEM_SET_HIDDEN (hidden_item);
2956   offset += 2;
2957
2958   if (dmp.version >= DMP_VERSION_2) {
2959     if ((dmp.msg_type != REPORT) && (dmp.msg_id_type == X400_MSG_ID || dmp.msg_id_type == NAT_MSG_ID)) {
2960       offset = dissect_mts_identifier (tvb, pinfo, envelope_tree, offset, FALSE);
2961     }
2962   }
2963
2964   /* Submission Time */
2965   subm_time = tvb_get_ntohs (tvb, offset);
2966   dmp.subm_time = dmp_dec_subm_time ((guint16)(subm_time & 0x7FFF),
2967                                      (gint32) pinfo->fd->abs_ts.secs);
2968   tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_subm_time, tvb,
2969                                    offset, 2, subm_time,
2970                                    "Submission time: %s",
2971                                    (subm_time & 0x7FFF) >= 0x7FF8 ?
2972                                    "Reserved" :
2973                                    abs_time_secs_to_str (dmp.subm_time, ABSOLUTE_TIME_LOCAL, TRUE));
2974   field_tree = proto_item_add_subtree (tf, ett_envelope_subm_time);
2975   proto_tree_add_item (field_tree, hf_envelope_time_diff_present, tvb, offset, 2, ENC_BIG_ENDIAN);
2976   proto_tree_add_item (field_tree, hf_envelope_subm_time_value, tvb, offset, 2, ENC_BIG_ENDIAN);
2977   offset += 2;
2978
2979   if (subm_time & 0x8000) {
2980     /* Timed Difference */
2981     time_diff = tvb_get_guint8 (tvb, offset);
2982     tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_time_diff,
2983                                      tvb, offset, 1, time_diff,
2984                                      "Time Difference: ");
2985     field_tree = proto_item_add_subtree (tf, ett_envelope_time_diff);
2986     proto_tree_add_item (field_tree, hf_envelope_time_diff_value, tvb, offset, 1, ENC_BIG_ENDIAN);
2987     secs = dmp_dec_time_diff (time_diff);
2988     if (secs == DMP_TIME_RESERVED) {
2989       proto_item_append_text (tf, "Reserved (0x%2.2x)", time_diff);
2990     } else {
2991       proto_item_append_text (tf, "%s", time_secs_to_str (secs));
2992     }
2993     offset += 1;
2994   }
2995
2996   /* Envelope Flags */
2997   envelope = tvb_get_guint8 (tvb, offset);
2998   tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_flags,
2999                                    tvb, offset, 1, envelope,
3000                                    "Envelope Flags");
3001
3002   field_tree = proto_item_add_subtree (tf, ett_envelope_flags);
3003   proto_tree_add_item (field_tree, hf_envelope_content_id_discarded, tvb, offset, 1, ENC_BIG_ENDIAN);
3004   proto_tree_add_item (field_tree, hf_envelope_recip_reassign_prohib, tvb, offset, 1, ENC_BIG_ENDIAN);
3005   proto_tree_add_item (field_tree, hf_envelope_dl_expansion_prohib, tvb, offset, 1, ENC_BIG_ENDIAN);
3006
3007   if (envelope & 0xE0) {
3008     env_flags = ep_strdup_printf ("%s%s%s",
3009                                   (envelope & 0x80) ? ", ContId discarded" : "",
3010                                   (envelope & 0x40) ? ", Reass prohibited" : "",
3011                                   (envelope & 0x20) ? ", DLE prohibited"   : "");
3012     proto_item_append_text (tf, ":%s", &env_flags[1]);
3013   } else {
3014     proto_item_append_text (tf, " (none)");
3015   }
3016
3017   /* Recipient Count */
3018   no_rec = (envelope & 0x1F);
3019   tf = proto_tree_add_uint_format (envelope_tree, hf_envelope_recipients,
3020                                    tvb, offset, 1, envelope,
3021                                    "Recipient Count: %d", no_rec);
3022
3023   field_tree = proto_item_add_subtree (tf, ett_envelope_recipients);
3024   proto_tree_add_item (field_tree, hf_envelope_recipients, tvb, offset, 1, ENC_BIG_ENDIAN);
3025   offset += 1;
3026
3027   if (no_rec == 0) {
3028     /* Extended Recipient Count */
3029     value16 = tvb_get_ntohs (tvb, offset);
3030     no_rec = value16 & 0x7FFF;
3031     tf = proto_tree_add_uint_format (envelope_tree,hf_envelope_ext_recipients,
3032                                      tvb, offset, 2, value16,
3033                                      "Extended Recipient Count: %d%s", no_rec,
3034                                      (no_rec < 32 ?
3035                                       " (incorrect, reserved value)" : ""));
3036
3037     field_tree = proto_item_add_subtree (tf, ett_envelope_ext_recipients);
3038     en = proto_tree_add_item (field_tree, hf_reserved_0x8000, tvb, offset, 2, ENC_BIG_ENDIAN);
3039     if (value16 & 0x8000) {
3040       expert_add_info_format (pinfo, en, PI_UNDECODED, PI_WARN,
3041                               "Reserved value");
3042     }
3043     proto_tree_add_item (field_tree, hf_envelope_ext_recipients, tvb, offset, 2, ENC_BIG_ENDIAN);
3044     offset += 2;
3045   }
3046
3047   if (dmp.msg_type != REPORT) {
3048     /* Originator - Not present for reports */
3049     offset = dissect_dmp_originator (tvb, pinfo, envelope_tree, offset);
3050   }
3051
3052   for (i = 1; i <= no_rec; i++) {
3053     /* Recipient(s) */
3054     offset = dissect_dmp_address (tvb, pinfo, envelope_tree, offset,
3055                                   &prev_rec_no, FALSE);
3056   }
3057
3058   if (dmp.version >= DMP_VERSION_2) {
3059     if ((dmp.msg_id_type == X400_MSG_ID || dmp.msg_id_type == NAT_MSG_ID) &&
3060         dmp.notif_req && (dmp.msg_type == STANAG || dmp.msg_type == IPM))
3061     {
3062       offset = dissect_ipm_identifier (tvb, pinfo, envelope_tree, offset, FALSE);
3063     }
3064   }
3065
3066   proto_item_set_len (en, offset - boffset);
3067
3068   return offset;
3069 }
3070
3071 static void dissect_dmp_structured_id (tvbuff_t *tvb, proto_tree *body_tree,
3072                                        gint offset)
3073 {
3074   gint        length;
3075
3076   offset += dmp_struct_offset;
3077   switch (dmp_struct_format) {
3078
3079   case STRUCT_ID_UINT8:
3080     dmp.struct_id = ep_strdup_printf ("%u", tvb_get_guint8 (tvb, offset));
3081     proto_tree_add_item (body_tree, hf_message_bodyid_uint8, tvb, offset, 1, ENC_BIG_ENDIAN);
3082     break;
3083
3084   case STRUCT_ID_UINT16:
3085     dmp.struct_id = ep_strdup_printf ("%u", tvb_get_ntohs (tvb, offset));
3086     proto_tree_add_item (body_tree, hf_message_bodyid_uint16, tvb, offset, 2, ENC_BIG_ENDIAN);
3087     break;
3088
3089   case STRUCT_ID_UINT32:
3090     dmp.struct_id = ep_strdup_printf ("%u", tvb_get_ntohl (tvb, offset));
3091     proto_tree_add_item (body_tree, hf_message_bodyid_uint32, tvb, offset, 4, ENC_BIG_ENDIAN);
3092     break;
3093
3094   case STRUCT_ID_UINT64:
3095     dmp.struct_id = ep_strdup_printf ("%" G_GINT64_MODIFIER "u", tvb_get_ntoh64 (tvb, offset));
3096     proto_tree_add_item (body_tree, hf_message_bodyid_uint64, tvb, offset, 8, ENC_BIG_ENDIAN);
3097     break;
3098
3099   case STRUCT_ID_STRING:
3100     dmp.struct_id = tvb_get_ephemeral_string (tvb, offset, (gint) dmp_struct_length);
3101     proto_tree_add_item (body_tree, hf_message_bodyid_string, tvb, offset, dmp_struct_length, ENC_ASCII|ENC_NA);
3102     break;
3103
3104   case STRUCT_ID_ZSTRING:
3105     dmp.struct_id = tvb_get_ephemeral_stringz (tvb, offset, &length);
3106     proto_tree_add_item (body_tree, hf_message_bodyid_zstring, tvb, offset, length, ENC_ASCII|ENC_NA);
3107     break;
3108
3109   }
3110 }
3111
3112 /*
3113  * Ref chapter 6.3.7.1 STANAG 4406 message structure
3114  * and chapter 6.3.8.1 IPM 88 message structure
3115  */
3116 static gint dissect_dmp_message (tvbuff_t *tvb, packet_info *pinfo,
3117                                  proto_tree *dmp_tree, gint offset)
3118 {
3119   tvbuff_t   *next_tvb = NULL;
3120   proto_tree *message_tree = NULL;
3121   proto_tree *field_tree = NULL;
3122   proto_item *en = NULL, *tf = NULL, *tr = NULL;
3123   guint8      message, eit = 0, compr_alg = ALGORITHM_NONE;
3124   gint        len, boffset = offset;
3125
3126   en = proto_tree_add_item (dmp_tree, hf_message_body, tvb, offset, -1, ENC_NA);
3127   message_tree = proto_item_add_subtree (en, ett_message);
3128
3129   if (dmp.body_format == FREE_TEXT_SUBJECT) {
3130     len = tvb_strsize (tvb, offset);
3131     if (dmp_subject_as_id) {
3132       dmp.struct_id = tvb_get_ephemeral_string (tvb, offset, len);
3133     }
3134     proto_tree_add_item (message_tree, hf_message_subject, tvb, offset, len, ENC_ASCII|ENC_NA);
3135     offset += len;
3136   }
3137
3138   if (dmp.body_format == FREE_TEXT || dmp.body_format == FREE_TEXT_SUBJECT) {
3139     message = tvb_get_guint8 (tvb, offset);
3140     eit = (message & 0xE0) >> 5;
3141     compr_alg = (message & 0x18) >> 3;
3142     /* Encoded Information Type */
3143     tf = proto_tree_add_uint_format (message_tree, hf_message_eit,
3144                                      tvb, offset, 1, message, "EIT: %s (%d)",
3145                                      val_to_str (eit, eit_vals, "Unknown"),
3146                                      eit);
3147     field_tree = proto_item_add_subtree (tf, ett_message_eit);
3148     proto_tree_add_item (field_tree, hf_message_eit, tvb, offset, 1, ENC_BIG_ENDIAN);
3149     proto_item_append_text (en, ", Type: %s",
3150                             val_to_str (eit, eit_vals, "Unknown"));
3151
3152     /* Compression Algorithm */
3153     tf = proto_tree_add_uint_format (message_tree, hf_message_compr,
3154                                      tvb, offset, 1, message,
3155                                      "Compression Algorithm: %s (%d)",
3156                                      val_to_str (compr_alg, compression_vals,
3157                                                  "Unknown"), compr_alg);
3158     field_tree = proto_item_add_subtree (tf, ett_message_compr);
3159     tr = proto_tree_add_item (field_tree, hf_message_compr, tvb, offset, 1, ENC_BIG_ENDIAN);
3160     if (compr_alg == ALGORITHM_ZLIB) {
3161       proto_item_append_text (en, " (compressed)");
3162     } else if (compr_alg != ALGORITHM_NONE) {
3163       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN,
3164                               "Unknown compression algorithm");
3165     }
3166
3167     if (message & 0x07) {
3168       /* Reserved */
3169       tf = proto_tree_add_uint_format (message_tree, hf_reserved_0x07,
3170                                        tvb, offset, 1, message,
3171                                        "Reserved: %d",  message & 0x07);
3172       field_tree = proto_item_add_subtree (tf, ett_message_body_reserved);
3173       tf = proto_tree_add_item (field_tree, hf_reserved_0x07, tvb, offset, 1, ENC_BIG_ENDIAN);
3174       expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3175                               "Reserved value");
3176     }
3177     offset += 1;
3178   }
3179
3180   len = tvb_length_remaining (tvb, offset);
3181   if (dmp.checksum) {
3182     len -= 2;
3183   }
3184
3185   tf = proto_tree_add_none_format (message_tree, hf_message_body_data, tvb,
3186                                    offset, len,
3187                                    "%sUser data, Length: %d",
3188                                    (compr_alg == ALGORITHM_ZLIB) ?
3189                                    "Compressed " : "", len);
3190   field_tree = proto_item_add_subtree (tf, ett_message_body);
3191
3192   if (dmp.body_format == STRUCTURED) {
3193     /* Structured Message ID */
3194     dissect_dmp_structured_id (tvb, field_tree, offset);
3195     proto_tree_add_item (field_tree, hf_message_body_structured, tvb, offset, len, ENC_NA);
3196   } else if (len > 0 && (dmp.body_format == FREE_TEXT ||
3197                          dmp.body_format == FREE_TEXT_SUBJECT)) {
3198     if (compr_alg == ALGORITHM_ZLIB) {
3199       if ((next_tvb = tvb_child_uncompress (tvb, tvb, offset, len)) != NULL) {
3200                 gint zlen = tvb_length (next_tvb);
3201                 add_new_data_source (pinfo, next_tvb, "Uncompressed User data");
3202                 tf = proto_tree_add_none_format (message_tree,
3203                                                  hf_message_body_uncompr,
3204                                                  next_tvb, 0, zlen,
3205                                                  "Uncompressed User data, "
3206                                                  "Length: %d", zlen);
3207                 field_tree = proto_item_add_subtree (tf, ett_message_body_uncompr);
3208                 proto_tree_add_item (field_tree, hf_message_body_uncompressed, next_tvb, 0, -1, ENC_ASCII|ENC_NA);
3209       } else {
3210                 tf = proto_tree_add_text (message_tree, tvb, offset, -1,
3211                                           "Error: Unable to uncompress content");
3212                 expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3213                                         "Unable to uncompress content");
3214       }
3215     } else if (eit != EIT_BILATERAL) {
3216       proto_tree_add_item (field_tree, hf_message_body_plain, tvb, offset, len, ENC_ASCII|ENC_NA);
3217     }
3218   }
3219   offset += len;
3220
3221   if (dmp.struct_id) {
3222     proto_item_append_text (en, ", Id: %s", format_text (dmp.struct_id, strlen (dmp.struct_id)));
3223   }
3224
3225   proto_item_set_len (en, offset - boffset);
3226
3227   return offset;
3228 }
3229
3230 /* Ref chapter 6.3.9.1 Report structure */
3231 static gint dissect_dmp_report (tvbuff_t *tvb, packet_info *pinfo,
3232                                 proto_tree *dmp_tree, gint offset,
3233                                 guint *prev_rec_no, gint num)
3234 {
3235   proto_tree *report_tree = NULL;
3236   proto_tree *field_tree = NULL;
3237   proto_item *en = NULL, *ei = NULL, *tf = NULL;
3238   guint8      report;
3239   gboolean    info_present;
3240   gint32      secs = 0;
3241   gint        len, boffset = offset;
3242   gint        rep_type = 0;
3243
3244   report = tvb_get_guint8 (tvb, offset);
3245   rep_type = (report & 0x80) >> 7;
3246   if (rep_type) {
3247     en = proto_tree_add_item (dmp_tree, hf_non_delivery_report, tvb, offset, 4, ENC_NA);
3248   } else {
3249     en = proto_tree_add_item (dmp_tree, hf_delivery_report, tvb, offset, 4, ENC_NA);
3250   }
3251   proto_item_append_text (en, " (#%d)", num);
3252
3253   report_tree = proto_item_add_subtree (en, ett_report);
3254
3255   /* Report Type */
3256   tf = proto_tree_add_boolean_format (report_tree, hf_report_type,
3257                                       tvb, offset, 1, report,
3258                                       "Report Type: %s", rep_type ?
3259                                       report_type.true_string :
3260                                       report_type.false_string);
3261   field_tree = proto_item_add_subtree (tf, ett_report_type);
3262   proto_tree_add_item (field_tree, hf_report_type, tvb, offset, 1, ENC_BIG_ENDIAN);
3263
3264   if (rep_type == DR) {
3265     dmp.dr = TRUE;
3266     /* Info Present */
3267     info_present = (report & 0x40);
3268     tf = proto_tree_add_boolean_format (report_tree,hf_report_info_present_dr,
3269                                         tvb, offset, 1, report,
3270                                         "Info Present: %s", (report & 0x40) ? "Present" : "Absent");
3271     field_tree = proto_item_add_subtree (tf, ett_report_info_present_dr);
3272     proto_tree_add_item (field_tree, hf_report_info_present_dr, tvb, offset, 1, ENC_BIG_ENDIAN);
3273
3274     /* Address Encoding */
3275     dmp.addr_enc = ((report & 0x20) >> 5);
3276     tf = proto_tree_add_boolean_format (report_tree, hf_report_addr_enc_dr,
3277                                         tvb, offset, 1, report,
3278                                         "Address Encoding: %s",
3279                                         (report & 0x20) ?
3280                                         addr_enc.true_string :
3281                                         addr_enc.false_string);
3282     field_tree = proto_item_add_subtree (tf, ett_report_addr_enc_dr);
3283     proto_tree_add_item (field_tree, hf_report_addr_enc_dr, tvb, offset, 1, ENC_BIG_ENDIAN);
3284
3285     if (report & 0x1F) {
3286       /* Reserved */
3287       tf = proto_tree_add_uint_format (report_tree, hf_reserved_0x1F,
3288                                        tvb, offset, 1, report,
3289                                        "Reserved: %d", report & 0x1F);
3290       field_tree = proto_item_add_subtree (tf, ett_report_reserved);
3291       tf = proto_tree_add_item (field_tree, hf_reserved_0x1F, tvb, offset, 1, ENC_BIG_ENDIAN);
3292       expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3293                               "Reserved value");
3294
3295     }
3296     offset += 1;
3297
3298     /* Delivery Time */
3299     report = tvb_get_guint8 (tvb, offset);
3300     tf = proto_tree_add_uint_format (report_tree, hf_report_del_time,
3301                                      tvb, offset, 1, report,
3302                                      "Delivery Time: ");
3303     field_tree = proto_item_add_subtree (tf, ett_report_del_time);
3304     ei = proto_tree_add_item (field_tree, hf_report_del_time_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3305     secs = dmp_dec_del_time (report);
3306     if (secs == DMP_TIME_RESERVED) {
3307       proto_item_append_text (tf, "Reserved (0x%2.2x)", report);
3308       proto_item_append_text (ei, " (Reserved)");
3309     } else {
3310       proto_item_append_text (tf, "%s (%s)", time_secs_to_str (secs),
3311                               abs_time_secs_to_str (dmp.subm_time - secs, ABSOLUTE_TIME_LOCAL, TRUE));
3312       proto_item_append_text (ei, " (%s from submission time)", time_secs_to_str (secs));
3313     }
3314   } else {
3315     dmp.ndr = TRUE;
3316     /* Address Encoding */
3317     dmp.addr_enc = ((report & 0x40) >> 6);
3318     tf = proto_tree_add_boolean_format (report_tree, hf_report_addr_enc_ndr,
3319                                         tvb, offset, 1, report,
3320                                         "Address Encoding: %s",
3321                                         (report & 0x40) ?
3322                                         addr_enc.true_string :
3323                                         addr_enc.false_string);
3324     field_tree = proto_item_add_subtree (tf, ett_report_addr_enc_ndr);
3325     proto_tree_add_item (field_tree, hf_report_addr_enc_ndr, tvb, offset, 1, ENC_BIG_ENDIAN);
3326
3327     /* Reason */
3328     tf = proto_tree_add_uint_format (report_tree, hf_report_reason,
3329                                      tvb, offset, 1, report,
3330                                      "Reason%s: %s (%d)",
3331                                      ((report & 0x3F) < 0x3D) ? " (P1)":"",
3332                                      non_del_reason_str (report & 0x3F),
3333                                      report & 0x3F);
3334     field_tree = proto_item_add_subtree (tf, ett_report_reason);
3335     proto_tree_add_item (field_tree, hf_report_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
3336     offset += 1;
3337
3338     /* Info Present */
3339     report = tvb_get_guint8 (tvb, offset);
3340     info_present = (report & 0x80);
3341     tf = proto_tree_add_boolean_format (report_tree,
3342                                         hf_report_info_present_ndr,
3343                                         tvb, offset, 1, report,
3344                                         "Info Present: %s", (report & 0x80) ? "Present" : "Absent");
3345     field_tree = proto_item_add_subtree (tf, ett_report_info_present_ndr);
3346     proto_tree_add_item (field_tree, hf_report_info_present_ndr, tvb, offset, 1, ENC_BIG_ENDIAN);
3347
3348     /* Diagnostic */
3349     tf = proto_tree_add_uint_format (report_tree, hf_report_diagn,
3350                                      tvb, offset, 1, report,
3351                                      "Diagnostic%s: %s (%d)",
3352                                      ((report & 0x7F) < 0x7C) ? " (P1)":"",
3353                                      non_del_diagn_str (report & 0x7F),
3354                                      report & 0x7F);
3355     field_tree = proto_item_add_subtree (tf, ett_report_diagn);
3356     proto_tree_add_item (field_tree, hf_report_diagn, tvb, offset, 1, ENC_BIG_ENDIAN);
3357   }
3358   offset += 1;
3359
3360   offset = dissect_dmp_address (tvb, pinfo, report_tree, offset,
3361                                 prev_rec_no, TRUE);
3362
3363   if (info_present) {
3364     /* Supplementary Information */
3365     len = tvb_strsize (tvb, offset);
3366     tf = proto_tree_add_uint_format (report_tree, hf_report_suppl_info_len,
3367                                      tvb, offset, len, len,
3368                                      "Supplementary Information, Length: %d",
3369                                      len - 1);
3370     if (len > 1) {
3371       if ((offset - boffset + len) > 128) {
3372         proto_item_append_text (tf, " (incorrect, should be less than %d)",
3373                                 128 - (offset - boffset));
3374       }
3375       field_tree = proto_item_add_subtree (tf, ett_report_suppl_info);
3376       proto_tree_add_item (field_tree, hf_report_suppl_info, tvb, offset, len, ENC_ASCII|ENC_NA);
3377     }
3378     offset += len;
3379   }
3380
3381   proto_item_set_len (en, offset - boffset);
3382
3383   return offset;
3384 }
3385
3386 /* Ref chapter 6.3.10.1 Notification structure */
3387 static gint dissect_dmp_notification (tvbuff_t *tvb, packet_info *pinfo _U_,
3388                                       proto_tree *dmp_tree, gint offset)
3389 {
3390   proto_tree *notif_tree = NULL;
3391   proto_tree *field_tree = NULL;
3392   proto_item *en = NULL, *ei = NULL, *tf = NULL;
3393   guint8      notif, rec_time, on_typex = 0xFF;
3394   gint        len, boffset = offset;
3395   gint32      secs = 0;
3396
3397   if (dmp.notif_type == RN) {
3398     en = proto_tree_add_item (dmp_tree, hf_receipt_notif, tvb, offset, 4, ENC_NA);
3399   } else if (dmp.notif_type == NRN) {
3400     en = proto_tree_add_item (dmp_tree, hf_non_receipt_notif, tvb, offset, 4, ENC_NA);
3401   } else if (dmp.notif_type == ON) {
3402     en = proto_tree_add_item (dmp_tree, hf_other_notif, tvb, offset, 4, ENC_NA);
3403   } else {
3404     return offset;
3405   }
3406   notif_tree = proto_item_add_subtree (en, ett_notif);
3407
3408   if (dmp.notif_type == RN || dmp.notif_type == ON) {
3409     /* Receipt Time */
3410     rec_time = tvb_get_guint8 (tvb, offset);
3411     tf = proto_tree_add_uint_format (notif_tree, hf_notif_rec_time,
3412                                      tvb, offset, 1, rec_time,
3413                                      "Receipt Time: ");
3414     field_tree = proto_item_add_subtree (tf, ett_notif_rec_time);
3415     ei = proto_tree_add_item (field_tree, hf_notif_rec_time_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3416     secs = dmp_dec_exp_time (rec_time);
3417     if (secs == DMP_TIME_NOT_PRESENT) {
3418       proto_item_append_text (tf, "Not present");
3419       proto_item_append_text (ei, " (not present)");
3420     } else if (secs == DMP_TIME_RESERVED) {
3421       proto_item_append_text (tf, "Reserved (0x%2.2x)", rec_time);
3422       proto_item_append_text (ei, " (Reserved)");
3423     } else {
3424       proto_item_append_text (tf, "%s (%s)", time_secs_to_str (secs),
3425                               abs_time_secs_to_str (dmp.subm_time - secs, ABSOLUTE_TIME_LOCAL, TRUE));
3426       proto_item_append_text (ei, " (%s from submission time)", time_secs_to_str (secs));
3427     }
3428     offset += 1;
3429
3430     if (dmp.notif_type == ON) {
3431       /* ON Type */
3432       on_typex = tvb_get_guint8 (tvb, offset);
3433       proto_tree_add_item (notif_tree, hf_notif_on_type, tvb, offset, 1, ENC_BIG_ENDIAN);
3434       offset += 1;
3435     }
3436
3437     /* Supplementary Information */
3438     len = tvb_strsize (tvb, offset);
3439     tf = proto_tree_add_uint_format (notif_tree, hf_notif_suppl_info_len,
3440                                      tvb, offset, len, len,
3441                                      "Supplementary Information, Length: %d",
3442                                      len - 1);
3443     if (len > 1) {
3444       if ((offset - boffset + len) > 128) {
3445         proto_item_append_text (tf, " (incorrect, should be less than %d)",
3446                                 128 - (offset - boffset));
3447       }
3448       field_tree = proto_item_add_subtree (tf, ett_notif_suppl_info);
3449       proto_tree_add_item (field_tree, hf_notif_suppl_info, tvb, offset, len, ENC_ASCII|ENC_NA);
3450     }
3451     offset += len;
3452
3453     if ((dmp.notif_type == ON) && (on_typex < 0x03)) {
3454       /* ACP127 Receipient */
3455       len = tvb_strsize (tvb, offset);
3456       tf = proto_tree_add_uint_format (notif_tree, hf_notif_acp127,
3457                                        tvb, offset, len, len,
3458                                        "ACP127 Recipient, Length: %d",
3459                                        len - 1);
3460       if (len > 1) {
3461         if (len > 64) {
3462           proto_item_append_text (tf, " (incorrect, must be less than 64)");
3463         }
3464         field_tree = proto_item_add_subtree (tf, ett_notif_acp127recip);
3465         proto_tree_add_item (field_tree, hf_notif_acp127recip, tvb, offset, len, ENC_ASCII|ENC_NA);
3466       }
3467       offset += len;
3468     }
3469   } else if (dmp.notif_type == NRN) {
3470     /* Non-Recipient Reason */
3471     notif = tvb_get_guint8 (tvb, offset);
3472     proto_tree_add_uint_format (notif_tree, hf_notif_non_rec_reason,
3473                                 tvb, offset, 1, notif,
3474                                 "Non-Receipt Reason%s: %s (%d)",
3475                                 (notif < 0x10) ? " (P22)" : "",
3476                                 nrn_reason_str (notif), notif);
3477     offset += 1;
3478
3479     /* Discard Reason */
3480     notif = tvb_get_guint8 (tvb, offset);
3481     proto_tree_add_uint_format (notif_tree, hf_notif_discard_reason,
3482                                 tvb, offset, 1, notif,
3483                                 "Discard Reason%s: %s (%d)",
3484                                 (notif < 0x10) ? " (P22)" : "",
3485                                 discard_reason_str (notif), notif);
3486     offset += 1;
3487   }
3488
3489   proto_item_set_len (en, offset - boffset);
3490
3491   return offset;
3492 }
3493
3494 /* Ref chapter 6.2.1.2.8 SecurityCategories */
3495 static gint dissect_dmp_security_category (tvbuff_t *tvb, packet_info *pinfo,
3496                                            proto_tree *tree, GString *label_string,
3497                                            gint offset, guint8 ext)
3498 {
3499   proto_tree *field_tree = NULL;
3500   proto_item *tf = NULL, *tr = NULL;
3501   gchar      *sec_cat = NULL;
3502   guint8      message;
3503   gboolean    country_code = FALSE;
3504
3505   message = tvb_get_guint8 (tvb, offset);
3506   tf = proto_tree_add_uint_format (tree, hf_message_sec_cat_nat, tvb,
3507                                    offset, 1, message, "Security Categories");
3508   field_tree = proto_item_add_subtree (tf, ett_message_sec_cat);
3509
3510   switch (ext) {
3511
3512   case SEC_CAT_EXT_NONE:
3513     proto_tree_add_item (field_tree, hf_message_sec_cat_cl, tvb, offset, 1, ENC_BIG_ENDIAN);
3514     proto_tree_add_item (field_tree, hf_message_sec_cat_cs, tvb, offset, 1, ENC_BIG_ENDIAN);
3515     proto_tree_add_item (field_tree, hf_message_sec_cat_ex, tvb, offset, 1, ENC_BIG_ENDIAN);
3516     proto_tree_add_item (field_tree, hf_message_sec_cat_ne, tvb, offset, 1, ENC_BIG_ENDIAN);
3517
3518     tr = proto_tree_add_item (field_tree, hf_reserved_0x08, tvb, offset, 1, ENC_BIG_ENDIAN);
3519     if (message & 0x08) {
3520       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3521     }
3522     tr = proto_tree_add_item (field_tree, hf_reserved_0x04, tvb, offset, 1, ENC_BIG_ENDIAN);
3523     if (message & 0x04) {
3524       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3525     }
3526
3527     if (message & 0xF0) {
3528       sec_cat = ep_strdup_printf ("%s%s%s%s",
3529                                   (message & 0x80) ? ",cl" : "",
3530                                   (message & 0x40) ? ",cs" : "",
3531                                   (message & 0x20) ? ",ex" : "",
3532                                   (message & 0x10) ? ",ne" : "");
3533       proto_item_append_text (tf, ": %s", &sec_cat[1]);
3534       g_string_append (label_string, sec_cat);
3535     }
3536     break;
3537
3538   case SEC_CAT_EXT_PERMISSIVE:
3539     if ((message >> 2) == 0x3F) {
3540       /* Fake entry because nat_pol_id defines 0x3F as reserved */
3541       proto_tree_add_uint_format (field_tree, hf_message_sec_cat_permissive, tvb, offset, 1,
3542                                   message, "1111 11.. = Next byte has Country Code (0x3F)");
3543       country_code = TRUE;
3544     } else {
3545       tr = proto_tree_add_item (field_tree, hf_message_sec_cat_permissive, tvb, offset, 1, ENC_BIG_ENDIAN);
3546       proto_item_append_text (tf, ": rel-to-%s", get_nat_pol_id_short (message >> 2));
3547       g_string_append_printf (label_string, ",rel-to-%s", get_nat_pol_id_short (message >> 2));
3548       if ((message >> 2) == 0) {
3549         expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3550       }
3551     }
3552     break;
3553
3554   case SEC_CAT_EXT_RESTRICTIVE:
3555     proto_tree_add_item (field_tree, hf_message_sec_cat_restrictive, tvb, offset, 1, ENC_BIG_ENDIAN);
3556     proto_item_append_text (tf, " (restrictive: 0x%2.2x)", message >> 2);
3557     break;
3558
3559   default:
3560     break;
3561   }
3562
3563   proto_item_append_text (tf, " (0x%2.2x)", message);
3564
3565   if (dmp.version == 1) {
3566     tr = proto_tree_add_item (field_tree, hf_reserved_0x02, tvb, offset, 1, ENC_BIG_ENDIAN);
3567     if (message & 0x02) {
3568       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3569     }
3570     tr = proto_tree_add_item (field_tree, hf_reserved_0x01, tvb, offset, 1, ENC_BIG_ENDIAN);
3571     if (message & 0x01) {
3572       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3573     }
3574   } else {
3575     tr = proto_tree_add_item (field_tree, hf_message_sec_cat_extended, tvb, offset, 1, ENC_BIG_ENDIAN);
3576     if ((message & 0x01) && (message & 0x02)) {
3577       expert_add_info_format (pinfo, tr, PI_UNDECODED, PI_WARN, "Reserved value");
3578     } else if (message & 0x01 || message & 0x02) {
3579       proto_item_append_text (tf, " (extended)");
3580       offset = dissect_dmp_security_category (tvb, pinfo, tree, label_string, offset+1, message & 0x03);
3581     }
3582
3583     if (country_code) {
3584       proto_tree_add_item (field_tree, hf_message_sec_cat_country_code, tvb, offset+1, 1, ENC_BIG_ENDIAN);
3585       proto_item_append_text (tf, " (rel-to country-code: %d)", tvb_get_guint8 (tvb, offset+1));
3586       proto_item_set_len (tf, 2);
3587       offset++;
3588     }
3589   }
3590
3591   return offset;
3592 }
3593
3594 /*
3595  * Ref chapter 6.3.7.1 STANAG 4406 message structure
3596  * and chapter 6.3.8.1 IPM 88 message structure
3597  * and chapter 6.3.9.1 Report structure
3598  * and chapter 6.3.10.1 Notification structure
3599  */
3600 static gint dissect_dmp_content (tvbuff_t *tvb, packet_info *pinfo,
3601                                  proto_tree *dmp_tree, gint offset)
3602 {
3603   proto_tree *message_tree = NULL;
3604   proto_tree *field_tree = NULL;
3605   proto_item *en = NULL, *ei = NULL, *tf = NULL;
3606   proto_item *hidden_item;
3607   GString    *label_string = g_string_new ("");
3608   const gchar *class_name = NULL;
3609   guint8      message, dmp_sec_pol, dmp_sec_class, dmp_nation = 0, exp_time, dtg;
3610   gint32      secs = 0;
3611   guint       prev_rec_no = 0;
3612   gint        rep_len, rep_no = 1;
3613   gint        loffset, boffset = offset;
3614
3615   if (dmp.msg_type == REPORT) {
3616     en = proto_tree_add_item (dmp_tree, hf_report_content, tvb, offset, 7, ENC_NA);
3617   } else if (dmp.msg_type == NOTIF) {
3618     en = proto_tree_add_item (dmp_tree, hf_notif_content, tvb, offset, 7, ENC_NA);
3619   } else {
3620     en = proto_tree_add_item (dmp_tree, hf_message_content, tvb, offset, 7, ENC_NA);
3621   }
3622   message_tree = proto_item_add_subtree (en, ett_content);
3623
3624   if (dmp.msg_type == STANAG || dmp.msg_type == IPM) {
3625     message = tvb_get_guint8 (tvb, offset);
3626     dmp.body_format = (message & 0x03);
3627
3628     if (dmp.msg_type == STANAG) {
3629       /* Message Type */
3630       dmp.st_type = (message & 0xC0) >> 6;
3631       tf = proto_tree_add_uint_format (message_tree, hf_message_st_type,
3632                                        tvb, offset, 1, message,
3633                                        "Message Type: %s (%d)",
3634                                        val_to_str (dmp.st_type,
3635                                                    message_type_vals, ""),
3636                                        dmp.st_type);
3637       field_tree = proto_item_add_subtree (tf, ett_message_st_type);
3638       proto_tree_add_item (field_tree, hf_message_st_type, tvb, offset, 1, ENC_BIG_ENDIAN);
3639
3640       if ((message & 0x20) >> 5) {
3641         /* Reserved */
3642         tf = proto_tree_add_uint_format (message_tree, hf_reserved_0x20,
3643                                          tvb, offset, 1, message,
3644                                          "Reserved: %d", (message & 0x20)>>5);
3645         field_tree = proto_item_add_subtree (tf, ett_message_reserved);
3646         tf = proto_tree_add_item (field_tree, hf_reserved_0x20, tvb, offset, 1, ENC_BIG_ENDIAN);
3647         expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3648                                 "Reserved value");
3649       }
3650
3651       /* Precedence */
3652       dmp.prec = (message & 0x1C) >> 2;
3653       tf = proto_tree_add_uint_format (message_tree, hf_message_precedence,
3654                                        tvb, offset, 1, message,
3655                                        "Precedence: %s (%d)",
3656                                        val_to_str (dmp.prec, precedence, ""),
3657                                        dmp.prec);
3658       field_tree = proto_item_add_subtree (tf, ett_message_precedence);
3659       proto_tree_add_item (field_tree, hf_message_precedence, tvb, offset, 1, ENC_BIG_ENDIAN);
3660
3661     } else {
3662       if ((message & 0xE0) >> 5) {
3663         /* Reserved */
3664         tf = proto_tree_add_uint_format (message_tree, hf_reserved_0xE0,
3665                                          tvb, offset, 1, message,
3666                                          "Reserved: %d", (message & 0xE0)>>5);
3667         field_tree = proto_item_add_subtree (tf, ett_message_reserved);
3668         tf = proto_tree_add_item (field_tree, hf_reserved_0xE0, tvb, offset, 1, ENC_BIG_ENDIAN);
3669         expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3670                                 "Reserved value");
3671       }
3672
3673       /* Importance */
3674       dmp.prec = (message & 0x1C) >> 2;
3675       tf = proto_tree_add_uint_format (message_tree, hf_message_importance,
3676                                        tvb, offset, 1, message,
3677                                        "Importance: %s (%d)",
3678                                        val_to_str (dmp.prec, importance, ""),
3679                                        dmp.prec);
3680       field_tree = proto_item_add_subtree (tf, ett_message_importance);
3681       proto_tree_add_item (field_tree, hf_message_importance, tvb, offset, 1, ENC_BIG_ENDIAN);
3682     }
3683
3684     /* Body Format */
3685     tf = proto_tree_add_uint_format (message_tree, hf_message_body_format,
3686                                      tvb, offset, 1, message,
3687                                      "Body Format: %s (%d)",
3688                                      val_to_str (message & 0x03,
3689                                                  body_format_vals, ""),
3690                                      message & 0x03);
3691     field_tree = proto_item_add_subtree (tf, ett_message_body_format);
3692     proto_tree_add_item (field_tree, hf_message_body_format, tvb, offset, 1, ENC_BIG_ENDIAN);
3693     offset += 1;
3694   }
3695
3696   message = tvb_get_guint8 (tvb, offset);
3697   /* Security Classification */
3698   dmp_sec_class = (message & 0xE0) >> 5;
3699   dmp_sec_pol = (message & 0x1C) >> 2;
3700   if (dmp_sec_pol == EXTENDED_NATIONAL) {
3701     dmp_nation = tvb_get_guint8 (tvb, offset + 1);
3702   }
3703
3704   loffset = offset; /* Offset to start of security label */
3705   if (dmp_sec_pol == NATIONAL && dmp_local_nation != 0) {
3706     class_name = dmp_national_sec_class (dmp_local_nation, dmp_sec_class);
3707   } else if (dmp_sec_pol == EXTENDED_NATIONAL) {
3708     class_name = dmp_national_sec_class (dmp_nation, dmp_sec_class);
3709   }
3710   if ((dmp_sec_pol == NATO || dmp_sec_pol == NATIONAL) && !class_name) {
3711     class_name = val_to_str (dmp_sec_class, sec_class, "");
3712   }
3713   if (class_name && class_name[0]) {
3714     tf = proto_tree_add_uint_format (message_tree, hf_message_sec_class_val,
3715                                      tvb, offset, 1, message,
3716                                      "Security Classification: %s (%d)",
3717                                      class_name, dmp_sec_class);
3718   } else {
3719     tf = proto_tree_add_uint_format (message_tree, hf_message_sec_class_val,
3720                                      tvb, offset, 1, message,
3721                                      "Security Classification: %d",
3722                                      dmp_sec_class);
3723   }
3724   field_tree = proto_item_add_subtree (tf, ett_message_sec_class);
3725   tf = proto_tree_add_item (field_tree, hf_message_sec_class_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3726   if (class_name) {
3727     proto_item_append_text (tf, " (%s)", class_name);
3728     g_string_append (label_string, class_name);
3729   }
3730
3731   /* Security Policy */
3732   tf = proto_tree_add_uint_format (message_tree, hf_message_sec_pol,
3733                                    tvb, offset, 1, message,
3734                                    "Security Policy: %s (%d)",
3735                                    val_to_str (dmp_sec_pol, sec_pol, "%d"),
3736                                    dmp_sec_pol);
3737   field_tree = proto_item_add_subtree (tf, ett_message_sec_pol);
3738   proto_tree_add_item (field_tree, hf_message_sec_pol, tvb, offset, 1, ENC_BIG_ENDIAN);
3739
3740   if (dmp.msg_type == STANAG || dmp.msg_type == IPM) {
3741     /* Heading Flags */
3742     tf = proto_tree_add_item (message_tree, hf_message_heading_flags, tvb, offset, 1, ENC_NA);
3743     field_tree = proto_item_add_subtree (tf, ett_message_heading_flags);
3744     proto_tree_add_item (field_tree, hf_message_auth_users, tvb, offset, 1, ENC_BIG_ENDIAN);
3745     proto_tree_add_item (field_tree, hf_message_subject_disc, tvb, offset, 1, ENC_BIG_ENDIAN);
3746     if (message & 0x03) {
3747       proto_item_append_text (tf, ": %s%s%s discarded",
3748                               (message & 0x02) ? "Authorizing users" : "",
3749                               (message & 0x03) == 0x03 ? " and " : "",
3750                               (message & 0x01) ? "Subject" : "");
3751     } else {
3752       proto_item_append_text (tf, " (none)");
3753     }
3754   } else if (dmp.msg_type == NOTIF) {
3755     /* Notification Type */
3756     dmp.notif_type = (message & 0x03);
3757     tf = proto_tree_add_uint_format (message_tree, hf_notif_type,
3758                                      tvb, offset, 1, message,
3759                                      "Notification Type: %s",
3760                                      val_to_str (dmp.notif_type, notif_type,
3761                                                  "Reserved"));
3762     field_tree = proto_item_add_subtree (tf, ett_notif_type);
3763     proto_tree_add_item (field_tree, hf_notif_type, tvb, offset, 1, ENC_BIG_ENDIAN);
3764   } else if (message & 0x02) {
3765     /* Reserved */
3766     tf = proto_tree_add_uint_format (message_tree, hf_reserved_0x02,
3767                                      tvb, offset, 1, message,
3768                                      "Reserved: %d", message & 0x02);
3769     field_tree = proto_item_add_subtree (tf, ett_message_reserved);
3770     tf = proto_tree_add_item (field_tree, hf_reserved_0x02, tvb, offset, 1, ENC_BIG_ENDIAN);
3771     expert_add_info_format (pinfo, tf, PI_UNDECODED, PI_WARN,
3772                             "Reserved value");
3773   }
3774   offset += 1;
3775
3776   if (dmp_sec_pol == NATIONAL && dmp_local_nation != 0) {
3777     /* Show configured national policy */
3778     tf = proto_tree_add_uint (message_tree, hf_message_national_policy_id,
3779                               tvb, offset, 0, dmp_local_nation);
3780     PROTO_ITEM_SET_GENERATED (tf);
3781   } else if (dmp_sec_pol == EXTENDED_NATIONAL) {
3782     /* National Policy Identifier */
3783     proto_tree_add_item (message_tree, hf_message_national_policy_id, tvb, offset, 1, ENC_BIG_ENDIAN);
3784     offset += 1;
3785   } else if (dmp_sec_pol == EXTENDED_MISSION) {
3786     /* Mission Policy Identifier */
3787     message = tvb_get_guint8 (tvb, offset);
3788     if (message == 0xFF) {
3789       proto_tree_add_uint_format (message_tree, hf_message_mission_policy_id,
3790                                   tvb, offset, 1, message,
3791                                   "Mission Policy Identifier: Reserved (0xFF)");
3792     } else {
3793       proto_tree_add_item (message_tree, hf_message_mission_policy_id, tvb, offset, 1, ENC_BIG_ENDIAN);
3794     }
3795     offset += 1;
3796   }
3797
3798   /* Security Categories */
3799   if (dmp_sec_pol == NATO || dmp_sec_pol == NATIONAL || dmp_sec_pol == EXTENDED_NATIONAL) {
3800     offset = dissect_dmp_security_category (tvb, pinfo, message_tree, label_string, offset, 0);
3801     proto_item_append_text (en, ", Security Label: %s", label_string->str);
3802     tf = proto_tree_add_string (message_tree, hf_message_sec_label, tvb, loffset,
3803                                 offset - loffset + 1, label_string->str);
3804     PROTO_ITEM_SET_GENERATED (tf);
3805   } else {
3806     tf = proto_tree_add_item (message_tree, hf_message_sec_cat_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3807     field_tree = proto_item_add_subtree (tf, ett_message_sec_cat);
3808
3809     proto_tree_add_item (field_tree, hf_message_sec_cat_bit7, tvb, offset, 1, ENC_BIG_ENDIAN);
3810     proto_tree_add_item (field_tree, hf_message_sec_cat_bit6, tvb, offset, 1, ENC_BIG_ENDIAN);
3811     proto_tree_add_item (field_tree, hf_message_sec_cat_bit5, tvb, offset, 1, ENC_BIG_ENDIAN);
3812     proto_tree_add_item (field_tree, hf_message_sec_cat_bit4, tvb, offset, 1, ENC_BIG_ENDIAN);
3813     proto_tree_add_item (field_tree, hf_message_sec_cat_bit3, tvb, offset, 1, ENC_BIG_ENDIAN);
3814     proto_tree_add_item (field_tree, hf_message_sec_cat_bit2, tvb, offset, 1, ENC_BIG_ENDIAN);
3815     proto_tree_add_item (field_tree, hf_message_sec_cat_bit1, tvb, offset, 1, ENC_BIG_ENDIAN);
3816     proto_tree_add_item (field_tree, hf_message_sec_cat_bit0, tvb, offset, 1, ENC_BIG_ENDIAN);
3817   }
3818   offset += 1;
3819
3820   if (dmp.msg_type == STANAG || dmp.msg_type == IPM) {
3821     /* Expiry Time */
3822     exp_time = tvb_get_guint8 (tvb, offset);
3823     tf = proto_tree_add_uint_format (message_tree, hf_message_exp_time,
3824                                      tvb, offset, 1, exp_time,
3825                                      "Expiry Time: ");
3826     field_tree = proto_item_add_subtree (tf, ett_message_exp_time);
3827     ei = proto_tree_add_item (field_tree, hf_message_exp_time_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3828     secs = dmp_dec_exp_time (exp_time);
3829     if (secs == DMP_TIME_NOT_PRESENT) {
3830       proto_item_append_text (tf, "Not present");
3831       proto_item_append_text (ei, " (not present)");
3832     } else if (secs == DMP_TIME_RESERVED) {
3833       proto_item_append_text (tf, "Reserved (0x%2.2x)", exp_time);
3834       proto_item_append_text (ei, " (Reserved)");
3835     } else {
3836       proto_item_append_text (tf, "%s (%s)", time_secs_to_str (secs),
3837                               abs_time_secs_to_str (dmp.subm_time + secs, ABSOLUTE_TIME_LOCAL, TRUE));
3838       proto_item_append_text (ei, " (%s from submission time)", time_secs_to_str (secs));
3839     }
3840     offset += 1;
3841   }
3842
3843   if (dmp.msg_type == STANAG) {
3844     dtg = tvb_get_guint8 (tvb, offset);
3845     tf = proto_tree_add_uint_format (message_tree, hf_message_dtg, tvb, offset, 1, dtg, "DTG: ");
3846     field_tree = proto_item_add_subtree (tf, ett_message_dtg);
3847     proto_tree_add_item (field_tree, hf_message_dtg_sign, tvb, offset, 1, ENC_BIG_ENDIAN);
3848     proto_tree_add_item (field_tree, hf_message_dtg_val, tvb, offset, 1, ENC_BIG_ENDIAN);
3849     secs = dmp_dec_dtg (dtg & 0x7F);
3850     if (secs == DMP_TIME_NOT_PRESENT) {
3851       proto_item_append_text (tf, "Not present");
3852     } else if (secs == DMP_TIME_RESERVED) {
3853       proto_item_append_text (tf, "Reserved (0x%2.2x)", dtg & 0x7F);
3854     } else if (secs == 0) {
3855       proto_item_append_text (tf, "0 minutes in the %s (%s)",
3856                               (dtg & 0x80) ? dtg_sign.true_string :
3857                               dtg_sign.false_string,
3858                               abs_time_secs_to_str (dmp.subm_time, ABSOLUTE_TIME_LOCAL, TRUE));
3859     } else {
3860       proto_item_append_text (tf, "%s in the %s (%s)", time_secs_to_str(secs),
3861                               (dtg & 0x80) ? dtg_sign.true_string :
3862                               dtg_sign.false_string, (dtg & 0x80) ?
3863                               abs_time_secs_to_str (dmp.subm_time + secs, ABSOLUTE_TIME_LOCAL, TRUE) :
3864                               abs_time_secs_to_str (dmp.subm_time - secs, ABSOLUTE_TIME_LOCAL, TRUE));
3865     }
3866     offset += 1;
3867   }
3868
3869   if (dmp.msg_type == STANAG) {
3870     /* SIC */
3871     offset = dissect_dmp_sic (tvb, pinfo, message_tree, offset);
3872   } else if (dmp.msg_type == REPORT || dmp.msg_type == NOTIF) {
3873     if (dmp.version == DMP_VERSION_1 || dmp.msg_id_type == ONLY_DMP_ID) {
3874       /* Subject Message Identifier */
3875       dmp.subj_id = tvb_get_ntohs (tvb, offset);
3876       proto_tree_add_item (message_tree, hf_message_subj_id, tvb, offset, 2, ENC_BIG_ENDIAN);
3877       hidden_item = proto_tree_add_item (message_tree, hf_dmp_id, tvb, offset, 2, ENC_BIG_ENDIAN);
3878       PROTO_ITEM_SET_HIDDEN (hidden_item);
3879       offset += 2;
3880     } else if (dmp.msg_id_type == X400_MSG_ID || dmp.msg_id_type == NAT_MSG_ID) {
3881       if (dmp.msg_type == REPORT) {
3882         /* Subject MTS Identifier */
3883         offset = dissect_mts_identifier (tvb, pinfo, message_tree, offset, TRUE);
3884       } else {
3885         /* Subject IPM Identifier */
3886         offset = dissect_ipm_identifier (tvb, pinfo, message_tree, offset, TRUE);
3887       }
3888       if (dmp.subj_id) {
3889         tf = proto_tree_add_uint (message_tree, hf_message_subj_id, tvb, offset, 0, dmp.subj_id);
3890         PROTO_ITEM_SET_GENERATED (tf);
3891         hidden_item = proto_tree_add_uint (message_tree, hf_dmp_id, tvb, offset, 0, dmp.subj_id);
3892         PROTO_ITEM_SET_GENERATED (hidden_item);
3893         PROTO_ITEM_SET_HIDDEN (hidden_item);
3894       }
3895     }
3896   }
3897
3898   if (use_seq_ack_analysis) {
3899     register_dmp_id (pinfo, 0);
3900   }
3901
3902   proto_item_set_len (en, offset - boffset);
3903
3904   if  (dmp.msg_type == STANAG || dmp.msg_type == IPM) {
3905     /* User Data */
3906     offset = dissect_dmp_message (tvb, pinfo, dmp_tree, offset);
3907   } else if (dmp.msg_type == REPORT) {
3908     /* One or more Delivery Report or Non-Delivery Report Data */
3909     rep_len = tvb_length (tvb);
3910     if (dmp.checksum) {
3911       rep_len -= 2;
3912     }
3913     while (offset < rep_len) {
3914       offset = dissect_dmp_report (tvb, pinfo, dmp_tree, offset, &prev_rec_no, rep_no++);
3915     }
3916   } else if (dmp.msg_type == NOTIF) {
3917     /* Notification Data */
3918     offset = dissect_dmp_notification (tvb, pinfo, dmp_tree, offset);
3919   }
3920
3921   g_string_free (label_string, TRUE);
3922
3923   return offset;
3924 }
3925
3926 static gint dissect_dmp_extensions (tvbuff_t *tvb, packet_info *pinfo _U_,
3927                                     proto_tree *dmp_tree, gint offset)
3928 {
3929   proto_tree *exts_tree, *ext_tree, *hdr_tree;
3930   proto_item *exts_item, *en;
3931   guint8      ext_hdr, ext_length;
3932   gboolean    more_extensions = TRUE;
3933   gint        num_ext = 0, boffset = offset;
3934
3935   exts_item = proto_tree_add_item (dmp_tree, hf_extensions, tvb, offset, -1, ENC_NA);
3936   exts_tree = proto_item_add_subtree (exts_item, ett_extensions);
3937
3938   while (more_extensions) {
3939     /* Extensions Present */
3940     ext_hdr = tvb_get_guint8 (tvb, offset);
3941     more_extensions = (ext_hdr & 0x80);
3942     ext_length = (ext_hdr & 0x7F) + 1;
3943
3944     en = proto_tree_add_none_format (exts_tree, hf_extension, tvb, offset, ext_length + 1,
3945                                      "Extension (#%d)", num_ext + 1);
3946     ext_tree = proto_item_add_subtree (en, ett_extension);
3947
3948     en = proto_tree_add_none_format (ext_tree, hf_extension_header, tvb, offset, 1,
3949                                      "Extension Length: %u, More %s", ext_length,
3950                                      (ext_hdr & 0x80) ? "Present" : "Not present");
3951     hdr_tree = proto_item_add_subtree (en, ett_extension_header);
3952     proto_tree_add_item (hdr_tree, hf_extension_more, tvb, offset, 1, ENC_BIG_ENDIAN);
3953     proto_tree_add_item (hdr_tree, hf_extension_length, tvb, offset, 1, ENC_BIG_ENDIAN);
3954     offset += 1;
3955
3956     proto_tree_add_item (ext_tree, hf_extension_data, tvb, offset, ext_length, ENC_NA);
3957     offset += ext_length;
3958     num_ext++;
3959   }
3960
3961   proto_item_append_text (exts_item, " (%d item%s)", num_ext, plurality (num_ext, "", "s"));
3962   proto_item_set_len (exts_item, offset - boffset);
3963
3964   return offset;
3965 }
3966
3967 static void dissect_dmp (tvbuff_t *tvb, packet_info *pinfo,
3968                          proto_tree *tree)
3969 {
3970   proto_tree *dmp_tree = NULL, *checksum_tree = NULL;
3971   proto_item *ti = NULL, *en = NULL;
3972   guint16     checksum1 = 0, checksum2 = 1;
3973   gint        length, offset = 0;
3974   gboolean    retrans_or_dup_ack = FALSE;
3975
3976   col_set_str (pinfo->cinfo, COL_PROTOCOL, "DMP");
3977   col_clear (pinfo->cinfo, COL_INFO);
3978
3979   /* Initialize global data structure */
3980   memset (&dmp, 0, sizeof (dmp));
3981
3982   ti = proto_tree_add_item (tree, proto_dmp, tvb, offset, -1, ENC_NA);
3983   dmp_tree = proto_item_add_subtree (ti, ett_dmp);
3984
3985   offset = dissect_dmp_envelope (tvb, pinfo, dmp_tree, offset);
3986
3987   if (dmp.version > DMP_VERSION_2) {
3988     /* Unsupported DMP Version, no point to continue */
3989     col_add_fstr (pinfo->cinfo, COL_INFO, "Unsupported Version: %d", dmp.version);
3990     return;
3991   }
3992
3993   if (dmp.extensions) {
3994     offset = dissect_dmp_extensions (tvb, pinfo, dmp_tree, offset);
3995   }
3996
3997   if ((dmp.msg_type == STANAG) || (dmp.msg_type == IPM) ||
3998       (dmp.msg_type == REPORT) || (dmp.msg_type == NOTIF))
3999   {
4000     offset = dissect_dmp_content (tvb, pinfo, dmp_tree, offset);
4001   } else if (dmp.msg_type == ACK) {
4002     offset = dissect_dmp_ack (tvb, pinfo, dmp_tree, offset);
4003   }
4004
4005   if (dmp.checksum) {
4006     length = tvb_length (tvb);
4007     checksum1 = crc16_x25_ccitt_tvb (tvb, length - 2);
4008     checksum2 = tvb_get_ntohs (tvb, offset);
4009
4010     en = proto_tree_add_item (dmp_tree, hf_checksum, tvb, offset, 2, ENC_BIG_ENDIAN);
4011     checksum_tree = proto_item_add_subtree (en, ett_checksum);
4012     if (checksum1 == checksum2) {
4013       proto_item_append_text (en, " (correct)");
4014       en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
4015                                    offset, 2, TRUE);
4016       PROTO_ITEM_SET_GENERATED (en);
4017       en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
4018                                    offset, 2, FALSE);
4019       PROTO_ITEM_SET_GENERATED (en);
4020     } else {
4021       proto_item_append_text (en, " (incorrect, should be 0x%04x)",
4022                               checksum1);
4023       expert_add_info_format (pinfo, en, PI_CHECKSUM, PI_WARN, "Bad checksum");
4024       en = proto_tree_add_boolean (checksum_tree, hf_checksum_good, tvb,
4025                                    offset, 2, FALSE);
4026       PROTO_ITEM_SET_GENERATED (en);
4027       en = proto_tree_add_boolean (checksum_tree, hf_checksum_bad, tvb,
4028                                    offset, 2, TRUE);
4029       PROTO_ITEM_SET_GENERATED (en);
4030     }
4031   }
4032
4033   if (use_seq_ack_analysis) {
4034     dmp_add_seq_ack_analysis (tvb, pinfo, dmp_tree, offset);
4035   }
4036
4037     if (((dmp.msg_type == STANAG) || (dmp.msg_type == IPM) ||
4038          (dmp.msg_type == REPORT) || (dmp.msg_type == NOTIF)) &&
4039         dmp.id_val && dmp.id_val->msg_resend_count)
4040     {
4041       guint retrans_num;
4042       if (dmp.msg_type == REPORT) {
4043         retrans_num = dmp.id_val->rep_id;
4044       } else if (dmp.msg_type == NOTIF) {
4045         retrans_num = dmp.id_val->not_id;
4046       } else {
4047         retrans_num = dmp.id_val->msg_id;
4048       }
4049       col_append_fstr (pinfo->cinfo, COL_INFO, "[Retrans %d#%d] ",
4050                        retrans_num, dmp.id_val->msg_resend_count);
4051       retrans_or_dup_ack = TRUE;
4052     } else if (dmp.msg_type == ACK && dmp.id_val && dmp.id_val->ack_resend_count) {
4053       col_append_fstr (pinfo->cinfo, COL_INFO, "[Dup ACK %d#%d] ",
4054                        dmp.id_val->ack_id, dmp.id_val->ack_resend_count);
4055       retrans_or_dup_ack = TRUE;
4056   }
4057   if (dmp_align && !retrans_or_dup_ack) {
4058     if (dmp.msg_type == ACK) {
4059       /* ACK does not have "Msg Id" */
4060       col_append_fstr (pinfo->cinfo, COL_INFO, "%-45.45s", msg_type_to_str ());
4061     } else {
4062       col_append_fstr (pinfo->cinfo, COL_INFO, "%-31.31s", msg_type_to_str ());
4063     }
4064   } else {
4065     col_append_str (pinfo->cinfo, COL_INFO, msg_type_to_str ());
4066   }
4067   if ((dmp.msg_type == STANAG) || (dmp.msg_type == IPM) ||
4068       (dmp.msg_type == REPORT) || (dmp.msg_type == NOTIF))
4069   {
4070     if (dmp_align && !retrans_or_dup_ack) {
4071       col_append_fstr (pinfo->cinfo, COL_INFO, " Msg Id: %5d", dmp.msg_id);
4072     } else {
4073       col_append_fstr (pinfo->cinfo, COL_INFO, ", Msg Id: %d", dmp.msg_id);
4074     }
4075   }
4076   if ((dmp.msg_type == REPORT) || (dmp.msg_type == NOTIF) ||
4077       (dmp.msg_type == ACK))
4078   {
4079     if (dmp_align && !retrans_or_dup_ack) {
4080       col_append_fstr (pinfo->cinfo, COL_INFO, "  Subj Id: %5d",
4081                        dmp.subj_id);
4082     } else {
4083       col_append_fstr (pinfo->cinfo, COL_INFO, ", Subj Id: %d",
4084                        dmp.subj_id);
4085     }
4086   } else if (dmp.struct_id) {
4087     if (dmp_align && !retrans_or_dup_ack) {
4088       col_append_fstr (pinfo->cinfo, COL_INFO, "  Body Id: %s",
4089                        format_text (dmp.struct_id, strlen (dmp.struct_id)));
4090     } else {
4091       col_append_fstr (pinfo->cinfo, COL_INFO, ", Body Id: %s",
4092                        format_text (dmp.struct_id, strlen (dmp.struct_id)));
4093     }
4094   }
4095   if (dmp.checksum && (checksum1 != checksum2)) {
4096     col_append_str (pinfo->cinfo, COL_INFO, ", Checksum incorrect");
4097   }
4098
4099   proto_item_append_text (ti, ", Version: %d%s, %s", dmp.version,
4100                           (dmp.prot_id == PROT_NAT ? " (national)" : ""),
4101                           msg_type_to_str());
4102 }
4103
4104 static void dmp_init_routine (void)
4105 {
4106   if (dmp_id_hash_table) {
4107     g_hash_table_destroy (dmp_id_hash_table);
4108   }
4109   if (dmp_long_id_hash_table) {
4110     g_hash_table_destroy (dmp_long_id_hash_table);
4111   }
4112
4113   dmp_id_hash_table = g_hash_table_new (dmp_id_hash, dmp_id_hash_equal);
4114   dmp_long_id_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
4115 }
4116
4117 void proto_register_dmp (void)
4118 {
4119   static hf_register_info hf[] = {
4120     /*
4121     ** DMP Identifier
4122     */
4123     { &hf_dmp_id,
4124       { "DMP Identifier", "dmp.id", FT_UINT16, BASE_DEC,
4125         NULL, 0x0, NULL, HFILL}},
4126
4127     /* MTS Identifier */
4128     { &hf_mts_id,
4129       { "MTS Identifier", "dmp.mts", FT_STRING, BASE_NONE,
4130         NULL, 0x0, NULL, HFILL } },
4131
4132     /* IPM Identifier */
4133     { &hf_ipm_id,
4134       { "IPM Identifier", "dmp.ipm", FT_STRING, BASE_NONE,
4135         NULL, 0x0, NULL, HFILL } },
4136
4137     /*
4138     ** Envelope
4139     */
4140     { &hf_envelope,
4141       { "Envelope", "dmp.envelope", FT_NONE, BASE_NONE,
4142         NULL, 0x0, NULL, HFILL}},
4143
4144     /* Protocol data */
4145     { &hf_envelope_protocol_id,
4146       { "Protocol Identifier", "dmp.protocol_id", FT_UINT8,
4147         BASE_HEX, NULL, 0xF8, NULL, HFILL}},
4148     { &hf_envelope_version,
4149       { "Protocol Version", "dmp.version", FT_UINT8, BASE_DEC,
4150         VALS(version_vals), 0x07, NULL, HFILL } },
4151     { &hf_envelope_version_value,
4152       { "Protocol Version", "dmp.version_value", FT_UINT8, BASE_DEC,
4153         VALS(version_vals), 0x07, NULL, HFILL } },
4154
4155     /* Envelope elements (byte 1) */
4156     { &hf_envelope_hop_count,
4157       { "Hop Count", "dmp.hop_count", FT_UINT8, BASE_DEC,
4158         NULL, 0xE0, NULL, HFILL } },
4159     { &hf_envelope_hop_count_value,
4160       { "Hop Count", "dmp.hop_count_value", FT_UINT8, BASE_DEC,
4161         NULL, 0xE0, NULL, HFILL } },
4162     { &hf_envelope_rec_present,
4163       { "Recipient Present", "dmp.rec_present", FT_BOOLEAN, 8,
4164         TFS (&tfs_present_absent), 0x20, NULL, HFILL } },
4165     { &hf_envelope_addr_enc,
4166       { "Address Encoding", "dmp.addr_encoding", FT_BOOLEAN, 8,
4167         TFS (&addr_enc), 0x10, NULL, HFILL } },
4168     { &hf_envelope_checksum,
4169       { "Checksum", "dmp.checksum_used", FT_BOOLEAN, 8,
4170         TFS (&tfs_used_notused), 0x08, "Checksum Used", HFILL } },
4171     { &hf_envelope_type,
4172       { "Content Type", "dmp.content_type", FT_UINT8, BASE_DEC,
4173         VALS(type_vals), 0x07, NULL, HFILL } },
4174
4175     /* Envelope elements (byte 2) */
4176     { &hf_envelope_extensions,
4177       { "Extensions", "dmp.extensions_used", FT_BOOLEAN, 8,
4178         TFS (&tfs_present_absent), 0x80, "Extensions Used", HFILL } },
4179     { &hf_envelope_msg_id_type,
4180       { "Message Identifier Type", "dmp.msg_id_type", FT_UINT8, BASE_DEC,
4181         VALS(msg_id_type_vals), 0x60, NULL, HFILL } },
4182     { &hf_envelope_msg_id_length,
4183       { "Message Identifier Length", "dmp.msg_id_short", FT_UINT8, BASE_DEC,
4184         VALS(msg_id_length_vals), 0x10, NULL, HFILL}},
4185     { &hf_envelope_mts_id_length,
4186       { "MTS Identifier Length", "dmp.mts_id_length", FT_UINT8, BASE_DEC,
4187         NULL, 0x1F, NULL, HFILL } },
4188     { &hf_envelope_ipm_id_modifier,
4189       { "IPM Identifier Modifier", "dmp.ipm_id_modifier", FT_UINT8, BASE_DEC,
4190         VALS(ipm_id_modifier), 0xC0, NULL, HFILL } },
4191     { &hf_envelope_ipm_id_length,
4192       { "IPM Identifier Length", "dmp.ipm_id_length", FT_UINT8, BASE_DEC,
4193         NULL, 0x3F, NULL, HFILL } },
4194
4195     { &hf_thales_ipm_id_modifier,
4196       { "IPM Identifier Modifier", "dmp.ipm_id_modifier", FT_UINT8, BASE_DEC,
4197         VALS(thales_ipm_id_modifier), 0xC0, "Thales XOmail IPM Identifier Modifier", HFILL } },
4198
4199     /* Message identifier */
4200     { &hf_envelope_msg_id,
4201       { "Message Identifier", "dmp.msg_id", FT_UINT16, BASE_DEC,
4202         NULL, 0x0, NULL, HFILL}},
4203     { &hf_envelope_msg_id_12bit,
4204       { "Message Identifier", "dmp.msg_id", FT_UINT16, BASE_DEC,
4205         NULL, 0x0FFF, NULL, HFILL}},
4206
4207     /* MTS Identifier */
4208     { &hf_envelope_mts_id,
4209       { "MTS Identifier", "dmp.mts_id", FT_STRING, BASE_NONE,
4210         NULL, 0x0, NULL, HFILL } },
4211
4212     /* IPM Identifier */
4213     { &hf_envelope_ipm_id,
4214       { "IPM Identifier", "dmp.ipm_id", FT_STRING, BASE_NONE,
4215         NULL, 0x0, NULL, HFILL } },
4216
4217     /* Extensions */
4218     { &hf_extensions,
4219       { "Extensions", "dmp.extensions", FT_NONE, BASE_NONE,
4220         NULL, 0x0, NULL, HFILL}},
4221     { &hf_extension,
4222       { "Extension", "dmp.extension", FT_NONE, BASE_NONE,
4223         NULL, 0x0, NULL, HFILL } },
4224     { &hf_extension_header,
4225       { "Extension Header", "dmp.extension_header", FT_NONE, BASE_NONE,
4226         NULL, 0x0, NULL, HFILL}},
4227     { &hf_extension_more,
4228       { "More Extensions", "dmp.extension_more", FT_BOOLEAN, 8,
4229         TFS (&tfs_present_absent), 0x80, NULL, HFILL } },
4230     { &hf_extension_length,
4231       { "Extension Length (minus one)", "dmp.extension_length", FT_UINT8, BASE_DEC,
4232         NULL, 0x7F, "Extension Length minus one", HFILL } },
4233     { &hf_extension_data,
4234       { "Extension Data", "dmp.extension_data", FT_BYTES, BASE_NONE,
4235         NULL, 0x0, NULL, HFILL } },
4236
4237     /* Submission time */
4238     { &hf_envelope_subm_time,
4239       { "Submission Time", "dmp.subm_time", FT_UINT16, BASE_HEX,
4240         NULL, 0x0, NULL, HFILL } },
4241     { &hf_envelope_time_diff_present,
4242       { "Time Diff", "dmp.time_diff_present", FT_BOOLEAN, 16,
4243         TFS (&tfs_present_absent), 0x8000, "Time Diff Present", HFILL } },
4244     { &hf_envelope_subm_time_value,
4245       { "Submission Time Value", "dmp.subm_time_value", FT_UINT16,
4246         BASE_HEX, NULL, 0x7FFF, NULL, HFILL } },
4247     { &hf_envelope_time_diff,
4248       { "Time Difference", "dmp.time_diff", FT_UINT8, BASE_HEX,
4249         NULL, 0xFF, NULL, HFILL } },
4250     { &hf_envelope_time_diff_value,
4251       { "Time Difference Value", "dmp.time_diff_value", FT_UINT8,
4252         BASE_HEX, NULL, 0xFF, NULL, HFILL } },
4253
4254     /* Envelope flags */
4255     { &hf_envelope_flags,
4256       { "Flags", "dmp.envelope_flags", FT_UINT8, BASE_DEC,
4257         NULL, 0x0, "Envelope Flags", HFILL}},
4258     { &hf_envelope_content_id_discarded,
4259       { "Content Identifier discarded", "dmp.cont_id_discarded",
4260         FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x80,
4261         NULL, HFILL } },
4262     { &hf_envelope_recip_reassign_prohib,
4263       { "Recipient reassign prohibited","dmp.recip_reassign_prohib",
4264         FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x40,
4265         NULL, HFILL }},
4266     { &hf_envelope_dl_expansion_prohib,
4267       { "DL expansion prohibited", "dmp.dl_expansion_prohib",
4268         FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, NULL,
4269         HFILL } },
4270
4271     /* Recipient Count */
4272     { &hf_envelope_recipients,
4273       { "Recipient Count", "dmp.rec_count", FT_UINT8, BASE_DEC,
4274         NULL, 0x1F, NULL, HFILL}},
4275     { &hf_envelope_ext_recipients,
4276       { "Extended Recipient Count", "dmp.ext_rec_count", FT_UINT16,
4277         BASE_DEC, NULL, 0x7FFF, NULL, HFILL}},
4278
4279     /*
4280     ** Address
4281     */
4282     { &hf_addr_recipient,
4283       { "Recipient Number", "dmp.recipient", FT_NONE, BASE_NONE,
4284         NULL, 0x0, "Recipient", HFILL } },
4285     { &hf_addr_originator,
4286       { "Originator", "dmp.originator", FT_NONE, BASE_NONE,
4287         NULL, 0x0, NULL, HFILL } },
4288     { &hf_addr_reporting_name,
4289       { "Reporting Name Number", "dmp.reporting_name", FT_NONE,
4290         BASE_NONE, NULL, 0x0, "Reporting Name", HFILL } },
4291     { &hf_addr_dl_expanded,
4292       { "DL Expanded", "dmp.dl_expanded", FT_BOOLEAN, BASE_NONE,
4293         NULL, 0x0, "Message has been DL expanded", HFILL } },
4294     { &hf_addr_int_rec,
4295       { "Intended Recipient", "dmp.int_rec", FT_BOOLEAN, BASE_NONE,
4296         NULL, 0x0, "Message has an intended recipient", HFILL } },
4297
4298     /*
4299     ** Address Direct
4300     */
4301     { &hf_addr_dir_addr_ext,
4302       { "Address Extended", "dmp.addr_ext", FT_BOOLEAN, 8,
4303         NULL, 0x80, NULL, HFILL } },
4304     { &hf_addr_dir_rec_no,
4305       { "Recipient Number Offset", "dmp.rec_no_offset", FT_UINT8,
4306         BASE_DEC, NULL, 0xF0, NULL, HFILL } },
4307     { &hf_addr_dir_rec_no_generated,
4308       { "Recipient Number", "dmp.rec_no", FT_UINT32,
4309         BASE_DEC, NULL, 0x0, "Recipient Number Offset", HFILL } },
4310     { &hf_addr_dir_rec_no1,
4311       { "Recipient Number (bits 3-0)", "dmp.rec_no_offset1", FT_UINT8,
4312         BASE_DEC, NULL, 0xF0, "Recipient Number (bits 3-0) Offset", HFILL } },
4313     { &hf_addr_dir_rec_no2,
4314       { "Recipient Number (bits 9-4)", "dmp.rec_no_offset2", FT_UINT8,
4315         BASE_DEC, NULL, 0x3F, "Recipient Number (bits 9-4) Offset", HFILL } },
4316     { &hf_addr_dir_rec_no3,
4317       { "Recipient Number (bits 14-10)", "dmp.rec_no_offset3", FT_UINT8,
4318         BASE_DEC, NULL, 0x1F, "Recipient Number (bits 14-10) Offset",HFILL } },
4319     { &hf_addr_dir_rep_req1,
4320       { "Report Request", "dmp.rep_rec", FT_UINT8, BASE_HEX,
4321         VALS (report_vals_ext), 0x0C, NULL, HFILL } },
4322     { &hf_addr_dir_rep_req2,
4323       { "Report Request", "dmp.rep_rec", FT_UINT8, BASE_HEX,
4324         VALS (report_vals_ext), 0xC0, NULL, HFILL } },
4325     { &hf_addr_dir_rep_req3,
4326       { "Report Request", "dmp.rep_rec", FT_UINT8, BASE_HEX,
4327         VALS (report_vals), 0xC0, NULL, HFILL } },
4328     { &hf_addr_dir_not_req1,
4329       { "Notification Request", "dmp.not_req", FT_UINT8, BASE_HEX,
4330         VALS (notif_vals_ext), 0x03, NULL, HFILL } },
4331     { &hf_addr_dir_not_req2,
4332       { "Notification Request", "dmp.not_req", FT_UINT8, BASE_HEX,
4333         VALS (notif_vals_ext), 0xC0, NULL, HFILL } },
4334     { &hf_addr_dir_not_req3,
4335       { "Notification Request", "dmp.not_req", FT_UINT8, BASE_HEX,
4336         VALS (notif_vals), 0xC0, NULL, HFILL } },
4337     { &hf_addr_dir_action,
4338       { "Action", "dmp.action", FT_BOOLEAN, 8,
4339         TFS (&tfs_yes_no), 0x80, NULL, HFILL } },
4340     { &hf_addr_dir_address,
4341       { "Direct Address", "dmp.direct_addr", FT_UINT8,
4342         BASE_DEC, NULL, 0x7F, NULL, HFILL } },
4343     { &hf_addr_dir_address_generated,
4344       { "Direct Address", "dmp.direct_addr", FT_UINT32,
4345         BASE_DEC, NULL, 0x0, NULL, HFILL } },
4346     { &hf_addr_dir_address1,
4347       { "Direct Address (bits 6-0)", "dmp.direct_addr1", FT_UINT8,
4348         BASE_DEC, NULL, 0x7F, NULL, HFILL } },
4349     { &hf_addr_dir_address2,
4350       { "Direct Address (bits 12-7)", "dmp.direct_addr2", FT_UINT8,
4351         BASE_DEC, NULL, 0x3F, NULL, HFILL } },
4352     { &hf_addr_dir_address3,
4353       { "Direct Address (bits 18-13)", "dmp.direct_addr3", FT_UINT8,
4354         BASE_DEC, NULL, 0x3F, NULL, HFILL } },
4355
4356     /*
4357     ** Address Extended
4358     */
4359     { &hf_addr_ext_form,
4360       { "Address Form", "dmp.addr_form", FT_UINT8, BASE_DEC,
4361         VALS (&addr_form), 0xE0, NULL, HFILL } },
4362     { &hf_addr_ext_form_orig_v1,
4363       { "Address Form", "dmp.addr_form", FT_UINT8, BASE_DEC,
4364         VALS (&addr_form_orig_v1), 0xE0, NULL, HFILL } },
4365     { &hf_addr_ext_form_orig,
4366       { "Address Form", "dmp.addr_form", FT_UINT8, BASE_DEC,
4367         VALS (&addr_form_orig), 0xE0, NULL, HFILL } },
4368     { &hf_addr_ext_action,
4369       { "Action", "dmp.action", FT_BOOLEAN, 8,
4370         TFS (&tfs_yes_no), 0x10, NULL, HFILL } },
4371     { &hf_addr_ext_rep_req,
4372       { "Report Request", "dmp.rep_rec", FT_UINT8, BASE_HEX,
4373         VALS (report_vals), 0x0C, NULL, HFILL } },
4374     { &hf_addr_ext_not_req,
4375       { "Notification Request", "dmp.not_req", FT_UINT8, BASE_HEX,
4376         VALS (notif_vals), 0x03, NULL, HFILL } },
4377     { &hf_addr_ext_rec_ext,
4378       { "Recipient Number Extended", "dmp.rec_no_ext", FT_BOOLEAN, 8,
4379         NULL, 0x80, NULL, HFILL } },
4380     { &hf_addr_ext_rec_no,
4381       { "Recipient Number Offset", "dmp.rec_no_offset", FT_UINT8,
4382         BASE_DEC, NULL, 0x7F, NULL, HFILL } },
4383     { &hf_addr_ext_rec_no_generated,
4384       { "Recipient Number", "dmp.rec_no", FT_UINT32,
4385         BASE_DEC, NULL, 0x0, NULL, HFILL } },
4386     { &hf_addr_ext_rec_no1,
4387       { "Recipient Number (bits 6-0)", "dmp.rec_no_offset1", FT_UINT8,
4388         BASE_DEC, NULL, 0x7F, "Recipient Number (bits 6-0) Offset", HFILL } },
4389     { &hf_addr_ext_rec_no2,
4390       { "Recipient Number (bits 14-7)", "dmp.rec_no_offset2", FT_UINT8,
4391         BASE_DEC, NULL, 0xFF, "Recipient Number (bits 14-7) Offset", HFILL } },
4392     { &hf_addr_ext_address,
4393       { "Extended Address", "dmp.addr_form", FT_NONE, BASE_NONE,
4394         NULL, 0x0, NULL, HFILL } },
4395     { &hf_addr_ext_type,
4396       { "Address Type", "dmp.addr_type", FT_UINT8, BASE_DEC,
4397         VALS (&ext_addr_type), 0xE0, NULL, HFILL } },
4398     { &hf_addr_ext_type_ext,
4399       { "Address Type Extended", "dmp.addr_type_ext", FT_UINT8,
4400         BASE_DEC, VALS (&ext_addr_type_ext), 0xE0, NULL,
4401         HFILL } },
4402     { &hf_addr_ext_length,
4403       { "Address Length", "dmp.addr_length", FT_UINT8,
4404         BASE_DEC, NULL, 0x1F, NULL, HFILL } },
4405     { &hf_addr_ext_length_generated,
4406       { "Address Length", "dmp.addr_length", FT_UINT32,
4407         BASE_DEC, NULL, 0x0, NULL, HFILL } },
4408     { &hf_addr_ext_length1,
4409       { "Address Length (bits 4-0)", "dmp.addr_length1", FT_UINT8,
4410         BASE_DEC, NULL, 0x1F, NULL, HFILL } },
4411     { &hf_addr_ext_length2,
4412       { "Address Length (bits 9-5)", "dmp.addr_length2", FT_UINT8,
4413         BASE_DEC, NULL, 0x1F, NULL, HFILL } },
4414     { &hf_addr_ext_asn1_ber,
4415       { "ASN.1 BER-encoded OR-name", "dmp.or_name", FT_NONE,
4416         BASE_NONE, NULL, 0x0, NULL, HFILL } },
4417     { &hf_addr_ext_asn1_per,
4418       { "ASN.1 PER-encoded OR-name", "dmp.asn1_per", FT_BYTES,
4419         BASE_NONE, NULL, 0x0, NULL, HFILL } },
4420     { &hf_addr_ext_unknown,
4421       { "Unknown encoded address", "dmp.addr_unknown", FT_BYTES,
4422         BASE_NONE, NULL, 0x0, NULL, HFILL } },
4423
4424     /*
4425     ** Message content
4426     */
4427     { &hf_message_content,
4428       { "Message Content", "dmp.message", FT_NONE, BASE_NONE,
4429         NULL, 0x0, NULL, HFILL } },
4430     { &hf_report_content,
4431       { "Report Content", "dmp.report", FT_NONE, BASE_NONE,
4432         NULL, 0x0, NULL, HFILL } },
4433     { &hf_notif_content,
4434       { "Notification Content", "dmp.notification", FT_NONE, BASE_NONE,
4435         NULL, 0x0, NULL, HFILL } },
4436
4437     { &hf_message_st_type,
4438       { "Message type", "dmp.msg_type", FT_UINT8, BASE_DEC,
4439         VALS (message_type_vals), 0xC0, NULL, HFILL } },
4440     { &hf_message_precedence,
4441       { "Precedence", "dmp.precedence", FT_UINT8, BASE_DEC,
4442         VALS (precedence), 0x1C, NULL, HFILL } },
4443     { &hf_message_importance,
4444       { "Importance", "dmp.importance", FT_UINT8, BASE_DEC,
4445         VALS (importance), 0x1C, NULL, HFILL } },
4446     { &hf_message_body_format,
4447       { "Body format", "dmp.body_format", FT_UINT8, BASE_DEC,
4448         VALS (body_format_vals), 0x03, NULL, HFILL } },
4449
4450     /* Security Values */
4451     { &hf_message_sec_label,
4452       { "Security Label", "dmp.sec_label", FT_STRING, BASE_NONE,
4453         NULL, 0x0, NULL, HFILL } },
4454     { &hf_message_sec_class_val,
4455       { "Security Classification", "dmp.sec_class", FT_UINT8,
4456         BASE_DEC, NULL, 0xE0, NULL, HFILL}},
4457     { &hf_message_sec_pol,
4458       { "Security Policy", "dmp.sec_pol", FT_UINT8, BASE_DEC,
4459         VALS (sec_pol), 0x1C, NULL, HFILL } },
4460     { &hf_message_heading_flags,
4461       { "Heading Flags", "dmp.heading_flags", FT_NONE, BASE_NONE,
4462         NULL, 0x0, NULL, HFILL } },
4463     { &hf_message_auth_users,
4464       { "Authorizing users discarded", "dmp.auth_discarded",
4465         FT_BOOLEAN, 8, TFS (&tfs_yes_no), 0x02,
4466         NULL, HFILL }},
4467     { &hf_message_subject_disc,
4468       { "Subject discarded", "dmp.subject_discarded", FT_BOOLEAN, 8,
4469         TFS (&tfs_yes_no), 0x01, NULL, HFILL } },
4470
4471     /* National Policy Identifier */
4472     { &hf_message_national_policy_id,
4473       { "National Policy Identifier", "dmp.nat_pol_id", FT_UINT8,
4474         BASE_DEC, VALS(nat_pol_id), 0x0, NULL,
4475         HFILL } },
4476
4477     /* Mission Policy Identifier */
4478     { &hf_message_mission_policy_id,
4479       { "Mission Policy Identifier", "dmp.mission_pol_id", FT_UINT8,
4480         BASE_DEC, NULL, 0x0, NULL,
4481         HFILL } },
4482
4483     /* Security Categories */
4484     { &hf_message_sec_cat_nat,
4485       { "Security Categories", "dmp.sec_cat", FT_UINT8, BASE_HEX,
4486         NULL, 0x0, NULL, HFILL } },
4487     { &hf_message_sec_cat_val,
4488       { "Security Categories", "dmp.sec_cat", FT_UINT8, BASE_HEX,
4489         NULL, 0x0, NULL, HFILL } },
4490     { &hf_message_sec_cat_cl,
4491       { "Clear", "dmp.sec_cat.cl", FT_BOOLEAN, 8,
4492         TFS (&tfs_set_notset), 0x80, NULL, HFILL } },
4493     { &hf_message_sec_cat_cs,
4494       { "Crypto Security", "dmp.sec_cat.cs", FT_BOOLEAN, 8,
4495         TFS (&tfs_set_notset), 0x40, NULL, HFILL } },
4496     { &hf_message_sec_cat_ex,
4497       { "Exclusive", "dmp.sec_cat.ex", FT_BOOLEAN, 8,
4498         TFS (&tfs_set_notset), 0x20, NULL, HFILL } },
4499     { &hf_message_sec_cat_ne,
4500       { "National Eyes Only", "dmp.sec_cat.ne", FT_BOOLEAN, 8,
4501         TFS (&tfs_set_notset), 0x10, NULL, HFILL } },
4502     { &hf_message_sec_cat_permissive,
4503       { "Releasable to", "dmp.sec_cat.permissive", FT_UINT8, BASE_HEX,
4504         VALS (nat_pol_id), 0xFC, NULL, HFILL } },
4505     { &hf_message_sec_cat_country_code,
4506       { "Country Code", "dmp.sec_cat.country", FT_UINT8, BASE_DEC,
4507         NULL, 0x00, NULL, HFILL } },
4508     { &hf_message_sec_cat_restrictive,
4509       { "Restrictive", "dmp.sec_cat.restrictive", FT_UINT8, BASE_HEX,
4510         NULL, 0xFC, NULL, HFILL } },
4511     { &hf_message_sec_cat_extended,
4512       { "Extended", "dmp.sec_cat.extended", FT_UINT8, BASE_HEX,
4513         VALS (ext_sec_cat), 0x03, "Extended Security Category", HFILL } },
4514     { &hf_message_sec_cat_bit0,
4515       { "Bit 0", "dmp.sec_cat.bit0", FT_BOOLEAN, 8,
4516         TFS (&tfs_set_notset), 0x01, NULL, HFILL } },
4517     { &hf_message_sec_cat_bit1,
4518       { "Bit 1", "dmp.sec_cat.bit1", FT_BOOLEAN, 8,
4519         TFS (&tfs_set_notset), 0x02, NULL, HFILL } },
4520     { &hf_message_sec_cat_bit2,
4521       { "Bit 2", "dmp.sec_cat.bit2", FT_BOOLEAN, 8,
4522         TFS (&tfs_set_notset), 0x04, NULL, HFILL } },
4523     { &hf_message_sec_cat_bit3,
4524       { "Bit 3", "dmp.sec_cat.bit3", FT_BOOLEAN, 8,
4525         TFS (&tfs_set_notset), 0x08, NULL, HFILL } },
4526     { &hf_message_sec_cat_bit4,
4527       { "Bit 4", "dmp.sec_cat.bit4", FT_BOOLEAN, 8,
4528         TFS (&tfs_set_notset), 0x10, NULL, HFILL } },
4529     { &hf_message_sec_cat_bit5,
4530       { "Bit 5", "dmp.sec_cat.bit5", FT_BOOLEAN, 8,
4531         TFS (&tfs_set_notset), 0x20, NULL, HFILL } },
4532     { &hf_message_sec_cat_bit6,
4533       { "Bit 6", "dmp.sec_cat.bit6", FT_BOOLEAN, 8,
4534         TFS (&tfs_set_notset), 0x40, NULL, HFILL } },
4535     { &hf_message_sec_cat_bit7,
4536       { "Bit 7", "dmp.sec_cat.bit7", FT_BOOLEAN, 8,
4537         TFS (&tfs_set_notset), 0x80, NULL, HFILL } },
4538
4539     /* Expiry Time */
4540     { &hf_message_exp_time,
4541       { "Expiry Time", "dmp.expiry_time", FT_UINT8, BASE_HEX,
4542         NULL, 0x0, NULL, HFILL } },
4543     { &hf_message_exp_time_val,
4544       { "Expiry Time Value", "dmp.expiry_time_val", FT_UINT8, BASE_HEX,
4545         NULL, 0xFF, NULL, HFILL } },
4546
4547     /* DTG */
4548     { &hf_message_dtg,
4549       { "DTG", "dmp.dtg", FT_UINT8, BASE_HEX,
4550         NULL, 0xFF, NULL, HFILL } },
4551     { &hf_message_dtg_sign,
4552       { "DTG in the", "dmp.dtg.sign", FT_BOOLEAN, 8, TFS (&dtg_sign),
4553         0x80, "Sign", HFILL } },
4554     { &hf_message_dtg_val,
4555       { "DTG Value", "dmp.dtg.val", FT_UINT8, BASE_HEX, NULL,
4556         0x7F, NULL, HFILL } },
4557
4558     /* SIC */
4559     { &hf_message_sic,
4560       { "SIC", "dmp.sic", FT_STRING, BASE_NONE,
4561         NULL, 0x0, NULL, HFILL } },
4562     { &hf_message_sic_key,
4563       { "SICs", "dmp.sic_key", FT_NONE, BASE_NONE,
4564         NULL, 0x0, "SIC Content", HFILL } },
4565     { &hf_message_sic_key_values,
4566       { "Content Byte", "dmp.sic_key.values", FT_UINT8, BASE_HEX,
4567         NULL, 0x0, "SIC Content Byte", HFILL } },
4568     { &hf_message_sic_key_type,
4569       { "Type", "dmp.sic_key.type", FT_UINT8, BASE_HEX,
4570         VALS (sic_key_type), 0xF0, "SIC Content Type", HFILL } },
4571     { &hf_message_sic_key_chars,
4572       { "Valid Characters", "dmp.sic_key.chars", FT_BOOLEAN, 8,
4573         TFS (&sic_key_chars), 0x08, "SIC Valid Characters", HFILL } },
4574     { &hf_message_sic_key_num,
4575       { "Number of SICs", "dmp.sic_key.num", FT_UINT8, BASE_HEX,
4576         VALS (sic_key_num), 0x07, NULL, HFILL } },
4577     { &hf_message_sic_bitmap,
4578       { "Length Bitmap (0 = 3 bytes, 1 = 4-8 bytes)", "dmp.sic_bitmap",
4579         FT_UINT8, BASE_HEX, NULL, 0xFF, "SIC Length Bitmap", HFILL } },
4580     { &hf_message_sic_bits,
4581       { "Bit 7-4", "dmp.sic_bits", FT_UINT8, BASE_HEX,
4582         VALS(sic_bit_vals), 0xF0, "SIC Bit 7-4, Characters [A-Z0-9] only",
4583         HFILL } },
4584     { &hf_message_sic_bits_any,
4585       { "Bit 7-4", "dmp.sic_bits_any", FT_UINT8, BASE_HEX,
4586         VALS(sic_bit_any_vals), 0xF0, "SIC Bit 7-4, Any valid characters",
4587         HFILL } },
4588
4589     /* Subject Message Id */
4590     { &hf_message_subj_id,
4591       { "Subject Message Identifier", "dmp.subj_id", FT_UINT16,
4592         BASE_DEC, NULL, 0x0, NULL, HFILL } },
4593
4594     /* Subject MTS Identifier */
4595     { &hf_message_subj_mts_id,
4596       { "Subject MTS Identifier", "dmp.subj_mts_id", FT_STRING, BASE_NONE,
4597         NULL, 0x0, NULL, HFILL } },
4598
4599     /* Subject IPM Identifier */
4600     { &hf_message_subj_ipm_id,
4601       { "Subject IPM Identifier", "dmp.subj_ipm_id", FT_STRING, BASE_NONE,
4602         NULL, 0x0, NULL, HFILL } },
4603
4604     /*
4605     ** Message body
4606     */
4607     { &hf_message_body,
4608       { "Message Body", "dmp.body", FT_NONE, BASE_NONE, NULL,
4609         0x0, NULL, HFILL}},
4610
4611     /* Body Id */
4612     { &hf_message_eit,
4613       { "EIT", "dmp.body.eit", FT_UINT8, BASE_DEC,
4614         VALS(eit_vals), 0xE0, "Encoded Information Type", HFILL } },
4615     { &hf_message_compr,
4616       { "Compression", "dmp.body.compression", FT_UINT8, BASE_DEC,
4617         VALS(compression_vals), 0x18, NULL, HFILL } },
4618
4619     /* Subject */
4620     { &hf_message_subject,
4621       { "Subject", "dmp.subject", FT_STRINGZ, BASE_NONE,
4622         NULL, 0x0, NULL, HFILL } },
4623
4624     /* Message Body */
4625     { &hf_message_body_data,
4626       { "User data", "dmp.body.data", FT_NONE, BASE_NONE,
4627         NULL, 0x0, NULL, HFILL } },
4628     { &hf_message_body_plain,
4629       { "Message Body", "dmp.body.plain", FT_STRING, BASE_NONE,
4630         NULL, 0x0, NULL, HFILL } },
4631     { &hf_message_bodyid_uint8,
4632       { "Structured Id", "dmp.body.id", FT_UINT8, BASE_DEC,
4633         NULL, 0x0, "Structured Body Id (1 byte)", HFILL } },
4634     { &hf_message_bodyid_uint16,
4635       { "Structured Id", "dmp.body.id", FT_UINT16, BASE_DEC,
4636         NULL, 0x0, "Structured Body Id (2 bytes)", HFILL } },
4637     { &hf_message_bodyid_uint32,
4638       { "Structured Id", "dmp.body.id", FT_UINT32, BASE_DEC,
4639         NULL, 0x0, "Structured Body Id (4 bytes)", HFILL } },
4640     { &hf_message_bodyid_uint64,
4641       { "Structured Id", "dmp.body.id", FT_UINT64, BASE_DEC,
4642         NULL, 0x0, "Structured Body Id (8 bytes)", HFILL } },
4643     { &hf_message_bodyid_string,
4644       { "Structured Id", "dmp.body.id", FT_STRING, BASE_NONE,
4645         NULL, 0x0, "Structured Body Id (fixed text string)", HFILL } },
4646     { &hf_message_bodyid_zstring,
4647       { "Structured Id", "dmp.body.id", FT_STRINGZ, BASE_NONE,
4648         NULL, 0x0, "Structured Body Id (zero terminated text string)",
4649         HFILL } },
4650     { &hf_message_body_structured,
4651       { "Structured Body", "dmp.body.structured", FT_BYTES, BASE_NONE,
4652         NULL, 0x0, NULL, HFILL } },
4653     { &hf_message_body_uncompr,
4654       { "Uncompressed User data", "dmp.body.uncompressed", FT_NONE,
4655         BASE_NONE, NULL, 0x0, NULL, HFILL } },
4656     { &hf_message_body_uncompressed,
4657       { "Uncompressed Message Body", "dmp.body.uncompressed",
4658         FT_STRING, BASE_NONE, NULL, 0x0, NULL,
4659         HFILL } },
4660
4661     /*
4662     ** Report
4663     */
4664     { &hf_delivery_report,
4665       { "Delivery Report", "dmp.dr", FT_NONE, BASE_NONE, NULL,
4666         0x0, NULL, HFILL}},
4667     { &hf_non_delivery_report,
4668       { "Non-Delivery Report", "dmp.ndr", FT_NONE, BASE_NONE, NULL,
4669         0x0, NULL, HFILL}},
4670
4671     { &hf_report_type,
4672       { "Report Type", "dmp.report_type", FT_BOOLEAN, 8,
4673         TFS (&report_type), 0x80, NULL, HFILL } },
4674     { &hf_report_info_present_dr,
4675       { "Info Present", "dmp.info_present", FT_BOOLEAN, 8,
4676         TFS (&tfs_present_absent), 0x40, NULL, HFILL } },
4677     { &hf_report_addr_enc_dr,
4678       { "Address Encoding", "dmp.addr_encoding", FT_BOOLEAN, 8,
4679         TFS (&addr_enc), 0x20, NULL, HFILL } },
4680     { &hf_report_del_time,
4681       { "Delivery Time", "dmp.delivery_time", FT_UINT8, BASE_HEX,
4682         NULL, 0x0, NULL, HFILL } },
4683     { &hf_report_del_time_val,
4684       { "Delivery Time Value", "dmp.delivery_time_val", FT_UINT8,
4685         BASE_HEX, NULL, 0xFF, NULL, HFILL } },
4686     { &hf_report_addr_enc_ndr,
4687       { "Address Encoding", "dmp.addr_encoding", FT_BOOLEAN, 8,
4688         TFS (&addr_enc), 0x40, NULL, HFILL } },
4689     { &hf_report_reason,
4690       { "Reason (P1)", "dmp.report_reason", FT_UINT8, BASE_DEC,
4691         VALS (p1_NonDeliveryReasonCode_vals), 0x3F,
4692         "Reason", HFILL } },
4693     { &hf_report_info_present_ndr,
4694       { "Info Present", "dmp.info_present", FT_BOOLEAN, 8,
4695         TFS (&tfs_present_absent), 0x80, NULL, HFILL } },
4696     { &hf_report_diagn,
4697       { "Diagnostic (P1)", "dmp.report_diagnostic", FT_UINT8, BASE_DEC,
4698         VALS (p1_NonDeliveryDiagnosticCode_vals), 0x7F,
4699         "Diagnostic", HFILL } },
4700     { &hf_report_suppl_info_len,
4701       { "Supplementary Information", "dmp.suppl_info_len", FT_UINT8,
4702         BASE_DEC, NULL, 0x0, "Supplementary Information Length", HFILL } },
4703     { &hf_report_suppl_info,
4704       { "Supplementary Information", "dmp.suppl_info", FT_STRINGZ,
4705         BASE_NONE, NULL, 0x0, NULL, HFILL } },
4706
4707     /*
4708     ** Notification
4709     */
4710     { &hf_receipt_notif,
4711       { "Receipt Notification (RN)", "dmp.rn", FT_NONE, BASE_NONE,
4712         NULL, 0x0, NULL, HFILL} },
4713     { &hf_non_receipt_notif,
4714       { "Non-Receipt Notification (NRN)", "dmp.nrn", FT_NONE, BASE_NONE,
4715         NULL, 0x0, NULL, HFILL} },
4716     { &hf_other_notif,
4717       { "Other Notification (ON)", "dmp.on", FT_NONE, BASE_NONE,
4718         NULL, 0x0, NULL, HFILL} },
4719
4720     { &hf_notif_type,
4721       { "Notification Type", "dmp.notif_type", FT_UINT8, BASE_DEC,
4722         VALS (notif_type), 0x03, NULL, HFILL } },
4723     { &hf_notif_rec_time,
4724       { "Receipt Time", "dmp.receipt_time", FT_UINT8, BASE_HEX,
4725         NULL, 0x0, NULL, HFILL } },
4726     { &hf_notif_rec_time_val,
4727       { "Receipt Time Value", "dmp.receipt_time_val", FT_UINT8,
4728         BASE_HEX, NULL, 0xFF, NULL, HFILL } },
4729     { &hf_notif_suppl_info_len,
4730       { "Supplementary Information", "dmp.suppl_info_len",
4731         FT_UINT8, BASE_DEC, NULL, 0x0, "Supplementary Information Length",
4732         HFILL } },
4733     { &hf_notif_suppl_info,
4734       { "Supplementary Information", "dmp.suppl_info",
4735         FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL,
4736         HFILL } },
4737     { &hf_notif_non_rec_reason,
4738       { "Non-Receipt Reason", "dmp.notif_non_rec_reason",
4739         FT_UINT8, BASE_DEC, VALS (p22_NonReceiptReasonField_vals), 0x0,
4740         NULL, HFILL } },
4741     { &hf_notif_discard_reason,
4742       { "Discard Reason", "dmp.notif_discard_reason", FT_UINT8,
4743         BASE_DEC, VALS (p22_DiscardReasonField_vals), 0x0,
4744         NULL, HFILL } },
4745     { &hf_notif_on_type,
4746       { "ON Type", "dmp.notif_on_type", FT_UINT8, BASE_DEC,
4747         VALS (on_type), 0x0, NULL, HFILL } },
4748     { &hf_notif_acp127,
4749       { "ACP127 Recipient", "dmp.acp127recip_len", FT_UINT8,
4750         BASE_DEC, NULL, 0x0, "ACP 127 Recipient Length", HFILL } },
4751     { &hf_notif_acp127recip,
4752       { "ACP127 Recipient", "dmp.acp127recip", FT_STRINGZ,
4753         BASE_NONE, NULL, 0x0, "ACP 127 Recipient", HFILL } },
4754
4755     /*
4756     ** Acknowledgement
4757     */
4758     { &hf_ack,
4759       { "Acknowledgement", "dmp.ack", FT_NONE, BASE_NONE,
4760         NULL, 0x0, NULL, HFILL } },
4761     { &hf_ack_reason,
4762       { "Ack Reason", "dmp.ack_reason", FT_UINT8, BASE_DEC,
4763         VALS (&ack_reason), 0x0, "Reason", HFILL } },
4764     { &hf_ack_diagnostic,
4765       { "Ack Diagnostic", "dmp.ack_diagnostic", FT_UINT8, BASE_DEC,
4766         NULL, 0x0, "Diagnostic", HFILL } },
4767     { &hf_ack_recips,
4768       { "Recipient List", "dmp.ack_rec_list", FT_NONE, BASE_NONE,
4769         NULL, 0x0, NULL, HFILL } },
4770
4771     /*
4772     ** Checksum
4773     */
4774     { &hf_checksum,
4775       { "Checksum", "dmp.checksum", FT_UINT16, BASE_HEX,
4776         NULL, 0x0, NULL, HFILL } },
4777     { &hf_checksum_good,
4778       { "Good", "dmp.checksum_good", FT_BOOLEAN, BASE_NONE,
4779         NULL, 0x0, "True: checksum matches packet content; False: doesn't match content or not checked", HFILL } },
4780     { &hf_checksum_bad,
4781       { "Bad", "dmp.checksum_bad", FT_BOOLEAN, BASE_NONE,
4782         NULL, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL } },
4783
4784     /*
4785     ** Ack matching / Resend
4786     */
4787     { &hf_analysis_ack_time,
4788       { "Acknowledgement Time", "dmp.analysis.ack_time", FT_RELATIVE_TIME, BASE_NONE,
4789         NULL, 0x0, "The time between the Message and the Acknowledge", HFILL } },
4790     { &hf_analysis_rep_time,
4791       { "Report Reply Time", "dmp.analysis.report_time", FT_RELATIVE_TIME, BASE_NONE,
4792         NULL, 0x0, "The time between the Message and the Report", HFILL } },
4793     { &hf_analysis_not_time,
4794       { "Notification Reply Time", "dmp.analysis.notif_time", FT_RELATIVE_TIME, BASE_NONE,
4795         NULL, 0x0, "The time between the Message and the Notification", HFILL } },
4796     { &hf_analysis_total_time,
4797       { "Total Time", "dmp.analysis.total_time", FT_RELATIVE_TIME, BASE_NONE,
4798         NULL, 0x0, "The time between the first Message and the Acknowledge", HFILL } },
4799     { &hf_analysis_retrans_time,
4800       { "Retransmission Time", "dmp.analysis.retrans_time", FT_RELATIVE_TIME, BASE_NONE,
4801         NULL, 0x0, "The time between the last Message and this Message", HFILL } },
4802     { &hf_analysis_total_retrans_time,
4803       { "Total Retransmission Time", "dmp.analysis.total_retrans_time", FT_RELATIVE_TIME, BASE_NONE,
4804         NULL, 0x0, "The time between the first Message and this Message", HFILL } },
4805     { &hf_analysis_msg_num,
4806       { "Message in", "dmp.analysis.msg_in", FT_FRAMENUM, BASE_NONE,
4807         NULL, 0x0, "This packet has a Message in this frame", HFILL } },
4808     { &hf_analysis_ack_num,
4809       { "Acknowledgement in", "dmp.analysis.ack_in", FT_FRAMENUM, BASE_NONE,
4810         NULL, 0x0, "This packet has an Acknowledgement in this frame", HFILL } },
4811     { &hf_analysis_rep_num,
4812       { "Report in", "dmp.analysis.report_in", FT_FRAMENUM, BASE_NONE,
4813         NULL, 0x0, "This packet has a Report in this frame", HFILL } },
4814     { &hf_analysis_not_num,
4815       { "Notification in", "dmp.analysis.notif_in", FT_FRAMENUM, BASE_NONE,
4816         NULL, 0x0, "This packet has a Notification in this frame", HFILL } },
4817     { &hf_analysis_msg_missing,
4818       { "Message missing", "dmp.analysis.msg_missing", FT_NONE, BASE_NONE,
4819         NULL, 0x0, "The Message for this packet is missing", HFILL } },
4820     { &hf_analysis_ack_missing,
4821       { "Acknowledgement missing", "dmp.analysis.ack_missing", FT_NONE, BASE_NONE,
4822         NULL, 0x0, "The acknowledgement for this packet is missing", HFILL } },
4823     { &hf_analysis_retrans_no,
4824       { "Retransmission #", "dmp.analysis.retrans_no", FT_UINT32, BASE_DEC,
4825         NULL, 0x0, "Retransmission count", HFILL } },
4826     { &hf_analysis_ack_dup_no,
4827       { "Duplicate ACK #", "dmp.analysis.dup_ack_no", FT_UINT32, BASE_DEC,
4828         NULL, 0x0, "Duplicate Acknowledgement count", HFILL } },
4829     { &hf_analysis_msg_resend_from,
4830       { "Retransmission of Message sent in", "dmp.analysis.msg_first_sent_in",
4831         FT_FRAMENUM, BASE_NONE,
4832         NULL, 0x0, "This Message was first sent in this frame", HFILL } },
4833     { &hf_analysis_rep_resend_from,
4834       { "Retransmission of Report sent in", "dmp.analysis.report_first_sent_in",
4835         FT_FRAMENUM, BASE_NONE,
4836         NULL, 0x0, "This Report was first sent in this frame", HFILL } },
4837     { &hf_analysis_not_resend_from,
4838       { "Retransmission of Notification sent in", "dmp.analysis.notif_first_sent_in",
4839         FT_FRAMENUM, BASE_NONE,
4840         NULL, 0x0, "This Notification was first sent in this frame", HFILL } },
4841     { &hf_analysis_ack_resend_from,
4842       { "Retransmission of Acknowledgement sent in", "dmp.analysis.ack_first_sent_in",
4843         FT_FRAMENUM, BASE_NONE,
4844         NULL, 0x0, "This Acknowledgement was first sent in this frame", HFILL } },
4845
4846     /*
4847     ** Reserved values
4848     */
4849     { &hf_reserved_0x01,
4850       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4851         NULL, 0x01, NULL, HFILL } },
4852     { &hf_reserved_0x02,
4853       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4854         NULL, 0x02, NULL, HFILL } },
4855     { &hf_reserved_0x04,
4856       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4857         NULL, 0x04, NULL, HFILL } },
4858     { &hf_reserved_0x07,
4859       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4860         NULL, 0x07, NULL, HFILL } },
4861     { &hf_reserved_0x08,
4862       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4863         NULL, 0x08, NULL, HFILL } },
4864     { &hf_reserved_0x0F,
4865       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4866         NULL, 0x0F, NULL, HFILL } },
4867     { &hf_reserved_0x1F,
4868       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4869         NULL, 0x1F, NULL, HFILL } },
4870     { &hf_reserved_0x20,
4871       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4872         NULL, 0x20, NULL, HFILL } },
4873     { &hf_reserved_0x40,
4874       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4875         NULL, 0x40, NULL, HFILL } },
4876     { &hf_reserved_0xC0,
4877       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4878         NULL, 0xC0, NULL, HFILL } },
4879     { &hf_reserved_0xE0,
4880       { "Reserved", "dmp.reserved", FT_UINT8, BASE_DEC,
4881         NULL, 0xE0, NULL, HFILL } },
4882     { &hf_reserved_0x8000,
4883       { "Reserved", "dmp.reserved", FT_UINT16, BASE_DEC,
4884         NULL, 0x8000, NULL, HFILL } },
4885   };
4886
4887   static gint *ett[] = {
4888     &ett_dmp,
4889     &ett_envelope,
4890     &ett_envelope_version,
4891     &ett_envelope_hop_count,
4892     &ett_envelope_rec_present,
4893     &ett_envelope_addr_enc,
4894     &ett_envelope_checksum,
4895     &ett_envelope_extensions,
4896     &ett_envelope_msg_id_type,
4897     &ett_envelope_msg_id,
4898     &ett_envelope_mts_id_length,
4899     &ett_envelope_ipm_id_length,
4900     &ett_envelope_cont_type,
4901     &ett_envelope_subm_time,
4902     &ett_envelope_time_diff,
4903     &ett_envelope_flags,
4904     &ett_envelope_recipients,
4905     &ett_envelope_ext_recipients,
4906     &ett_envelope_addresses,
4907     &ett_address,
4908     &ett_address_direct,
4909     &ett_address_rec_no,
4910     &ett_address_extended,
4911     &ett_address_ext_form,
4912     &ett_address_ext_rec_no,
4913     &ett_address_ext_action,
4914     &ett_address_ext_rep_req,
4915     &ett_address_ext_not_req,
4916     &ett_address_ext_type,
4917     &ett_address_ext_length,
4918     &ett_extensions,
4919     &ett_extension,
4920     &ett_extension_header,
4921     &ett_content,
4922     &ett_message,
4923     &ett_message_st_type,
4924     &ett_message_reserved,
4925     &ett_message_precedence,
4926     &ett_message_importance,
4927     &ett_message_body_format,
4928     &ett_message_sec_class,
4929     &ett_message_sec_pol,
4930     &ett_message_sec_cat,
4931     &ett_message_heading_flags,
4932     &ett_message_exp_time,
4933     &ett_message_dtg,
4934     &ett_message_sic,
4935     &ett_message_sic_key,
4936     &ett_message_sic_bitmap,
4937     &ett_message_sic_bits,
4938     &ett_message_eit,
4939     &ett_message_compr,
4940     &ett_message_body_reserved,
4941     &ett_message_body,
4942     &ett_message_body_uncompr,
4943     &ett_report,
4944     &ett_report_type,
4945     &ett_report_info_present_dr,
4946     &ett_report_info_present_ndr,
4947     &ett_report_addr_enc_dr,
4948     &ett_report_addr_enc_ndr,
4949     &ett_report_reserved,
4950     &ett_report_del_time,
4951     &ett_report_reason,
4952     &ett_report_suppl_info,
4953     &ett_report_diagn,
4954     &ett_notif,
4955     &ett_notif_type,
4956     &ett_notif_rec_time,
4957     &ett_notif_suppl_info,
4958     &ett_notif_acp127recip,
4959     &ett_ack,
4960     &ett_ack_recips,
4961     &ett_checksum,
4962     &ett_analysis
4963   };
4964
4965   static uat_field_t attributes_flds[] = {
4966     UAT_FLD_VS(dmp_security_class,nation, "Nation", nat_pol_id, 0),
4967     UAT_FLD_DEC(dmp_security_class,sec_class, "Classification", "Security Classification"),
4968     UAT_FLD_CSTRING(dmp_security_class,name, "Name", "Classification Name"),
4969     UAT_END_FIELDS
4970   };
4971
4972   uat_t *attributes_uat = uat_new("DMP Security Classifications",
4973                                   sizeof(dmp_security_class_t),
4974                                   "dmp_security_classifications",
4975                                   TRUE,
4976                                   (void*) &dmp_security_classes,
4977                                   &num_dmp_security_classes,
4978                                   UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
4979                                   "ChDMPSecurityClassifications",
4980                                   dmp_class_copy_cb,
4981                                   NULL,
4982                                   dmp_class_free_cb,
4983                                   NULL,
4984                                   attributes_flds);
4985
4986   module_t *dmp_module;
4987
4988   proto_dmp = proto_register_protocol (PNAME, PSNAME, PFNAME);
4989   register_dissector(PFNAME, dissect_dmp, proto_dmp);
4990
4991   proto_register_field_array (proto_dmp, hf, array_length (hf));
4992   proto_register_subtree_array (ett, array_length (ett));
4993   register_init_routine (&dmp_init_routine);
4994
4995   /* Set default UDP ports */
4996   range_convert_str (&global_dmp_port_range, DEFAULT_DMP_PORT_RANGE,
4997                      MAX_UDP_PORT);
4998
4999   /* Build national values */
5000   build_national_strings ();
5001
5002   /* Register our configuration options */
5003   dmp_module = prefs_register_protocol (proto_dmp, proto_reg_handoff_dmp);
5004
5005   prefs_register_obsolete_preference (dmp_module, "udp_port");
5006   prefs_register_obsolete_preference (dmp_module, "udp_port_second");
5007
5008   prefs_register_range_preference (dmp_module, "udp_ports",
5009                                   "DMP port numbers",
5010                                   "Port numbers used for DMP traffic",
5011                                    &global_dmp_port_range, MAX_UDP_PORT);
5012   prefs_register_enum_preference (dmp_module, "national_decode",
5013                                   "National decoding",
5014                                   "Select the type of decoding for nationally-defined values",
5015                                   &dmp_nat_decode, national_decoding,
5016                                   FALSE);
5017   prefs_register_enum_preference (dmp_module, "local_nation",
5018                                   "Nation of local server",
5019                                   "Select the nation of sending server.  This is used when presenting"
5020                                   " security classification values in messages with security"
5021                                   " policy set to National (nation of local server)",
5022                                   &dmp_local_nation, dmp_national_values,
5023                                   FALSE);
5024   prefs_register_uat_preference (dmp_module, "classes_table",
5025                                  "National Security Classifications",
5026                                  "Translation table for national security classifications.  This is used"
5027                                  " when presenting security classification values in messages with"
5028                                  " security policy set to National or Extended National",
5029                                  attributes_uat);
5030   prefs_register_bool_preference (dmp_module, "seq_ack_analysis",
5031                                   "SEQ/ACK Analysis",
5032                                   "Calculate sequence/acknowledgement analysis",
5033                                   &use_seq_ack_analysis);
5034   prefs_register_bool_preference (dmp_module, "align_ids",
5035                                   "Align identifiers in info list",
5036                                   "Align identifiers in info list"
5037                                   " (does not align when retransmission or"
5038                                   " duplicate acknowledgement indication)",
5039                                   &dmp_align);
5040   prefs_register_bool_preference (dmp_module, "subject_as_id",
5041                                   "Print subject as body id",
5042                                   "Print subject as body id in free text "
5043                                   "messages with subject",
5044                                   &dmp_subject_as_id);
5045   prefs_register_enum_preference (dmp_module, "struct_print",
5046                                   "Structured message id format",
5047                                   "Format of the structured message id",
5048                                   &dmp_struct_format, struct_id_options,
5049                                   FALSE);
5050   prefs_register_uint_preference (dmp_module, "struct_offset",
5051                                   "Offset to structured message id",
5052                                   "Used to set where the structured message "
5053                                   "id starts in the User Data",
5054                                   10, &dmp_struct_offset);
5055
5056   prefs_register_uint_preference (dmp_module, "struct_length",
5057                                   "Fixed text string length",
5058                                   "Used to set length of fixed text string "
5059                                   "in the structured message id format "
5060                                   "(maximum 128 characters)",
5061                                   10, &dmp_struct_length);
5062 }
5063
5064 static void range_delete_callback (guint32 port)
5065 {
5066     dissector_delete_uint ("udp.port", port, dmp_handle);
5067 }
5068
5069 static void range_add_callback (guint32 port)
5070 {
5071     dissector_add_uint ("udp.port", port, dmp_handle);
5072 }
5073
5074 void proto_reg_handoff_dmp (void)
5075 {
5076   static range_t *dmp_port_range;
5077   static gboolean dmp_prefs_initialized = FALSE;
5078
5079   if (!dmp_prefs_initialized) {
5080     dmp_handle = find_dissector (PFNAME);
5081     dmp_prefs_initialized = TRUE;
5082   } else {
5083     range_foreach (dmp_port_range, range_delete_callback);
5084     g_free (dmp_port_range);
5085   }
5086
5087   /* Save port number for later deletion */
5088   dmp_port_range = range_copy (global_dmp_port_range);
5089
5090   range_foreach (dmp_port_range, range_add_callback);
5091 }
5092
5093 /*
5094  * Editor modelines
5095  *
5096  * Local Variables:
5097  * c-basic-offset: 2
5098  * tab-width: 8
5099  * indent-tabs-mode: nil
5100  * End:
5101  *
5102  * ex: set shiftwidth=2 tabstop=8 expandtab:
5103  * :indentSize=2:tabSize=8:noTabs=true:
5104  */
5105