From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-s5066.c
1 /* packet-s5066.c
2  * Routines for STANAG 5066 SIS layer packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2005 by Menno Andriesse <s5066 [AT] nc3a.nato.int>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <gmodule.h>
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/dissectors/packet-tcp.h> /* For tcp_dissect_pdus() */
35
36 /* Forward reference */
37 /* Register functions */
38 void proto_reg_handoff_s5066(void);
39 /* Main dissectors */
40 static void dissect_s5066_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
41 static guint get_s5066_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset);
42 static void dissect_s5066_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
43 /* Service type and address dissectors */
44 static guint dissect_s5066_servicetype(tvbuff_t *tvb, guint offset, proto_tree *tree);
45 static guint dissect_s5066_address(tvbuff_t *tvb, guint offset, proto_tree *tree, gint source);
46 /* S-Primitive dissectors */
47 static guint dissect_s5066_01(tvbuff_t *tvb, guint offset, proto_tree *tree);
48 /* static guint dissect_s5066_02(tvbuff_t *tvb, guint offset, proto_tree *tree); */
49 static guint dissect_s5066_03(tvbuff_t *tvb, guint offset, proto_tree *tree);
50 static guint dissect_s5066_04(tvbuff_t *tvb, guint offset, proto_tree *tree);
51 static guint dissect_s5066_05(tvbuff_t *tvb, guint offset, proto_tree *tree);
52 static guint dissect_s5066_06(tvbuff_t *tvb, guint offset, proto_tree *tree);
53 static guint dissect_s5066_07(tvbuff_t *tvb, guint offset, proto_tree *tree);
54 static guint dissect_s5066_08(tvbuff_t *tvb, guint offset, proto_tree *tree);
55 static guint dissect_s5066_09(tvbuff_t *tvb, guint offset, proto_tree *tree);
56 static guint dissect_s5066_10(tvbuff_t *tvb, guint offset, proto_tree *tree);
57 static guint dissect_s5066_11(tvbuff_t *tvb, guint offset, proto_tree *tree);
58 static guint dissect_s5066_12(tvbuff_t *tvb, guint offset, proto_tree *tree);
59 static guint dissect_s5066_13(tvbuff_t *tvb, guint offset, proto_tree *tree);
60 static guint dissect_s5066_14(tvbuff_t *tvb, guint offset, proto_tree *tree);
61 /* static guint dissect_s5066_15(tvbuff_t *tvb, guint offset, proto_tree *tree); */
62 /* static guint dissect_s5066_16(tvbuff_t *tvb, guint offset, proto_tree *tree); */
63 /* static guint dissect_s5066_17(tvbuff_t *tvb, guint offset, proto_tree *tree); */
64 static guint dissect_s5066_18(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size);
65 static guint dissect_s5066_19(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size);
66 static guint dissect_s5066_20(tvbuff_t *tvb, guint offset, proto_tree *tree);
67 static guint dissect_s5066_21(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size);
68 static guint dissect_s5066_22(tvbuff_t *tvb, guint offset, proto_tree *tree);
69 static guint dissect_s5066_23(tvbuff_t *tvb, guint offset, proto_tree *tree);
70 static guint dissect_s5066_24(tvbuff_t *tvb, guint offset, proto_tree *tree);
71 static guint dissect_s5066_25(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size);
72 static guint dissect_s5066_26(tvbuff_t *tvb, guint offset, proto_tree *tree);
73 static guint dissect_s5066_27(tvbuff_t *tvb, guint offset, proto_tree *tree);
74
75 static gint proto_s5066 = -1;
76 static dissector_handle_t data_handle;
77
78 /* Enable desegmentation of S5066 over TCP */
79 static gboolean s5066_desegment = TRUE;
80 /* Dissect old 'edition 1' of STANAG 5066 (It lacks the 'version' field.) */
81 static gboolean s5066_edition_one = FALSE;
82 /* This port is registered with IANA */
83 static guint global_s5066_port = 5066;
84 /* Size of header outside 'size' field */
85 static gint s5066_header_size = 5;
86 /* Offset of 'size' field */
87 static gint s5066_size_offset = 3;
88
89 /* Sync should be 0x90EB */
90 static gint hf_s5066_sync_word = -1;
91 /* Version should be 0x00 */
92 static gint hf_s5066_version = -1;
93 /* Total size of the PDU, excluding this size and previous fields */
94 /* So total size is this + 5 bytes (s5066_header_size) */
95 static gint hf_s5066_size = -1;
96 /* Th type of PDU */
97 static gint hf_s5066_type = -1;
98 static const value_string s5066_pdu_type[] = {
99         { 1, "S_BIND_REQUEST"},
100         { 2, "S_UNBIND_REQUEST"},
101         { 3, "S_BIND_ACCEPTED"},
102         { 4, "S_BIND_REJECTED"},
103         { 5, "S_UNBIND_INDICATION"},
104         { 6, "S_HARD_LINK_ESTABLISH"},
105         { 7, "S_HARD_LINK_TERMINATE"},
106         { 8, "S_HARD_LINK_ESTABLISHED"},
107         { 9, "S_HARD_LINK_REJECTED"},
108         {10, "S_HARD_LINK_TERMINATED"},
109         {11, "S_HARD_LINK_INDICATION"},
110         {12, "S_HARD_LINK_ACCEPT"},
111         {13, "S_HARD_LINK_REJECT"},
112         {14, "S_SUBNET_AVAILABILITY"},
113         {15, "S_DATAFLOW_ON"},
114         {16, "S_DATAFLOW_OFF"},
115         {17, "S_KEEP_ALIVE"},
116         {18, "S_MANAGEMENT_MESSAGE_REQUEST"},
117         {19, "S_MANAGEMENT_MESSAGE_INDICATION"},
118         {20, "S_UNIDATA_REQUEST"},
119         {21, "S_UNIDATA_INDICATION"},
120         {22, "S_UNIDATA_REQUEST_CONFIRM"},
121         {23, "S_UNIDATA_REQUEST_REJECTED"},
122         {24, "S_EXPEDITED_UNIDATA_REQUEST"},
123         {25, "S_EXPEDITED_UNIDATA_INDICATION"},
124         {26, "S_EXPEDITED_UNIDATA_REQUEST_CONFIRM"},
125         {27, "S_EXPEDITED_UNIDATA_REQUEST_REJECTED"},
126         { 0, NULL },
127 };
128
129 /* STANAG 5066 Address */
130 /* Size is defined in nibbles (4 bits) */
131 static gint hf_s5066_ad_size = -1;
132 /* Group flag: 0 = false, 1 = true */
133 static gint hf_s5066_ad_group = -1;
134 /* The remainder of the 4 bytes form the address */
135 static gint hf_s5066_ad_address = -1;
136
137 /* Service type */
138 /* Transmission mode: */
139 static gint hf_s5066_st_txmode = -1;
140 static const value_string s5066_st_txmode[] = {
141         { 0, "Ignore service type field"},
142         { 1, "ARQ"},
143         { 2, "Non-ARQ (Broadcast)"},
144         { 3, "Non-ARQ (with errors)"},
145         { 4, "Other non-ARQ types"},
146         { 5, "Other non-ARQ types"},
147         { 6, "Other non-ARQ types"},
148         { 7, "Other non-ARQ types"},
149         { 8, "Other non-ARQ types"},
150         { 9, "Other non-ARQ types"},
151         {10, "Other non-ARQ types"},
152         {11, "Other non-ARQ types"},
153         {12, "Other non-ARQ types"},
154         {13, "Other non-ARQ types"},
155         {14, "Other non-ARQ types"},
156         {15, "Other non-ARQ types"},
157         { 0, NULL },
158 };
159 /* Delivery confirmation: */
160 static gint hf_s5066_st_delivery_confirmation = -1;
161 static const value_string s5066_st_delivery_confirmation[] = {
162         { 0, "No confirmation"},
163         { 1, "Node delivery confirmation"},
164         { 2, "Client delivery confirmation"},
165         { 3, "-- Not defined --"},
166         { 0, NULL },
167 };
168 /* Delivery order: */
169 static gint hf_s5066_st_delivery_order = -1;
170 static const value_string s5066_st_delivery_order[] = {
171         { 0, "In-order delivery"},
172         { 1, "As-they-arrive"},
173         { 0, NULL },
174 };
175 /* Extended field present: (Never in the current version.) */
176 static gint hf_s5066_st_extended = -1;
177 static const value_string s5066_st_extended[] = {
178         { 0, "No extended field"},
179         { 1, "Extended field follows"},
180         { 0, NULL },
181 };
182 /* Number of retransmissions when in Non-ARQ: */
183 static gint hf_s5066_st_retries = -1;
184
185 /* Type  1: S_BIND_REQUEST */
186 static gint hf_s5066_01_sapid = -1;
187 static gint hf_s5066_01_rank = -1;
188 static gint hf_s5066_01_unused = -1;
189
190 /* Type  2: S_UNBIND_REQUEST */
191 /*   --- no subfields ---   */
192
193 /* Type  3: S_BIND_ACCEPTED */
194 static gint hf_s5066_03_sapid = -1;
195 static gint hf_s5066_03_unused = -1;
196 static gint hf_s5066_03_mtu = -1;
197
198 /* Type  4: S_BIND_REJECTED */
199 static gint hf_s5066_04_reason = -1;
200 static const value_string s5066_04_reason[] = {
201         { 0, "Unknown reason"},
202         { 1, "Not enough resources"},
203         { 2, "Invalid Sap ID"},
204         { 3, "Sap ID already allocated"},
205         { 4, "ARQ mode unsupportable during broadcast session"},
206         { 0, NULL },
207 };
208
209 /* Type  5: S_UNBIND_INDICATION */
210 static gint hf_s5066_05_reason = -1;
211 static const value_string s5066_05_reason[] = {
212         { 0, "Unknown reason"},
213         { 1, "Connection pre-empted by higher ranking client"},
214         { 2, "Inactivity (failure to respond to 'Keep-alive')"},
215         { 3, "Too many invalid primitives"},
216         { 4, "Too many expedited data request primitives"},
217         { 5, "ARQ mode unsupportable during broadcast session"},
218         { 0, NULL },
219 };
220
221 /* Hard links: hardlinktype value string array. */
222 static const value_string s5066_hard_link_type[] = {
223         { 0, "Link reservation"},
224         { 1, "Partial Bandwidth reservation"},
225         { 2, "Full Bandwidth reservation"},
226         { 3, "--- undefined ---"},
227         { 0, NULL },
228 };
229
230 /* Type  6: S_HARD_LINK_ESTABLISH */
231 static gint hf_s5066_06_link_type = -1;
232 static gint hf_s5066_06_link_priority = -1;
233 static gint hf_s5066_06_sapid = -1;
234
235 /* Type  7: S_HARD_LINK_TERMINATE */
236 /* Only  remote node address */
237
238 /* Type  8: S_HARD_LINK_ESTABLISHED */
239 static gint hf_s5066_08_remote_status = -1;
240 static const value_string s5066_08_remote_status[] = {
241         { 0, "ERROR"},
242         { 1, "OK"},
243         { 0, NULL },
244 };
245 static gint hf_s5066_08_link_type = -1;
246 static gint hf_s5066_08_link_priority = -1;
247 static gint hf_s5066_08_sapid = -1;
248
249 /* Type  9: S_HARD_LINK_REJECTED */
250 static gint hf_s5066_09_reason = -1;
251 static const value_string s5066_09_reason[] = {
252         { 0, "--- undefined ---"},
253         { 1, "Remote node busy"},
254         { 2, "Higher priority link exists"},
255         { 3, "Remote node not responding"},
256         { 4, "Destination Sap ID not bound"},
257         { 5, "Requested Type-0 link exists"},
258         { 0, NULL },
259 };
260 static gint hf_s5066_09_link_type = -1;
261 static gint hf_s5066_09_link_priority = -1;
262 static gint hf_s5066_09_sapid = -1;
263
264 /* Type 10: S_HARD_LINK_TERMINATED */
265 static gint hf_s5066_10_reason = -1;
266 static const value_string s5066_10_reason[] = {
267         { 0, "--- undefined ---"},
268         { 1, "Link terminated by remote node"},
269         { 2, "Higher priority link requested"},
270         { 3, "Remote node not responding"},
271         { 4, "Destination Sap ID not bound"},
272         { 5, "Physical link broken"},
273         { 0, NULL },
274 };
275 static gint hf_s5066_10_link_type = -1;
276 static gint hf_s5066_10_link_priority = -1;
277 static gint hf_s5066_10_sapid = -1;
278
279 /* Type 11: S_HARD_LINK_INDICATION */
280 static gint hf_s5066_11_remote_status = -1;
281 static const value_string s5066_11_remote_status[] = {
282         { 0, "ERROR"},
283         { 1, "OK"},
284         { 0, NULL },
285 };
286 static gint hf_s5066_11_link_type = -1;
287 static gint hf_s5066_11_link_priority = -1;
288 static gint hf_s5066_11_sapid = -1;
289
290 /* Type 12: S_HARD_LINK_ACCEPT */
291 static gint hf_s5066_12_link_type = -1;
292 static gint hf_s5066_12_link_priority = -1;
293 static gint hf_s5066_12_sapid = -1;
294
295 /* Type 13: S_HARD_LINK_REJECT */
296 static gint hf_s5066_13_reason = -1;
297 static const value_string s5066_13_reason[] = {
298         { 0, "--- undefined ---"},
299         { 0, NULL },
300 };
301 static gint hf_s5066_13_link_type = -1;
302 static gint hf_s5066_13_link_priority = -1;
303 static gint hf_s5066_13_sapid = -1;
304
305 /* Type 14: S_SUBNET_AVAILABILITY */
306 static gint hf_s5066_14_status= -1;
307 static const value_string s5066_14_status[] = {
308         { 0, "Off"},
309         { 1, "On"},
310         { 2, "Receive only"},
311         { 3, "Half-duplex"},
312         { 4, "Full-duplex"},
313         { 0, NULL },
314 };
315 static gint hf_s5066_14_reason= -1;
316 static const value_string s5066_14_reason[] = {
317         { 0, "Unknown reason"},
318         { 1, "Local node in EMCON"},
319         { 2, "Higher priority link requested"},
320         { 0, NULL },
321 };
322
323 /* Type 15: S_DATAFLOW_ON */
324 /*   --- no subfields ---   */
325
326 /* Type 16: S_DATAFLOW_OFF */
327 /*   --- no subfields ---   */
328
329 /* Type 17: S_KEEP_ALIVE */
330 /*   --- no subfields ---   */
331
332 /* Type 18: S_MANAGEMENT_MESSAGE_REQUEST */
333 static gint hf_s5066_18_type = -1;
334 static gint hf_s5066_18_body = -1;
335
336 /* Type 19: S_MANAGEMENT_MESSAGE_INDICATION */
337 static gint hf_s5066_19_type = -1;
338 static gint hf_s5066_19_body = -1;
339
340 /* Type 20: S_UNIDATA_REQUEST */
341 static gint hf_s5066_20_priority = -1;
342 static gint hf_s5066_20_sapid = -1;
343 static gint hf_s5066_20_ttl = -1;
344 static gint hf_s5066_20_size = -1;
345
346 /* Type 21: S_UNIDATA_INDICATION */
347 static gint hf_s5066_21_priority = -1;
348 static gint hf_s5066_21_dest_sapid = -1;
349 static gint hf_s5066_21_tx_mode = -1;
350 static gint hf_s5066_21_src_sapid = -1;
351 static gint hf_s5066_21_size = -1;
352 static gint hf_s5066_21_err_blocks = -1;
353 static gint hf_s5066_21_err_ptr = -1;
354 static gint hf_s5066_21_err_size = -1;
355 static gint hf_s5066_21_nrx_blocks = -1;
356 static gint hf_s5066_21_nrx_ptr = -1;
357 static gint hf_s5066_21_nrx_size = -1;
358
359
360 /* Type 22: S_UNIDATA_REQUEST_CONFIRM */
361 static gint hf_s5066_22_unused = -1;
362 static gint hf_s5066_22_sapid = -1;
363 static gint hf_s5066_22_size = -1;
364 static gint hf_s5066_22_data = -1;
365
366 /* Type 23: S_UNIDATA_REQUEST_REJECTED */
367 static gint hf_s5066_23_reason = -1;
368 static const value_string s5066_23_reason[] = {
369         { 0, "Unknown reason"},
370         { 1, "Time-To-Live expired"},
371         { 2, "Destination SapID not bound"},
372         { 3, "Destination node not responding"},
373         { 4, "U_PDU larger than MTU"},
374         { 5, "Transmission Mode not specified"},
375         { 0, NULL },
376 };
377 static gint hf_s5066_23_sapid = -1;
378 static gint hf_s5066_23_size = -1;
379 static gint hf_s5066_23_data = -1;
380
381 /* Type 24: S_EXPEDITED_UNIDATA_REQUEST */
382 static gint hf_s5066_24_unused = -1;
383 static gint hf_s5066_24_sapid = -1;
384 static gint hf_s5066_24_ttl = -1;
385 static gint hf_s5066_24_size = -1;
386
387 /* Type 25: S_EXPEDITED_UNIDATA_INDICATION */
388 static gint hf_s5066_25_unused = -1;
389 static gint hf_s5066_25_dest_sapid = -1;
390 static gint hf_s5066_25_tx_mode = -1;
391 static gint hf_s5066_25_src_sapid = -1;
392 static gint hf_s5066_25_size = -1;
393 static gint hf_s5066_25_err_blocks = -1;
394 static gint hf_s5066_25_err_ptr = -1;
395 static gint hf_s5066_25_err_size = -1;
396 static gint hf_s5066_25_nrx_blocks = -1;
397 static gint hf_s5066_25_nrx_ptr = -1;
398 static gint hf_s5066_25_nrx_size = -1;
399
400 /* Type 26: S_EXPEDITED_UNIDATA_REQUEST_CONFIRM */
401 static gint hf_s5066_26_unused = -1;
402 static gint hf_s5066_26_sapid = -1;
403 static gint hf_s5066_26_size = -1;
404 static gint hf_s5066_26_data = -1;
405
406 /* Type 27: S_EXPEDITED_UNIDATA_REQUEST_REJECTED */
407 static gint hf_s5066_27_reason = -1;
408 static const value_string s5066_27_reason[] = {
409         { 0, "Unknown reason"},
410         { 1, "Time-To-Live expired"},
411         { 2, "Destination SapID not bound"},
412         { 3, "Destination node not responding"},
413         { 4, "U_PDU larger than MTU"},
414         { 5, "Transmission Mode not specified"},
415         { 0, NULL },
416 };
417 static gint hf_s5066_27_sapid = -1;
418 static gint hf_s5066_27_size = -1;
419 static gint hf_s5066_27_data = -1;
420
421
422 static gint ett_s5066 = -1;
423 static gint ett_s5066_pdu = -1;
424 static gint ett_s5066_servicetype = -1;
425 static gint ett_s5066_address = -1;
426
427 void
428 proto_register_s5066(void)
429 {
430         static hf_register_info hf[] = {
431                 { &hf_s5066_sync_word,
432                         { "Sync preamble", "s5066.sync", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
433                 },
434                 { &hf_s5066_version,
435                         { "S5066 version", "s5066.version", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
436                 },
437                 { &hf_s5066_size,
438                         { "S_Primitive size", "s5066.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
439                 },
440                 { &hf_s5066_type,
441                         { "PDU Type", "s5066.type", FT_UINT8, BASE_DEC, VALS(s5066_pdu_type), 0x0, NULL, HFILL }
442                 },
443                 /* STANAG 5066 Address */
444                 { &hf_s5066_ad_size,
445                         { "Address size (1/2 Bytes)", "s5066.address.size", FT_UINT8, BASE_HEX, NULL, 0xE0, NULL, HFILL }
446                 },
447                 { &hf_s5066_ad_group,
448                         { "Group address", "s5066.address.group", FT_UINT8, BASE_HEX, NULL, 0x10, NULL, HFILL }
449                 },
450                 { &hf_s5066_ad_address,
451                         { "Address", "s5066.address.address", FT_IPv4, BASE_NONE, NULL, 0, NULL, HFILL }
452                 },
453                 /* Service type */
454                 { &hf_s5066_st_txmode,
455                         { "Transmission mode", "s5066.st.txmode", FT_UINT8, BASE_HEX, VALS(s5066_st_txmode), 0xF0, NULL, HFILL }
456                 },
457                 { &hf_s5066_st_delivery_confirmation,
458                         { "Delivery confirmation", "s5066.st.confirm", FT_UINT8, BASE_HEX, VALS(s5066_st_delivery_confirmation),  0x0C, NULL, HFILL }
459                 },
460                 { &hf_s5066_st_delivery_order,
461                         { "Delivery order", "s5066.st.order", FT_UINT8, BASE_HEX, VALS(s5066_st_delivery_order), 0x02, NULL, HFILL }
462                 },
463                 { &hf_s5066_st_extended,
464                         { "Extended field", "s5066.st.extended", FT_UINT8, BASE_HEX, VALS(s5066_st_extended), 0x01, NULL, HFILL }
465                 },
466                 { &hf_s5066_st_retries,
467                         { "Minimum number of retransmissions", "s5066.st.retries", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
468                 },
469                 /* PDU Type 01: S_BIND_REQUEST */
470                 { &hf_s5066_01_sapid,
471                         { "Sap ID", "s5066.01.sapid", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
472                 },
473                 { &hf_s5066_01_rank,
474                         { "Rank", "s5066.01.rank", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
475                 },
476                 { &hf_s5066_01_unused,
477                         { "(Unused)", "s5066.01.unused", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }
478                 },
479                 /* PDU Type 02: S_UNBIND_REQUEST */
480                 /*     --- no subfields ---     */
481                 /* PDU Type 03: S_BIND_ACCEPTED */
482                 { &hf_s5066_03_sapid,
483                         { "Sap ID", "s5066.03.sapid", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
484                 },
485                 { &hf_s5066_03_unused,
486                         { "(Unused)", "s5066.03.unused", FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL }
487                 },
488                 { &hf_s5066_03_mtu,
489                         { "MTU", "s5066.03.mtu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
490                 },
491                 /* PDU Type 04: S_BIND_REJECTED */
492                 { &hf_s5066_04_reason,
493                         { "Reason", "s5066.04.reason", FT_UINT8, BASE_DEC, VALS(s5066_04_reason), 0x0, NULL, HFILL }
494                 },
495                 /* PDU Type 05: S_UNBIND_INDICATION */
496                 { &hf_s5066_05_reason,
497                         { "Reason", "s5066.05.reason", FT_UINT8, BASE_DEC, VALS(s5066_05_reason), 0x0, NULL, HFILL }
498                 },
499                 /* Type  6: S_HARD_LINK_ESTABLISH */
500                 { &hf_s5066_06_link_type,
501                         { "Hardlink type", "s5066.06.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
502                 },
503                 { &hf_s5066_06_link_priority,
504                         { "Priority", "s5066.06.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
505                 },
506                 { &hf_s5066_06_sapid,
507                         { "Remote Sap ID", "s5066.06.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
508                 },
509                 /* Type  7: S_HARD_LINK_TERMINATE */
510                 /* --- Only remote node address --- */
511                 /* Type  8: S_HARD_LINK_ESTABLISHED */
512                 { &hf_s5066_08_remote_status,
513                         { "Remote node status", "s5066.08.status", FT_UINT8, BASE_DEC, VALS(s5066_08_remote_status), 0x0, NULL, HFILL }
514                 },
515                 { &hf_s5066_08_link_type,
516                         { "Hardlink type", "s5066.08.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
517                 },
518                 { &hf_s5066_08_link_priority,
519                         { "Priority", "s5066.08.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
520                 },
521                 { &hf_s5066_08_sapid,
522                         { "Remote Sap ID", "s5066.08.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
523                 },
524                 /* Type  9: S_HARD_LINK_REJECTED */
525                 { &hf_s5066_09_reason,
526                         { "Reason", "s5066.09.reason", FT_UINT8, BASE_DEC, VALS(s5066_09_reason), 0x0, NULL, HFILL }
527                 },
528                 { &hf_s5066_09_link_type,
529                         { "Hardlink type", "s5066.09.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
530                 },
531                 { &hf_s5066_09_link_priority,
532                         { "Priority", "s5066.09.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
533                 },
534                 { &hf_s5066_09_sapid,
535                         { "Remote Sap ID", "s5066.09.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
536                 },
537                 /* Type 10: S_HARD_LINK_TERMINATED */
538                 { &hf_s5066_10_reason,
539                         { "Reason", "s5066.10.reason", FT_UINT8, BASE_DEC, VALS(s5066_10_reason), 0x0, NULL, HFILL }
540                 },
541                 { &hf_s5066_10_link_type,
542                         { "Hardlink type", "s5066.10.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
543                 },
544                 { &hf_s5066_10_link_priority,
545                         { "Priority", "s5066.10.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
546                 },
547                 { &hf_s5066_10_sapid,
548                         { "Remote Sap ID", "s5066.10.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
549                 },
550                 /* Type 11: S_HARD_LINK_INDICATION */
551                 { &hf_s5066_11_remote_status,
552                         { "Remote node status", "s5066.11.status", FT_UINT8, BASE_DEC, VALS(s5066_11_remote_status), 0x0, NULL, HFILL }
553                 },
554                 { &hf_s5066_11_link_type,
555                         { "Hardlink type", "s5066.11.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
556                 },
557                 { &hf_s5066_11_link_priority,
558                         { "Priority", "s5066.11.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
559                 },
560                 { &hf_s5066_11_sapid,
561                         { "Remote Sap ID", "s5066.11.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
562                 },
563                 /* Type 12: S_HARD_LINK_ACCEPT */
564                 { &hf_s5066_12_link_type,
565                         { "Hardlink type", "s5066.12.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
566                 },
567                 { &hf_s5066_12_link_priority,
568                         { "Priority", "s5066.12.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
569                 },
570                 { &hf_s5066_12_sapid,
571                         { "Remote Sap ID", "s5066.12.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
572                 },
573                 /* Type 13: S_HARD_LINK_REJECT */
574                 { &hf_s5066_13_reason,
575                         { "Reason", "s5066.13.reason", FT_UINT8, BASE_DEC, VALS(s5066_13_reason), 0x0, NULL, HFILL }
576                 },
577                 { &hf_s5066_13_link_type,
578                         { "Hardlink type", "s5066.13.type", FT_UINT8, BASE_DEC, VALS(s5066_hard_link_type), 0xC0, NULL, HFILL }
579                 },
580                 { &hf_s5066_13_link_priority,
581                         { "Priority", "s5066.13.priority", FT_UINT8, BASE_DEC, NULL, 0x30, NULL, HFILL }
582                 },
583                 { &hf_s5066_13_sapid,
584                         { "Remote Sap ID", "s5066.13.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
585                 },
586                 /* Type 14: S_SUBNET_AVAILABILITY */
587                 { &hf_s5066_14_status,
588                         { "Status", "s5066.14.status", FT_UINT8, BASE_DEC, VALS(s5066_14_status), 0x0, NULL, HFILL }
589                 },
590                 { &hf_s5066_14_reason,
591                         { "Reason", "s5066.14.reason", FT_UINT8, BASE_DEC, VALS(s5066_14_reason), 0x0, NULL, HFILL }
592                 },
593                 /* Type 15: S_DATAFLOW_ON */
594                 /*   --- no subfields ---   */
595                 /* Type 16: S_DATAFLOW_OFF */
596                 /*   --- no subfields ---   */
597                 /* Type 17: S_KEEP_ALIVE */
598                 /*   --- no subfields ---   */
599                 /* Type 18: S_MANAGEMENT_MESSAGE_REQUEST */
600                 { &hf_s5066_18_type,
601                         { "Message Type", "s5066.18.type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
602                 },
603                 { &hf_s5066_18_body,
604                         { "Message Body", "s5066.18.body", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
605                 },
606                 /* Type 19: S_MANAGEMENT_MESSAGE_INDICATION */
607                 { &hf_s5066_19_type,
608                         { "Message Type", "s5066.19.type", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }
609                 },
610                 { &hf_s5066_19_body,
611                         { "Message Body", "s5066.19.body", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
612                 },
613                 /* Type 20: S_UNIDATA_REQUEST */
614                 { &hf_s5066_20_priority,
615                         { "Priority", "s5066.20.priority", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
616                 },
617                 { &hf_s5066_20_sapid,
618                         { "Destination Sap ID", "s5066.20.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
619                 },
620                 { &hf_s5066_20_ttl,
621                         { "Time-To-Live (x2 seconds)", "s5066.20.ttl", FT_UINT24, BASE_DEC, NULL, 0x0FFFFF, NULL, HFILL }
622                 },
623                 { &hf_s5066_20_size,
624                         { "U_PDU Size", "s5066.20.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
625                 },
626                 /* Type 21: S_UNIDATA_INDICATION */
627                 { &hf_s5066_21_priority,
628                         { "Priority", "s5066.21.priority", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
629                 },
630                 { &hf_s5066_21_dest_sapid,
631                         { "Destination Sap ID", "s5066.21.dest_sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
632                 },
633                 { &hf_s5066_21_tx_mode,
634                         { "Transmission Mode", "s5066.21.txmode", FT_UINT8, BASE_HEX, VALS(s5066_st_txmode), 0xF0, NULL, HFILL }
635                 },
636                 { &hf_s5066_21_src_sapid,
637                         { "Source Sap ID", "s5066.21.src_sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
638                 },
639                 { &hf_s5066_21_size,
640                         { "U_PDU Size", "s5066.21.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
641                 },
642                 { &hf_s5066_21_err_blocks,
643                         { "Number of errored blocks", "s5066.21.err_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
644                 },
645                 { &hf_s5066_21_err_ptr,
646                         { "Pointer to error block", "s5066.21.err_ptr", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
647                 },
648                 { &hf_s5066_21_err_size,
649                         { "Size of error block", "s5066.21.err_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
650                 },
651                 { &hf_s5066_21_nrx_blocks,
652                         { "Number of non-received blocks", "s5066.21.nrx_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
653                 },
654                 { &hf_s5066_21_nrx_ptr,
655                         { "Pointer to non-received block", "s5066.21.nrx_ptr", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
656                 },
657                 { &hf_s5066_21_nrx_size,
658                         { "Size of non-received block", "s5066.21.nrx_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
659                 },
660                 /* Type 22: S_UNIDATA_REQUEST_CONFIRM */
661                 { &hf_s5066_22_unused,
662                         { "(Unused)", "s5066.22.unused", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
663                 },
664                 { &hf_s5066_22_sapid,
665                         { "Destination Sap ID", "s5066.22.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
666                 },
667                 { &hf_s5066_22_size,
668                         { "U_PDU Size", "s5066.22.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
669                 },
670                 { &hf_s5066_22_data,
671                         { "(Part of) Confirmed data", "s5066.22.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
672                 },
673                 /* Type 23: S_UNIDATA_REQUEST_REJECTED */
674                 { &hf_s5066_23_reason,
675                         { "Reason", "s5066.23.reason", FT_UINT8, BASE_DEC, VALS(s5066_23_reason), 0xF0, NULL, HFILL }
676                 },
677                 { &hf_s5066_23_sapid,
678                         { "Destination Sap ID", "s5066.23.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
679                 },
680                 { &hf_s5066_23_size,
681                         { "U_PDU Size", "s5066.23.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
682                 },
683                 { &hf_s5066_23_data,
684                         { "(Part of) Rejected data", "s5066.23.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
685                 },
686                 /* Type 24: S_EXPEDITED_UNIDATA_REQUEST */
687                 { &hf_s5066_24_unused,
688                         { "(Unused)", "s5066.24.unused", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
689                 },
690                 { &hf_s5066_24_sapid,
691                         { "Destination Sap ID", "s5066.24.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
692                 },
693                 { &hf_s5066_24_ttl,
694                         { "Time-To-Live (x2 seconds)", "s5066.24.ttl", FT_UINT24, BASE_DEC, NULL, 0x0FFFFF, NULL, HFILL }
695                 },
696                 { &hf_s5066_24_size,
697                         { "U_PDU Size", "s5066.24.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
698                 },
699                 /* Type 25: S_EXPEDITED_UNIDATA_INDICATION */
700                 { &hf_s5066_25_unused,
701                         { "(Unused)", "s5066.25.unused", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
702                 },
703                 { &hf_s5066_25_dest_sapid,
704                         { "Destination Sap ID", "s5066.25.dest_sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
705                 },
706                 { &hf_s5066_25_tx_mode,
707                         { "Transmission Mode", "s5066.25.txmode", FT_UINT8, BASE_HEX, VALS(s5066_st_txmode), 0xF0, NULL, HFILL }
708                 },
709                 { &hf_s5066_25_src_sapid,
710                         { "Source Sap ID", "s5066.25.src_sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
711                 },
712                 { &hf_s5066_25_size,
713                         { "U_PDU Size", "s5066.25.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
714                 },
715                 { &hf_s5066_25_err_blocks,
716                         { "Number of errored blocks", "s5066.25.err_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
717                 },
718                 { &hf_s5066_25_err_ptr,
719                         { "Pointer to error block", "s5066.25.err_ptr", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
720                 },
721                 { &hf_s5066_25_err_size,
722                         { "Size of error block", "s5066.25.err_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
723                 },
724                 { &hf_s5066_25_nrx_blocks,
725                         { "Number of non-received blocks", "s5066.25.nrx_blocks", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
726                 },
727                 { &hf_s5066_25_nrx_ptr,
728                         { "Pointer to non-received block", "s5066.25.nrx_ptr", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
729                 },
730                 { &hf_s5066_25_nrx_size,
731                         { "Size of non-received block", "s5066.25.nrx_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
732                 },
733                 /* Type 26: S_EXPEDITED_UNIDATA_REQUEST_CONFIRM */
734                 { &hf_s5066_26_unused,
735                         { "(Unused)", "s5066.26.unused", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }
736                 },
737                 { &hf_s5066_26_sapid,
738                         { "Destination Sap ID", "s5066.26.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
739                 },
740                 { &hf_s5066_26_size,
741                         { "U_PDU Size", "s5066.26.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
742                 },
743                 { &hf_s5066_26_data,
744                         { "(Part of) Confirmed data", "s5066.26.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
745                 },
746                 /* Type 27: S_EXPEDITED_UNIDATA_REQUEST_REJECTED */
747                 { &hf_s5066_27_reason,
748                         { "Reason", "s5066.27.reason", FT_UINT8, BASE_DEC, VALS(s5066_27_reason), 0xF0, NULL, HFILL }
749                 },
750                 { &hf_s5066_27_sapid,
751                         { "Destination Sap ID", "s5066.27.sapid", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }
752                 },
753                 { &hf_s5066_27_size,
754                         { "U_PDU Size", "s5066.27.size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
755                 },
756                 { &hf_s5066_27_data,
757                         { "(Part of) Rejected data", "s5066.27.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
758                 },
759
760         };
761
762         /* Setup protocol subtree array */
763         static gint *ett[] = {
764                 &ett_s5066,
765                 &ett_s5066_pdu,
766                 &ett_s5066_servicetype,
767                 &ett_s5066_address,
768         };
769
770         module_t *s5066_module;
771
772         proto_s5066 = proto_register_protocol (
773                         "STANAG 5066 (SIS layer)",      /* name */
774                         "STANAG 5066",                  /* short name*/
775                         "s5066"                         /* abbrev */
776                 );
777         proto_register_field_array(proto_s5066, hf, array_length(hf));
778         proto_register_subtree_array(ett, array_length(ett));
779
780         s5066_module = prefs_register_protocol(proto_s5066, proto_reg_handoff_s5066);
781         prefs_register_bool_preference(s5066_module, "desegment_pdus",
782                                        "Reassemble S5066 PDUs spanning multiple TCP segments",
783                                        "Whether the S5066 dissector should reassemble PDUs spanning multiple TCP segments."
784                                        " The default is to use reassembly.",
785                                        &s5066_desegment);
786         prefs_register_bool_preference(s5066_module, "edition_one",
787                                        "Dissect edition 1.0 of STANAG 5066",
788                                        "Whether the S5066 dissector should dissect this edition of the STANAG."
789                                        " This edition was never formally approved and is very rare. The common edition is edition 1.2.",
790                                        &s5066_edition_one);
791         prefs_register_uint_preference(s5066_module, "tcp.port",
792                                        "STANAG 5066 TCP Port",
793                                        "Set the port for STANAG 5066. (If other than the default 5066."
794                                        " This number is registered with IANA.)",
795                                        10, &global_s5066_port);
796 }
797
798 void
799 proto_reg_handoff_s5066(void)
800 {
801         static gboolean Initialized = FALSE;
802         static dissector_handle_t s5066_tcp_handle;
803         static guint saved_s5066_port;
804
805         if (!Initialized) {
806                 s5066_tcp_handle = create_dissector_handle(dissect_s5066_tcp, proto_s5066);
807                 data_handle = find_dissector("data");
808                 Initialized = TRUE;
809         } else {
810                 dissector_delete("tcp.port", saved_s5066_port, s5066_tcp_handle);
811         }
812
813         dissector_add("tcp.port", global_s5066_port, s5066_tcp_handle);
814         saved_s5066_port = global_s5066_port;
815
816         if (!s5066_edition_one) {
817                 s5066_header_size = 5;
818                 s5066_size_offset = 3;
819         } else {
820                 s5066_header_size = 4;
821                 s5066_size_offset = 2;
822         }
823 }
824
825 static guint
826 dissect_s5066_address(tvbuff_t *tvb, guint offset, proto_tree *tree, gint source)
827 {
828         proto_item *ti = NULL;
829         proto_tree *s5066_tree_address = NULL;
830         guint32 address;
831
832         if (source) {
833                 ti = proto_tree_add_text(tree, tvb, offset, 4, "Source Address");
834         }
835         else {
836                 ti = proto_tree_add_text(tree, tvb, offset, 4, "Destination Address");
837         }
838         s5066_tree_address = proto_item_add_subtree(ti, ett_s5066_address);
839         proto_tree_add_item(s5066_tree_address, hf_s5066_ad_size, tvb, offset, 1, FALSE);
840         proto_tree_add_item(s5066_tree_address, hf_s5066_ad_group, tvb, offset, 1, FALSE);
841         address = tvb_get_ntohl(tvb, offset);
842         address = address & 0x1FFFFFFF;
843         proto_tree_add_ipv4(s5066_tree_address, hf_s5066_ad_address, tvb, offset, 4, g_htonl(address));
844
845         return offset += 4;
846 }
847
848 static guint
849 dissect_s5066_servicetype(tvbuff_t *tvb, guint offset, proto_tree *tree)
850 {
851         proto_item *ti = NULL;
852         proto_tree *s5066_tree_servicetype = NULL;
853
854         ti = proto_tree_add_text(tree, tvb, offset, 2, "Service type");
855         s5066_tree_servicetype = proto_item_add_subtree(ti, ett_s5066_servicetype);
856
857         proto_tree_add_item(s5066_tree_servicetype, hf_s5066_st_txmode, tvb, offset, 1, FALSE);
858         proto_tree_add_item(s5066_tree_servicetype, hf_s5066_st_delivery_confirmation, tvb, offset, 1, FALSE);
859         proto_tree_add_item(s5066_tree_servicetype, hf_s5066_st_delivery_order, tvb, offset, 1, FALSE);
860         proto_tree_add_item(s5066_tree_servicetype, hf_s5066_st_extended, tvb, offset, 1, FALSE); offset++;
861         proto_tree_add_item(s5066_tree_servicetype, hf_s5066_st_retries, tvb, offset, 1, FALSE);
862
863         return offset;
864 }
865
866 /* S_BIND_REQUEST */
867 static guint
868 dissect_s5066_01(tvbuff_t *tvb, guint offset, proto_tree *tree)
869 {
870         proto_tree_add_item(tree, hf_s5066_01_sapid, tvb, offset, 1, FALSE);
871         proto_tree_add_item(tree, hf_s5066_01_rank, tvb, offset, 1, FALSE); offset++;
872
873         offset = dissect_s5066_servicetype(tvb, offset, tree);
874
875         proto_tree_add_item(tree, hf_s5066_01_unused, tvb, offset, 1, FALSE); offset++;
876         return offset;
877 }
878
879 /* S_UNBIND_REQUEST */
880 /* Commented out: does nothing and causes <variable not used> messages.
881 static guint
882 dissect_s5066_02(tvbuff_t *tvb, guint offset, proto_tree *tree)
883 {
884         return offset;
885 }
886 */
887
888 /* S_BIND_ACCEPTED */
889 static guint
890 dissect_s5066_03(tvbuff_t *tvb, guint offset, proto_tree *tree)
891 {
892         proto_tree_add_item(tree, hf_s5066_03_sapid, tvb, offset, 1, FALSE);
893         proto_tree_add_item(tree, hf_s5066_03_unused, tvb, offset, 1, FALSE); offset++;
894         proto_tree_add_item(tree, hf_s5066_03_mtu, tvb, offset, 2, FALSE); offset +=2;
895         return offset;
896 }
897
898 /* S_BIND_REJECTED */
899 static guint
900 dissect_s5066_04(tvbuff_t *tvb, guint offset, proto_tree *tree)
901 {
902         proto_tree_add_item(tree, hf_s5066_04_reason, tvb, offset, 1, FALSE); offset++;
903         return offset;
904 }
905
906 /* S_UNBIND_INDICATION */
907 static guint
908 dissect_s5066_05(tvbuff_t *tvb, guint offset, proto_tree *tree)
909 {
910         proto_tree_add_item(tree, hf_s5066_05_reason, tvb, offset, 1, FALSE); offset++;
911         return offset;
912 }
913
914 /* S_HARD_LINK_ESTABLISH */
915 static guint
916 dissect_s5066_06(tvbuff_t *tvb, guint offset, proto_tree *tree)
917 {
918         proto_tree_add_item(tree, hf_s5066_06_link_type, tvb, offset, 1, FALSE);
919         proto_tree_add_item(tree, hf_s5066_06_link_priority, tvb, offset, 1, FALSE);
920         proto_tree_add_item(tree, hf_s5066_06_sapid, tvb, offset, 1, FALSE); offset++;
921         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
922         return offset;
923 }
924
925 /* S_HARD_LINK_TERMINATE */
926 static guint
927 dissect_s5066_07(tvbuff_t *tvb, guint offset, proto_tree *tree)
928 {
929         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
930         return offset;
931 }
932
933 /* S_HARD_LINK_ESTABLISHED */
934 static guint
935 dissect_s5066_08(tvbuff_t *tvb, guint offset, proto_tree *tree)
936 {
937         proto_tree_add_item(tree, hf_s5066_08_remote_status, tvb, offset, 1, FALSE); offset++;
938         proto_tree_add_item(tree, hf_s5066_08_link_type, tvb, offset, 1, FALSE);
939         proto_tree_add_item(tree, hf_s5066_08_link_priority, tvb, offset, 1, FALSE);
940         proto_tree_add_item(tree, hf_s5066_08_sapid, tvb, offset, 1, FALSE); offset++;
941         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
942         return offset;
943 }
944
945 /* S_HARD_LINK_REJECTED */
946 static guint
947 dissect_s5066_09(tvbuff_t *tvb, guint offset, proto_tree *tree)
948 {
949         proto_tree_add_item(tree, hf_s5066_09_reason, tvb, offset, 1, FALSE); offset++;
950         proto_tree_add_item(tree, hf_s5066_09_link_type, tvb, offset, 1, FALSE);
951         proto_tree_add_item(tree, hf_s5066_09_link_priority, tvb, offset, 1, FALSE);
952         proto_tree_add_item(tree, hf_s5066_09_sapid, tvb, offset, 1, FALSE); offset++;
953         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
954         return offset;
955 }
956
957 /* S_HARD_LINK_TERMINATED */
958 static guint
959 dissect_s5066_10(tvbuff_t *tvb, guint offset, proto_tree *tree)
960 {
961         proto_tree_add_item(tree, hf_s5066_10_reason, tvb, offset, 1, FALSE); offset++;
962         proto_tree_add_item(tree, hf_s5066_10_link_type, tvb, offset, 1, FALSE);
963         proto_tree_add_item(tree, hf_s5066_10_link_priority, tvb, offset, 1, FALSE);
964         proto_tree_add_item(tree, hf_s5066_10_sapid, tvb, offset, 1, FALSE); offset++;
965         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
966         return offset;
967 }
968
969 /* S_HARD_LINK_INDICATION */
970 static guint
971 dissect_s5066_11(tvbuff_t *tvb, guint offset, proto_tree *tree)
972 {
973         proto_tree_add_item(tree, hf_s5066_11_remote_status, tvb, offset, 1, FALSE); offset++;
974         proto_tree_add_item(tree, hf_s5066_11_link_type, tvb, offset, 1, FALSE);
975         proto_tree_add_item(tree, hf_s5066_11_link_priority, tvb, offset, 1, FALSE);
976         proto_tree_add_item(tree, hf_s5066_11_sapid, tvb, offset, 1, FALSE); offset++;
977         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
978         return offset;
979 }
980
981 /* S_HARD_LINK_ACCEPT */
982 static guint
983 dissect_s5066_12(tvbuff_t *tvb, guint offset, proto_tree *tree)
984 {
985         proto_tree_add_item(tree, hf_s5066_12_link_type, tvb, offset, 1, FALSE);
986         proto_tree_add_item(tree, hf_s5066_12_link_priority, tvb, offset, 1, FALSE);
987         proto_tree_add_item(tree, hf_s5066_12_sapid, tvb, offset, 1, FALSE); offset++;
988         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
989         return offset;
990 }
991
992 /* S_HARD_LINK_REJECT */
993 static guint
994 dissect_s5066_13(tvbuff_t *tvb, guint offset, proto_tree *tree)
995 {
996         proto_tree_add_item(tree, hf_s5066_13_reason, tvb, offset, 1, FALSE); offset++;
997         proto_tree_add_item(tree, hf_s5066_13_link_type, tvb, offset, 1, FALSE);
998         proto_tree_add_item(tree, hf_s5066_13_link_priority, tvb, offset, 1, FALSE);
999         proto_tree_add_item(tree, hf_s5066_13_sapid, tvb, offset, 1, FALSE); offset++;
1000         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1001         return offset;
1002 }
1003
1004 /* S_SUBNET_AVAILABILITY */
1005 static guint
1006 dissect_s5066_14(tvbuff_t *tvb, guint offset, proto_tree *tree)
1007 {
1008         proto_tree_add_item(tree, hf_s5066_14_status, tvb, offset, 1, FALSE); offset++;
1009         proto_tree_add_item(tree, hf_s5066_14_reason, tvb, offset, 1, FALSE); offset++;
1010         return offset;
1011 }
1012
1013 /* Following three commented out: do nothing and cause <variable not used> messages. */
1014 /* S_DATA_FLOW_ON */
1015 /*
1016 static guint
1017 dissect_s5066_15(tvbuff_t *tvb, guint offset, proto_tree *tree)
1018 {
1019         return offset;
1020 }
1021 */
1022
1023 /* S_DATA_FLOW_OFF */
1024 /*
1025 static guint
1026 dissect_s5066_16(tvbuff_t *tvb, guint offset, proto_tree *tree)
1027 {
1028         return offset;
1029 }
1030 */
1031
1032 /* S_KEEP_ALIVE */
1033 /*
1034 static guint
1035 dissect_s5066_17(tvbuff_t *tvb, guint offset, proto_tree *tree)
1036 {
1037         return offset;
1038 }
1039 */
1040
1041 /* S_MANAGEMENT_MESSAGE_REQUEST */
1042 static guint
1043 dissect_s5066_18(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
1044 {
1045         guint body_size = 0;
1046         proto_tree_add_item(tree, hf_s5066_18_type, tvb, offset, 1, FALSE); offset++;
1047         body_size = pdu_size - offset;
1048         proto_tree_add_item(tree, hf_s5066_18_body, tvb, offset, body_size, FALSE); offset += body_size;
1049         return offset;
1050 }
1051
1052 /* S_MANAGEMENT_MESSAGE_INDICATION */
1053 static guint
1054 dissect_s5066_19(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
1055 {
1056         guint body_size = 0;
1057         proto_tree_add_item(tree, hf_s5066_19_type, tvb, offset, 1, FALSE); offset++;
1058         body_size = pdu_size - offset;
1059         proto_tree_add_item(tree, hf_s5066_19_body, tvb, offset, body_size, FALSE); offset += body_size;
1060         return offset;
1061 }
1062
1063 /* S_UNIDATA_REQUEST */
1064 static guint
1065 dissect_s5066_20(tvbuff_t *tvb, guint offset, proto_tree *tree)
1066 {
1067         proto_tree_add_item(tree, hf_s5066_20_priority, tvb, offset, 1, FALSE);
1068         proto_tree_add_item(tree, hf_s5066_20_sapid, tvb, offset, 1, FALSE); offset++;
1069         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1070         offset = dissect_s5066_servicetype(tvb, offset, tree);
1071         proto_tree_add_item(tree, hf_s5066_20_ttl, tvb, offset, 3, FALSE); offset += 3;
1072         proto_tree_add_item(tree, hf_s5066_20_size, tvb, offset, 2, FALSE); offset += 2;
1073
1074         return offset;
1075 }
1076
1077 /* S_UNIDATA_INDICATION */
1078 static guint
1079 dissect_s5066_21(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
1080 {
1081         guint i=0;
1082         proto_item *ti = NULL;
1083         guint d_pdu_size = 0;
1084         guint8 tx_mode = 0;
1085         guint16 no_err_blocks = 0;
1086         guint16 no_nrx_blocks = 0;
1087         gboolean non_arq_w_errors = FALSE;
1088
1089         proto_tree_add_item(tree, hf_s5066_21_priority, tvb, offset, 1, FALSE);
1090         proto_tree_add_item(tree, hf_s5066_21_dest_sapid, tvb, offset, 1, FALSE); offset++;
1091         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1092
1093         tx_mode = tvb_get_guint8(tvb, offset);
1094         tx_mode = (tx_mode & 0xF0) >> 4;
1095         if (tx_mode == 3) {
1096                 non_arq_w_errors = TRUE;
1097         }
1098
1099         proto_tree_add_item(tree, hf_s5066_21_tx_mode, tvb, offset, 1, FALSE);
1100         proto_tree_add_item(tree, hf_s5066_21_src_sapid, tvb, offset, 1, FALSE); offset++;
1101         offset = dissect_s5066_address(tvb, offset, tree, TRUE);
1102
1103         d_pdu_size = tvb_get_ntohs(tvb, offset);
1104         proto_tree_add_item(tree, hf_s5066_21_size, tvb, offset, 2, FALSE); offset += 2;
1105
1106         /* Handle RockwellCollins (<= v2.1) 4-byte offset */
1107         if ( (pdu_size - offset) == (d_pdu_size + 4) ) {
1108                 ti = proto_tree_add_item(tree, hf_s5066_21_err_blocks, tvb, offset, 2, FALSE); offset += 2;
1109                 proto_item_append_text(ti, ", (Field should not be present. Rockwell Collins v2.1 or earlier.) ");
1110                 ti = proto_tree_add_item(tree, hf_s5066_21_nrx_blocks, tvb, offset, 2, FALSE); offset += 2;
1111                 proto_item_append_text(ti, ", (Field should not be present. Rockwell Collins v2.1 or earlier.) ");
1112         }
1113         /* Handle Non-ARQ with errors */
1114         if ( non_arq_w_errors ) {
1115                 no_err_blocks = tvb_get_ntohs(tvb, offset);
1116                 proto_tree_add_item(tree, hf_s5066_21_err_blocks, tvb, offset, 2, FALSE); offset += 2;
1117                 for (i=0; i<no_err_blocks; i++) {
1118                         proto_tree_add_item(tree, hf_s5066_21_err_ptr, tvb, offset, 2, FALSE); offset += 2;
1119                         proto_tree_add_item(tree, hf_s5066_21_err_size, tvb, offset, 2, FALSE); offset += 2;
1120                 }
1121                 no_nrx_blocks = tvb_get_ntohs(tvb, offset);
1122                 proto_tree_add_item(tree, hf_s5066_21_nrx_blocks, tvb, offset, 2, FALSE); offset += 2;
1123                 for (i=0; i<no_nrx_blocks; i++) {
1124                         proto_tree_add_item(tree, hf_s5066_21_nrx_ptr, tvb, offset, 2, FALSE); offset += 2;
1125                         proto_tree_add_item(tree, hf_s5066_21_nrx_size, tvb, offset, 2, FALSE); offset += 2;
1126                 }
1127         }
1128         return offset;
1129 }
1130
1131 /* S_UNIDATA_REQUEST_CONFIRM */
1132 static guint
1133 dissect_s5066_22(tvbuff_t *tvb, guint offset, proto_tree *tree)
1134 {
1135         guint pdu_size = 0;
1136         proto_tree_add_item(tree, hf_s5066_22_unused, tvb, offset, 1, FALSE);
1137         proto_tree_add_item(tree, hf_s5066_22_sapid, tvb, offset, 1, FALSE); offset++;
1138         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1139         pdu_size = tvb_get_ntohs(tvb, offset);
1140         proto_tree_add_item(tree, hf_s5066_22_size, tvb, offset, 2, FALSE); offset += 2;
1141         proto_tree_add_item(tree, hf_s5066_22_data, tvb, offset, pdu_size, FALSE); offset += pdu_size;
1142
1143         return offset;
1144 }
1145
1146 /* S_UNIDATA_REQUEST_REJECTED */
1147 static guint
1148 dissect_s5066_23(tvbuff_t *tvb, guint offset, proto_tree *tree)
1149 {
1150         guint pdu_size = 0;
1151         proto_tree_add_item(tree, hf_s5066_23_reason, tvb, offset, 1, FALSE);
1152         proto_tree_add_item(tree, hf_s5066_23_sapid, tvb, offset, 1, FALSE); offset++;
1153         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1154         pdu_size = tvb_get_ntohs(tvb, offset);
1155         proto_tree_add_item(tree, hf_s5066_23_size, tvb, offset, 2, FALSE); offset += 2;
1156         proto_tree_add_item(tree, hf_s5066_23_data, tvb, offset, pdu_size, FALSE); offset += pdu_size;
1157
1158         return offset;
1159 }
1160
1161 /* S_EXPEDITED_UNIDATA_REQUEST */
1162 static guint
1163 dissect_s5066_24(tvbuff_t *tvb, guint offset, proto_tree *tree)
1164 {
1165         proto_tree_add_item(tree, hf_s5066_24_unused, tvb, offset, 1, FALSE);
1166         proto_tree_add_item(tree, hf_s5066_24_sapid, tvb, offset, 1, FALSE); offset++;
1167         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1168         offset = dissect_s5066_servicetype(tvb, offset, tree);
1169         proto_tree_add_item(tree, hf_s5066_24_ttl, tvb, offset, 3, FALSE); offset += 3;
1170         proto_tree_add_item(tree, hf_s5066_24_size, tvb, offset, 2, FALSE); offset += 2;
1171
1172         return offset;
1173 }
1174
1175 /* S_EXPEDITED_UNIDATA_INDICATION */
1176 static guint
1177 dissect_s5066_25(tvbuff_t *tvb, guint offset, proto_tree *tree, guint pdu_size)
1178 {
1179         guint i=0;
1180         proto_item *ti = NULL;
1181         guint d_pdu_size = 0;
1182         guint8 tx_mode = 0;
1183         guint16 no_err_blocks = 0;
1184         guint16 no_nrx_blocks = 0;
1185         gboolean non_arq_w_errors = FALSE;
1186
1187         proto_tree_add_item(tree, hf_s5066_25_unused, tvb, offset, 1, FALSE);
1188         proto_tree_add_item(tree, hf_s5066_25_dest_sapid, tvb, offset, 1, FALSE); offset++;
1189         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1190
1191         tx_mode = tvb_get_guint8(tvb, offset);
1192         tx_mode = (tx_mode & 0xF0) >> 4;
1193         if (tx_mode == 3) {
1194                 non_arq_w_errors = TRUE;
1195         }
1196
1197         proto_tree_add_item(tree, hf_s5066_25_tx_mode, tvb, offset, 1, FALSE);
1198         proto_tree_add_item(tree, hf_s5066_25_src_sapid, tvb, offset, 1, FALSE); offset++;
1199         offset = dissect_s5066_address(tvb, offset, tree, TRUE);
1200
1201         d_pdu_size = tvb_get_ntohs(tvb, offset);
1202         proto_tree_add_item(tree, hf_s5066_25_size, tvb, offset, 2, FALSE); offset += 2;
1203
1204         /* Handle RockwellCollins (<= v2.1) 4-byte offset */
1205         if ( (pdu_size - offset) == (d_pdu_size + 4) ) {
1206                 ti = proto_tree_add_item(tree, hf_s5066_25_err_blocks, tvb, offset, 2, FALSE); offset += 2;
1207                 proto_item_append_text(ti, ", (Field should not be present. Rockwell Collins v2.1 or earlier.) ");
1208                 ti = proto_tree_add_item(tree, hf_s5066_25_nrx_blocks, tvb, offset, 2, FALSE); offset += 2;
1209                 proto_item_append_text(ti, ", (Field should not be present. Rockwell Collins v2.1 or earlier.) ");
1210         }
1211         /* Handle Non-ARQ with errors */
1212         if ( non_arq_w_errors ) {
1213                 no_err_blocks = tvb_get_ntohs(tvb, offset);
1214                 proto_tree_add_item(tree, hf_s5066_25_err_blocks, tvb, offset, 2, FALSE); offset += 2;
1215                 for (i=0; i<no_err_blocks; i++) {
1216                         proto_tree_add_item(tree, hf_s5066_25_err_ptr, tvb, offset, 2, FALSE); offset += 2;
1217                         proto_tree_add_item(tree, hf_s5066_25_err_size, tvb, offset, 2, FALSE); offset += 2;
1218                 }
1219                 no_nrx_blocks = tvb_get_ntohs(tvb, offset);
1220                 proto_tree_add_item(tree, hf_s5066_25_nrx_blocks, tvb, offset, 2, FALSE); offset += 2;
1221                 for (i=0; i<no_nrx_blocks; i++) {
1222                         proto_tree_add_item(tree, hf_s5066_25_nrx_ptr, tvb, offset, 2, FALSE); offset += 2;
1223                         proto_tree_add_item(tree, hf_s5066_25_nrx_size, tvb, offset, 2, FALSE); offset += 2;
1224                 }
1225         }
1226         return offset;
1227 }
1228
1229 /* S_EXPEDITED_UNIDATA_REQUEST_CONFIRM */
1230 static guint
1231 dissect_s5066_26(tvbuff_t *tvb, guint offset, proto_tree *tree)
1232 {
1233         guint pdu_size = 0;
1234         proto_tree_add_item(tree, hf_s5066_26_unused, tvb, offset, 1, FALSE);
1235         proto_tree_add_item(tree, hf_s5066_26_sapid, tvb, offset, 1, FALSE); offset++;
1236         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1237         pdu_size = tvb_get_ntohs(tvb, offset);
1238         proto_tree_add_item(tree, hf_s5066_26_size, tvb, offset, 2, FALSE); offset += 2;
1239         proto_tree_add_item(tree, hf_s5066_26_data, tvb, offset, pdu_size, FALSE); offset += pdu_size;
1240
1241         return offset;
1242 }
1243
1244 /* S_EXPEDITED_UNIDATA_REQUEST_REJECTED */
1245 static guint
1246 dissect_s5066_27(tvbuff_t *tvb, guint offset, proto_tree *tree)
1247 {
1248         guint pdu_size = 0;
1249         proto_tree_add_item(tree, hf_s5066_27_reason, tvb, offset, 1, FALSE);
1250         proto_tree_add_item(tree, hf_s5066_27_sapid, tvb, offset, 1, FALSE); offset++;
1251         offset = dissect_s5066_address(tvb, offset, tree, FALSE);
1252         pdu_size = tvb_get_ntohs(tvb, offset);
1253         proto_tree_add_item(tree, hf_s5066_27_size, tvb, offset, 2, FALSE); offset += 2;
1254         proto_tree_add_item(tree, hf_s5066_27_data, tvb, offset, pdu_size, FALSE); offset += pdu_size;
1255
1256         return offset;
1257 }
1258
1259 static guint
1260 get_s5066_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1261 {
1262   guint16 plen;
1263
1264   /* Get the length of the S5066 PDU. */
1265   plen = tvb_get_ntohs(tvb, offset + s5066_size_offset);
1266
1267   /* That length doesn't include the sync, version and length fields; add that in. */
1268   return plen + s5066_header_size;
1269 }
1270
1271 static void
1272 dissect_s5066_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1273 {
1274         /* Make sure there are enough bytes... */
1275         if (tvb_length(tvb) < 5)
1276                 return;
1277         /* Check if the first two bytes are 0x90 0xEB: if not,
1278            then this is not a S5066 PDU or an unreassembled one.
1279            The third byte is the STANAG 5066 version: Right now only 0x00 is defined. */
1280         if( (tvb_get_guint8(tvb, 0) != 0x90) ||
1281             (tvb_get_guint8(tvb, 1) != 0xEB) ||
1282             (tvb_get_guint8(tvb, 2) != 0x00) ) {
1283                 return;
1284         }
1285         tcp_dissect_pdus(tvb, pinfo, tree, s5066_desegment, s5066_header_size, get_s5066_pdu_len, dissect_s5066_common);
1286 }
1287
1288 static void
1289 dissect_s5066_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1290 {
1291         guint offset = 0;
1292         guint pdu_size = 0;
1293         proto_item *ti_s5066 = NULL;
1294         proto_item *ti_pdu = NULL;
1295         tvbuff_t *next_tvb;
1296         gint available_length = 0;
1297         gint reported_length = 0;
1298
1299         /* Determine PDU type to display in INFO column */
1300         guint8 pdu_type = tvb_get_guint8(tvb, s5066_header_size);
1301
1302         col_set_str(pinfo->cinfo, COL_PROTOCOL, "S5066");
1303         /* Clear out stuff in the info column, the add PDU type */
1304         col_clear(pinfo->cinfo, COL_INFO);
1305         if (check_col(pinfo->cinfo, COL_INFO)) {
1306                 col_add_fstr(pinfo->cinfo, COL_INFO, "PDU type %s", val_to_str(pdu_type, s5066_pdu_type, "Unknown (0x%02x)"));
1307         }
1308
1309         if (tree) { /* We are being asked for details */
1310                 proto_tree *s5066_tree = NULL;
1311                 proto_tree *s5066_tree_pdu = NULL;
1312
1313                 pdu_size = tvb_get_ntohs(tvb, s5066_size_offset) + s5066_header_size;
1314
1315                 ti_s5066 = proto_tree_add_item(tree, proto_s5066, tvb, 0, -1, FALSE);
1316                 proto_item_append_text(ti_s5066, ", PDU type %s", val_to_str(pdu_type, s5066_pdu_type, "Unknown (0x%02x)"));
1317                 s5066_tree = proto_item_add_subtree(ti_s5066, ett_s5066);
1318                 proto_tree_add_item(s5066_tree, hf_s5066_sync_word, tvb, offset, 2, FALSE); offset +=2;
1319                 if (!s5066_edition_one) {
1320                         proto_tree_add_item(s5066_tree, hf_s5066_version,   tvb, offset, 1, FALSE); offset++;
1321                 }
1322                 proto_tree_add_item(s5066_tree, hf_s5066_size,      tvb, offset, 2, FALSE); offset +=2;
1323                 ti_pdu = proto_tree_add_item(s5066_tree, hf_s5066_type, tvb, offset, 1, FALSE); offset++;
1324                 s5066_tree_pdu = proto_item_add_subtree(ti_pdu, ett_s5066_pdu);
1325                 switch (pdu_type) {
1326                 case  1: offset = dissect_s5066_01(tvb, offset, s5066_tree_pdu); break;
1327                 /* case  2: offset = dissect_s5066_02(tvb, offset, s5066_tree_pdu); break; */
1328                 case  3: offset = dissect_s5066_03(tvb, offset, s5066_tree_pdu); break;
1329                 case  4: offset = dissect_s5066_04(tvb, offset, s5066_tree_pdu); break;
1330                 case  5: offset = dissect_s5066_05(tvb, offset, s5066_tree_pdu); break;
1331                 case  6: offset = dissect_s5066_06(tvb, offset, s5066_tree_pdu); break;
1332                 case  7: offset = dissect_s5066_07(tvb, offset, s5066_tree_pdu); break;
1333                 case  8: offset = dissect_s5066_08(tvb, offset, s5066_tree_pdu); break;
1334                 case  9: offset = dissect_s5066_09(tvb, offset, s5066_tree_pdu); break;
1335                 case 10: offset = dissect_s5066_10(tvb, offset, s5066_tree_pdu); break;
1336                 case 11: offset = dissect_s5066_11(tvb, offset, s5066_tree_pdu); break;
1337                 case 12: offset = dissect_s5066_12(tvb, offset, s5066_tree_pdu); break;
1338                 case 13: offset = dissect_s5066_13(tvb, offset, s5066_tree_pdu); break;
1339                 case 14: offset = dissect_s5066_14(tvb, offset, s5066_tree_pdu); break;
1340                 /* case 15: offset = dissect_s5066_15(tvb, offset, s5066_tree_pdu); break; */
1341                 /* case 16: offset = dissect_s5066_16(tvb, offset, s5066_tree_pdu); break; */
1342                 /* case 17: offset = dissect_s5066_17(tvb, offset, s5066_tree_pdu); break; */
1343                 case 18: offset = dissect_s5066_18(tvb, offset, s5066_tree_pdu, pdu_size); break;
1344                 case 19: offset = dissect_s5066_19(tvb, offset, s5066_tree_pdu, pdu_size); break;
1345                 case 20: offset = dissect_s5066_20(tvb, offset, s5066_tree_pdu); break;
1346                 case 21: offset = dissect_s5066_21(tvb, offset, s5066_tree_pdu, pdu_size); break;
1347                 case 22: offset = dissect_s5066_22(tvb, offset, s5066_tree_pdu); break;
1348                 case 23: offset = dissect_s5066_23(tvb, offset, s5066_tree_pdu); break;
1349                 case 24: offset = dissect_s5066_24(tvb, offset, s5066_tree_pdu); break;
1350                 case 25: offset = dissect_s5066_25(tvb, offset, s5066_tree_pdu, pdu_size); break;
1351                 case 26: offset = dissect_s5066_26(tvb, offset, s5066_tree_pdu); break;
1352                 case 27: offset = dissect_s5066_27(tvb, offset, s5066_tree_pdu); break;
1353                 }
1354         }
1355         proto_item_set_len(ti_s5066, offset);
1356
1357         /* Call sub dissector(s) */
1358         reported_length = pdu_size - offset;
1359         available_length = tvb_length(tvb) - offset;
1360
1361         next_tvb = tvb_new_subset(tvb, offset, MIN(available_length, reported_length), reported_length);
1362         call_dissector(data_handle, next_tvb, pinfo, tree);
1363
1364         return;
1365 }