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