2 * By Mathias Guettler <guettler@web.de>
5 * Routines for ATN upper layer
6 * protocol packet disassembly
8 * ATN upper layers are embedded within OSI Layer 4 (COTP).
10 * ATN upper layers contain:
11 * Session Layer (NUL protocol option)
12 * Presentation Layer (NUL protocol option)
13 * ATN upper Layer/Application (ACSE PDU or PDV-list PDU)
15 * ATN applications protocols (i.e. CM or CPDLC) are contained within
16 * ACSE user-information or PDV presentation data.
19 * https://en.wikipedia.org/wiki/CPDLC
20 * https://members.optusnet.com.au/~cjr/introduction.htm
23 * We are dealing with ATN/ULCS aka ICAO Doc 9705 Second Edition here
24 * (don't think there is an ULCS equivalent for "FANS-1/A ").
25 * https://www.icao.int/safety/acp/repository/_%20Doc9705_ed2_1999.pdf
27 * Wireshark - Network traffic analyzer
28 * By Gerald Combs <gerald@wireshark.org>
29 * Copyright 1998 Gerald Combs
31 * SPDX-License-Identifier: GPL-2.0-or-later
36 why not using existing ses, pres and acse dissectors ?
37 ATN upper layers are derived from OSI standards for session,
38 presentation and application but the encoding differs
39 (it's PER instead of BER encoding to save bandwidth).
40 Session and presentation use the "null" encoding option,
41 meaning that they are only present at connection establishment
42 and omitted otherwise.
43 Instead of adapting existing dissectors it seemed simpler and cleaner
44 to implement everything the new atn-ulcs dissector.
46 why using conversations ?
47 PER encoded user data is ambigous; the same encoding may apply to a CM or
48 CPDLC PDU. The workaround is to decode on a transport connection basis.
49 I use my own version of conversations to identify
50 the transport connection the PDU belongs to for the standard functions
51 from "conversation.h" didn't work out.
53 what is the use of AARQ/AARE data ?
54 Converstions should be maintained on the COTP layer in a standard way
55 for there are usually more packets available than in the layers above.
56 In the worst case my dissector is called from a DT packet which
57 has destination references but no source reference.
58 I have to guess the reference used the other way round
59 (curently I am using ACSE PDU'S used during OSI connection establishment for that).
60 The idea is that each ACSE AARQ is answered by ACSE AARE and having this sequence
61 I have all the source/destination references for this transport connection.
62 I use AARQ/AARE data to store the source/destination reference of AARQ as well
63 as the optional ae-qualifier which tells me the application and
64 the dissector I have to use.
65 This approach donesn't work well when there are interleaving AARQ/AARE sequences for
68 which ATN standard is supported ?
69 The dissector has been tested with ICAO doc9705 Edition2 compliant traffic.
70 No ATN Secutity is supported.
72 The ATN upper layers are derived from OSI standards (ICAO DOC 9705)
73 while ATN/IPS (ICAO DOC 9896) which is entirely based on IPV6.
78 known defects/deficiencies:
80 - user-information within AARE is sometines not decoded due to an unset flag
81 (the field is optional). As far as I can tell asn2wrs is right here,
82 but on the other hand I know that in all of this cases user-information
83 is present and is processed by the ATN end system.
84 Maybe a true ATN expert may help me out here.
86 - The conversation handling is based on src/dst addresses as well as
87 source or destination references depending on the TP4 packet type.
88 This means that after some time these references get reused for
89 new conversations. This almost certain happens for traces longer
90 than one day rendering this dissector unsuitable for captures exceeding
102 #include <epan/packet.h>
103 #include <epan/address.h>
104 #include <epan/conversation.h>
105 #include <wsutil/array.h>
106 #include <epan/osi-utils.h>
107 #include "packet-ber.h"
108 #include "packet-per.h"
109 #include "packet-atn-ulcs.h"
111 #define ATN_ACSE_PROTO "ICAO Doc9705 ULCS ACSE (ISO 8649/8650-1:1996)"
112 #define ATN_ULCS_PROTO "ICAO Doc9705 ULCS"
114 void proto_register_atn_ulcs(void);
115 void proto_reg_handoff_atn_ulcs(void);
117 static heur_dissector_list_t atn_ulcs_heur_subdissector_list
;
119 /* presentation subdissectors i.e. CM, CPDLC */
120 static dissector_handle_t atn_cm_handle
;
121 static dissector_handle_t atn_cpdlc_handle
;
123 static int proto_atn_ulcs
;
124 static uint32_t ulcs_context_value
;
125 static const char *object_identifier_id
;
127 static wmem_tree_t
*aarq_data_tree
;
128 static wmem_tree_t
*atn_conversation_tree
;
131 static proto_tree
*root_tree
;
133 /* forward declarations for functions generated from asn1 */
134 static int dissect_atn_ulcs_T_externalt_encoding_single_asn1_type(
137 asn1_ctx_t
*actx _U_
,
138 proto_tree
*tree _U_
,
142 static int dissect_atn_ulcs_T_externalt_encoding_octet_aligned(
145 asn1_ctx_t
*actx _U_
,
146 proto_tree
*tree _U_
,
149 static int dissect_atn_ulcs_T_externalt_encoding_arbitrary(
152 asn1_ctx_t
*actx _U_
,
153 proto_tree
*tree _U_
,
156 static int dissect_ACSE_apdu_PDU(
158 packet_info
*pinfo _U_
,
159 proto_tree
*tree _U_
,
162 uint32_t dissect_per_object_descriptor_t(
168 tvbuff_t
**value_tvb
);
170 static int dissect_atn_ulcs(
176 #include "packet-atn-ulcs-hf.c"
178 #include "packet-atn-ulcs-ett.c"
179 static int ett_atn_ulcs
;
180 static int ett_atn_acse
;
182 #include "packet-atn-ulcs-fn.c"
185 /* re-implementing external data: packet-per.c */
186 static const value_string per_External_encoding_vals
[] = {
187 { 0, "single-ASN1-type" },
188 { 1, "octet-aligned" },
193 /* re-implementing external data: packet-per.c */
194 static const per_choice_t External_encoding_choice
[] =
197 &hf_atn_ulcs_externalt_encoding_single_asn1_type
,
199 dissect_atn_ulcs_T_externalt_encoding_single_asn1_type
202 &hf_atn_ulcs_externalt_encoding_octet_aligned
,
204 dissect_atn_ulcs_T_externalt_encoding_octet_aligned
207 &hf_atn_ulcs_externalt_encoding_arbitrary
,
209 dissect_atn_ulcs_T_externalt_encoding_arbitrary
219 /* ATN Session layer */
220 #define SES_PDU_TYPE_MASK 0xf8
221 #define SES_PARAM_IND_MASK 0x04
222 #define SES_PARAM_B2_MASK 0x02
223 #define SES_PARAM_B1_MASK 0x01
225 static int hf_atn_ses_type
;
226 static int hf_atn_ses_param_ind
;
227 static int hf_atn_ses_param_b1
;
228 static int hf_atn_ses_param_b2
;
230 static int ett_atn_ses
;
232 #define ATN_SES_PROTO "ICAO Doc9705 ULCS Session (ISO 8326/8327-1:1994)"
234 static const value_string atn_ses_param_ind
[] =
236 {0, "No Parameter Indication "},
237 {1, "Parameter Indication "},
241 static const value_string srf_b2
[] =
243 {0, "Transport Connection is kept"},
244 {1, "Transport Connection is released" },
248 static const value_string srf_b1
[] =
250 {0, "Transport Connection is transient"},
251 {1, "Transport Connection is persistent"},
255 #define SES_ATN_SCN 0xe8
256 #define SES_ATN_SCNC 0xf8
257 #define SES_ATN_SAC 0xf0
258 #define SES_ATN_SACC 0xd8
259 #define SES_ATN_SRF 0xe0
260 #define SES_ATN_SRFC 0xa0
262 static const value_string atn_ses_type
[] =
264 { 0x1d, "Short Connect (SCN) SPDU" },
265 { 0x1f, "Short Connect Accept (SAC) SPDU" },
266 { 0x1e, "Short Connect Accept Continue (SACC) SPDU" },
267 { 0x1c, "Short Refuse (SRF) SPDU" },
268 { 0x14, "Short Refuse Continue (SRFC) SPDU" },
272 /* ATN Presentation layer */
273 #define ATN_PRES_PROTO "ICAO Doc9705 ULCS Presentation (ISO 8822/8823-1:1994)"
275 static int hf_atn_pres_err
;
276 static int hf_atn_pres_pdu_type
;
277 static int ett_atn_pres
;
279 #define ATN_SES_PRES_MASK 0xf803
280 #define PRES_CPR_ER_MASK 0x70
282 /* type determined by SPDU and PPDU */
283 static const value_string atn_pres_vals
[] =
285 { 0xe802, "Short Presentation Connect PPDU (CP) " },
286 { 0xf802, "Short Presentation Connect PPDU (CP) " },
287 { 0xf002, "Short Presentation Connect Accept PPDU (CPA)" },
288 { 0xd802, "Short Presentation Connect Accept PPDU (CPA)" },
289 { 0xe002, "Short Presentation Connect Reject PPDU (CPR)" },
290 { 0xa002, "Short Presentation Connect Reject PPDU (CPR)" },
294 /* Short Presentation Connect Reject PPDU's 0yyy 00zz */
295 static const value_string atn_pres_err
[] =
297 { 0x00, "Presentation-user" },
298 { 0x01, "Reason not specified (transient)"},
299 { 0x02, "Temporary congestion (transient)"},
300 { 0x03, "Local limit exceeded (transient)"},
301 { 0x04, "Called presentation-address unknown (permanent)"},
302 { 0x05, "Protocol version not supported (permanent)"},
303 { 0x06, "Default context not supported (permanent)"},
304 { 0x07, "User data not readable (permanent)"},
309 /* re-implementing external data: packet-per.c */
310 static int atn_ulcs_Externalt_encoding(
313 asn1_ctx_t
*actx _U_
,
314 proto_tree
*tree _U_
,
317 offset
= dissect_per_choice(
323 ett_atn_ulcs_EXTERNALt
,
324 External_encoding_choice
,
325 &actx
->external
.encoding
);
330 /* re-implementing external data: packet-per.c */
331 static uint32_t atn_per_external_type(
335 proto_tree
*tree _U_
,
339 memset(&actx
->external
, '\0', sizeof(actx
->external
));
340 actx
->external
.hf_index
= -1;
341 actx
->external
.encoding
= -1;
343 actx
->external
.u
.per
.type_cb
= type_cb
;
344 offset
= atn_ulcs_Externalt_encoding(
354 sizeof(actx
->external
));
356 actx
->external
.hf_index
= -1;
357 actx
->external
.encoding
= -1;
363 /* determine 24-bit aircraft address(ARS) */
364 /* from 20-byte ATN NSAP. */
365 uint32_t get_aircraft_24_bit_address_from_nsap(
368 const uint8_t* addr
= NULL
;
370 uint32_t adr_prefix
=0;
372 /* check NSAP address type*/
373 if( (pinfo
->src
.type
!= get_osi_address_type()) ||
374 (pinfo
->dst
.type
!= get_osi_address_type())) {
377 /* 20 octets address length required */
379 if( (pinfo
->src
.len
!= 20) ||
380 (pinfo
->dst
.len
!= 20)) {
383 /* first try source address */
384 /* if the src address originates */
385 /* from an aircraft it's downlink */
387 /* convert addr into 32-bit integer */
388 addr
= (const uint8_t *)pinfo
->src
.data
;
395 /* according to ICAO doc9507 Ed2 SV5 */
396 /* clause 5.4.3.8.1.5 and 5.4.3.8.1.3 */
397 /* mobile addresses contain "c1" of "41" */
398 /* in the VER subfield of the NSAP */
399 if((adr_prefix
== 0x470027c1) ||
400 (adr_prefix
== 0x47002741)) {
401 /* ICAO doc9507 Ed2 SV5 5.4.3.8.4.4 */
402 /* states that the ARS subfield contains */
403 /* the 24-bitaddress of the aircraft */
404 ars
= ((addr
[8])<<16) |
409 /* try destination address */
410 /* if the src address originates */
411 /* from an aircraft it's downlink */
413 /* convert addr into 32-bit integer */
414 addr
= (const uint8_t *)pinfo
->dst
.data
;
415 adr_prefix
= ((addr
[0]<<24) |
420 /* according to ICAO doc9507 Ed2 SV5 */
421 /* clause 5.4.3.8.1.5 and 5.4.3.8.1.3 */
422 /* mobile addresses contain "c1" of "41" */
423 /* in the VER subfield of the NSAP */
424 if((adr_prefix
== 0x470027c1) ||
425 (adr_prefix
== 0x47002741)) {
426 /* ICAO doc9507 Ed2 SV5 5.4.3.8.4.4 */
427 /* states that the ARS subfield contains */
428 /* the 24-bitaddress of the aircraft */
429 ars
= ((addr
[8])<<16) |
436 /* determine whether a PDU is uplink or downlink */
437 /* by checking for known aircraft address prefixes*/
438 int check_heur_msg_type(packet_info
*pinfo _U_
)
441 const uint8_t* addr
= NULL
;
442 uint32_t adr_prefix
=0;
444 /* check NSAP address type*/
445 if( (pinfo
->src
.type
!= get_osi_address_type()) || (pinfo
->dst
.type
!= get_osi_address_type())) {
448 /* check NSAP address length; 20 octets address length required */
449 if( (pinfo
->src
.len
!= 20) || (pinfo
->dst
.len
!= 20)) {
452 addr
= (const uint8_t *)pinfo
->src
.data
;
454 /* convert address to 32-bit integer */
455 adr_prefix
= ((addr
[0]<<24) | (addr
[1]<<16) | (addr
[2]<<8) | addr
[3] );
457 /* According to the published ATN NSAP adddressing scheme */
458 /* in ICAO doc9705 Ed2 SV5 5.4.3.8.1.3 and 5.4.3.8.1.5 */
459 /* the "VER" field shall be 0x41 ("all Mobile AINSC") or */
460 /* 0xc1 ("all Mobile ATSC") for mobile stations (aka aircraft).*/
461 if((adr_prefix
== 0x470027c1) || (adr_prefix
== 0x47002741)) {
462 t
= dm
; /* source is an aircraft: it's a downlink PDU */
465 addr
= (const uint8_t *)pinfo
->dst
.data
;
467 /* convert address to 32-bit integer */
468 adr_prefix
= ((addr
[0]<<24) | (addr
[1]<<16) | (addr
[2]<<8) | addr
[3] );
470 /* According to the published ATN NSAP adddressing scheme */
471 /* in ICAO doc9705 Ed2 SV5 5.4.3.8.1.3 and 5.4.3.8.1.5 */
472 /* the "VER" field shall be 0x41 ("all Mobile AINSC") or */
473 /* 0xc1 ("all Mobile ATSC") for mobile stations (aka aircraft).*/
474 if((adr_prefix
== 0x470027c1) || (adr_prefix
== 0x47002741)) {
475 t
= um
; /* destination is aircraft: uplink PDU */
481 /* conversation may be used by other dissectors */
482 wmem_tree_t
*get_atn_conversation_tree(void){
483 return atn_conversation_tree
;
487 /* find a atn conversation tree node by an endpoint */
488 /* an endpoint is identified by atn src and dst addresses */
489 /* and srcref or dstref (depends on the transport packet type) */
490 /* IMHO it's a hack - conversations should be maintained */
491 /* at transport layer (cotp) but this isn't working yet. */
492 atn_conversation_t
* find_atn_conversation(
497 atn_conversation_t
*cv
= NULL
;
501 tmp
= add_address_to_hash( tmp
, address1
);
502 key
= (tmp
<< 16) | clnp_ref1
;
504 tmp
= add_address_to_hash( tmp
, address2
);
505 key
= (tmp
<< 24) | key
;
507 /* search for atn conversation */
508 cv
= (atn_conversation_t
*)
509 wmem_tree_lookup32(get_atn_conversation_tree(),key
);
514 /* create a atn conversation tree node */
515 /* conversation data is to be allocated externally */
516 /* a conversation may be referenced from both endpoints */
517 atn_conversation_t
* create_atn_conversation(
521 atn_conversation_t
*conversation
)
523 atn_conversation_t
*cv
= NULL
;
527 tmp
= add_address_to_hash( tmp
, address1
);
528 key
= (tmp
<< 16) | clnp_ref1
;
530 tmp
= add_address_to_hash( tmp
, address2
);
531 key
= (tmp
<< 24) | key
;
533 /* search for aircraft entry */
534 cv
= (atn_conversation_t
*)
536 get_atn_conversation_tree(),
539 /* tree node already present */
543 /* insert conversation data in tree*/
545 get_atn_conversation_tree(),
547 (void*)conversation
);
560 proto_item
*ti
= NULL
;
561 proto_tree
*atn_ulcs_tree
= NULL
;
562 uint8_t value_pres
= 0;
563 uint8_t value_ses
= 0;
564 uint16_t value_ses_pres
= 0;
569 /* decode as PDV-list */
570 if ( (int)(intptr_t) data
== false )
572 ti
= proto_tree_add_item(
580 atn_ulcs_tree
= proto_item_add_subtree(
584 dissect_Fully_encoded_data_PDU(
587 atn_ulcs_tree
, NULL
);
590 tvb_reported_length_remaining(tvb
, offset
) ;
593 /* decode as SPDU, PPDU and ACSE PDU */
594 if ( (int)(intptr_t) data
== true )
596 /* get session and presentation PDU's */
597 value_ses_pres
= tvb_get_ntohs(tvb
, offset
);
599 /* SPDU: dissect session layer */
600 atn_ulcs_tree
= proto_tree_add_subtree(
601 tree
, tvb
, offset
, 0,
602 ett_atn_ses
, NULL
, ATN_SES_PROTO
);
604 /* get SPDU (1 octet) */
605 value_ses
= tvb_get_uint8(tvb
, offset
);
607 /* SPDU type/identifier */
608 proto_tree_add_item(atn_ulcs_tree
,
615 /* SPDU parameters may be present in Short Refuse */
616 /* or Short Refuse Continue SPDU's */
617 switch(value_ses
& SES_PDU_TYPE_MASK
){
621 /* SPDU parameter presence */
622 proto_tree_add_item(atn_ulcs_tree
,
623 hf_atn_ses_param_ind
,
630 proto_tree_add_item(atn_ulcs_tree
,
638 proto_tree_add_item(atn_ulcs_tree
,
651 /* PPDU: dissect presentation layer */
652 atn_ulcs_tree
= proto_tree_add_subtree(
653 tree
, tvb
, offset
, 0,
654 ett_atn_pres
, NULL
, ATN_PRES_PROTO
);
656 value_pres
= tvb_get_uint8(tvb
, offset
);
658 /* need session context to identify PPDU type */
660 proto_tree_add_uint_format(atn_ulcs_tree
, hf_atn_pres_pdu_type
,
666 val_to_str_const( value_ses_pres
& ATN_SES_PRES_MASK
, atn_pres_vals
, "?"),
669 /* PPDU errorcode in case of SRF/CPR */
670 switch(value_ses
& SES_PDU_TYPE_MASK
){
687 /* ACSE PDU: dissect application layer */
688 atn_ulcs_tree
= proto_tree_add_subtree(
689 tree
, tvb
, offset
, 0,
690 ett_atn_acse
, NULL
, ATN_ACSE_PROTO
);
692 dissect_ACSE_apdu_PDU(
693 tvb_new_subset_remaining(tvb
, offset
),
695 atn_ulcs_tree
, NULL
);
698 tvb_reported_length_remaining(tvb
, offset
);
703 static bool dissect_atn_ulcs_heur(
709 /* do we have enough data*/
710 /* at least session + presentation data or pdv-list */
711 if (tvb_captured_length(tvb
) < 2){
714 /* check for session/presentation/ACSE PDU's */
715 /* SPDU and PPDU are one octet each */
716 switch( tvb_get_ntohs(tvb
, 0) & 0xf8ff ){
717 case 0xe802: /* SCN + CP*/
718 case 0xf802: /* SCNC + CP */
719 case 0xf002: /* SAC + CPA */
720 case 0xd802: /* SACC + CPA */
721 case 0xe002: /* SRF + CPR + R0 */
722 case 0xe012: /* SRF + CPR + R1 */
723 case 0xe022: /* SRF + CPR + R2 */
724 case 0xe032: /* SRF + CPR + R3 */
725 case 0xe042: /* SRF + CPR + R4 */
726 case 0xe052: /* SRF + CPR + R5 */
727 case 0xe062: /* SRF + CPR + R6 */
728 case 0xe072: /* SRF + CPR + R7 */
729 case 0xa002: /* SRFC + CPR + R0*/
730 case 0xa012: /* SRFC + CPR + R1*/
731 case 0xa022: /* SRFC + CPR + R2*/
732 case 0xa032: /* SRFC + CPR + R3*/
733 case 0xa042: /* SRFC + CPR + R4*/
734 case 0xa052: /* SRFC + CPR + R5*/
735 case 0xa062: /* SRFC + CPR + R6*/
736 case 0xa072: /* SRFC + CPR + R7*/
737 /* indicate to dissector routine */
738 /* that a least SPDU, PPDU and */
739 /* ACSE PDU is present */
746 default: /* no SPDU */
750 /* try to detect "Fully-encoded-data" heuristically */
751 /* the constants listed match the ASN.1 PER encoding */
753 switch( tvb_get_ntohs(tvb
, 0) & 0xfff0 ){
754 case 0x0020: /* acse-apdu */
755 case 0x00a0: /* user-ase-apdu */
756 /* indicate to dissector routine */
757 /* that a PDV-list PDU is present */
759 /* PDV-list PDU may contain */
760 /* application protocol data (CM, CPDLC) */
762 dissect_atn_ulcs(tvb
, pinfo
, tree
, (void*) false);
764 default: /* no or unsupported PDU */
770 void proto_register_atn_ulcs (void)
772 static hf_register_info hf_atn_ulcs
[] = {
773 #include "packet-atn-ulcs-hfarr.c"
781 "Indicates presence of session parameters",
783 {&hf_atn_ses_param_ind
,
784 { "SPDU Parameter Indication",
785 "atn-ulcs.ses.parameter-indication",
788 VALS(atn_ses_param_ind
),
790 "Indicates presence of session parameters",
792 {&hf_atn_ses_param_b1
,
793 { "SRF Parameter B1",
794 "atn-ulcs.ses.srf-b1",
799 "Determines if transport connection reject is transient or persistent",
801 {&hf_atn_ses_param_b2
,
802 { "SRF Parameter B2",
803 "atn-ulcs.ses.srf-b2",
808 "Determines if transport connection is retained or released",
811 { "Error Code", "atn-ulcs.pres.cpr-error",
818 { &hf_atn_pres_pdu_type
,
819 { "PDU type", "atn-ulcs.pres.pdu_type",
828 static int *ett
[] = {
829 #include "packet-atn-ulcs-ettarr.c"
836 proto_atn_ulcs
= proto_register_protocol (
841 proto_register_field_array (
844 array_length(hf_atn_ulcs
));
846 proto_register_subtree_array (
855 /* initiate sub dissector list */
856 atn_ulcs_heur_subdissector_list
= register_heur_dissector_list_with_description("atn-ulcs", "ATN-ULCS unhandled data", proto_atn_ulcs
);
858 /* init aare/aare data */
859 aarq_data_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
861 atn_conversation_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
864 void proto_reg_handoff_atn_ulcs(void)
866 atn_cm_handle
= find_dissector_add_dependency("atn-cm", proto_atn_ulcs
);
867 atn_cpdlc_handle
= find_dissector_add_dependency("atn-cpdlc", proto_atn_ulcs
);
869 /* add session dissector to cotp dissector list dissector list*/
872 dissect_atn_ulcs_heur
,
873 "ATN-ULCS over COTP",
875 proto_atn_ulcs
, HEURISTIC_ENABLE
);
879 * Editor modelines - https://www.wireshark.org/tools/modelines.html
884 * indent-tabs-mode: nil
887 * vi: set shiftwidth=4 tabstop=8 expandtab:
888 * :indentSize=4:tabSize=8:noTabs=true: