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