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