2 * Routines for ATSC3 LLS(Low Level Signalling) dissection
3 * Copyright 2023, Sergey V. Lobanov <sergey@lobanov.in>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * ATSC3 Signaling, Delivery, Synchronization, and Error Protection (A/331)
14 * https://www.atsc.org/atsc-documents/3312017-signaling-delivery-synchronization-error-protection/
16 * ATSC3 Security and Service Protection (A/360)
17 * https://www.atsc.org/atsc-documents/3602018-atsc-3-0-security-service-protection/
19 * ATSC Code Point Registry
20 * https://www.atsc.org/documents/code-point-registry/
24 #include <epan/expert.h>
25 #include <epan/packet.h>
27 #include "packet-lls.h"
29 #define LLS_PORT 4937 // IANA Registered (atsc-mh-ssc)
31 void proto_reg_handoff_lls(void);
32 void proto_register_lls(void);
36 static int ett_lls_smt_entry
;
37 static int ett_lls_smt_signature
;
38 static int ett_lls_table_payload
;
39 static int ett_lls_table_payload_xml
;
41 static dissector_handle_t lls_handle
;
42 static dissector_handle_t xml_handle
;
43 static dissector_handle_t cms_handle
;
45 static expert_field ei_lls_table_decompression_failed
;
47 static int hf_lls_table_id
;
48 #define LLS_TABLE_TYPE_SIGNED_MULTI_TABLE 0xFE
49 #define LLS_TABLE_TYPE_SLT 0x01
50 static const value_string hf_lls_table_type_vals
[] = {
51 { 0x01, "SLT (Service List Table)" },
52 { 0x02, "RRT (Rating Region Table)" },
53 { 0x03, "System Time" },
54 { 0x04, "AEAT (Advanced Emergency Information Table)" },
55 { 0x05, "On Screen Message Notification" },
56 { 0x06, "CDT (Certification Data Table)" },
57 { 0x07, "DRCT (Dedicated Return Channel Table)" },
58 { 0x80, "VIT (Version Information Table)" },
59 { 0x81, "CPT (Content Protection Table)" },
60 { 0x82, "CAP (Common Alerting Protocol)" },
61 { 0xFE, "Signed Multi Table" },
62 { 0xFF, "User Defined" },
65 static const value_string hf_lls_table_type_short_vals
[] = {
81 static int hf_lls_group_id
;
82 static int hf_lls_group_count
;
83 static int hf_lls_table_version
;
84 static int hf_lls_table_payload
;
85 static int hf_lls_table_payload_uncompressed
;
87 static int hf_lls_smt_payload_count
;
88 static int hf_lls_smt_entry
;
89 static int hf_lls_smt_entry_payload_length
;
90 static int hf_lls_smt_signature_length
;
91 static int hf_lls_smt_signature
;
95 dissect_lls_table_payload(uint8_t lls_table_id
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, int len
, proto_tree
*tree
)
97 proto_item
*ti
= proto_tree_add_item(tree
, hf_lls_table_payload
, tvb
, offset
, len
, ENC_NA
);
99 if (lls_table_id
== LLS_TABLE_TYPE_SIGNED_MULTI_TABLE
) {
100 /* Nested SignedMultiTable decoding is not specified in the standard */
104 proto_tree
*uncompress_tree
= proto_item_add_subtree(ti
, ett_lls_table_payload
);
105 tvbuff_t
*uncompress_tvb
= tvb_uncompress_zlib(tvb
, offset
, len
);
106 proto_tree
*xml_tree
= NULL
;
107 if (uncompress_tvb
) {
108 const char *table_type_short
= val_to_str_const(lls_table_id
, hf_lls_table_type_short_vals
, "Unknown");
109 char *source_name
= wmem_strdup_printf(pinfo
->pool
, "Table ID %u (%s)", lls_table_id
, table_type_short
);
110 add_new_data_source(pinfo
, uncompress_tvb
, source_name
);
111 unsigned decomp_length
= tvb_captured_length(uncompress_tvb
);
113 proto_item
*ti_uncomp
= proto_tree_add_item(uncompress_tree
, hf_lls_table_payload_uncompressed
, uncompress_tvb
, 0, decomp_length
, ENC_ASCII
);
114 proto_item_set_generated(ti_uncomp
);
117 xml_tree
= proto_item_add_subtree(ti_uncomp
, ett_lls_table_payload_xml
);
118 call_dissector(xml_handle
, uncompress_tvb
, pinfo
, xml_tree
);
121 expert_add_info(pinfo
, ti
, &ei_lls_table_decompression_failed
);
124 if (lls_table_id
== LLS_TABLE_TYPE_SLT
&& xml_tree
!= NULL
) {
125 lls_extract_save_slt_table(pinfo
, xml_handle
);
131 dissect_lls(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
133 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "LLS");
135 proto_item
*ti
= proto_tree_add_item(tree
, proto_lls
, tvb
, 0, -1, ENC_NA
);
136 proto_tree
*lls_tree
= proto_item_add_subtree(ti
, ett_lls
);
140 uint8_t lls_table_id
= tvb_get_uint8(tvb
, offset
);
141 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(lls_table_id
, hf_lls_table_type_vals
, "Unknown"));
142 proto_tree_add_item(lls_tree
, hf_lls_table_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
145 proto_tree_add_item(lls_tree
, hf_lls_group_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
148 uint16_t lls_group_count
= tvb_get_uint8(tvb
, offset
) + 1;
149 PROTO_ITEM_SET_GENERATED(
150 proto_tree_add_uint(lls_tree
, hf_lls_group_count
, tvb
, offset
, 1, lls_group_count
)
154 proto_tree_add_item(lls_tree
, hf_lls_table_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
157 if (lls_table_id
== LLS_TABLE_TYPE_SIGNED_MULTI_TABLE
) {
158 uint8_t smt_payload_count
= tvb_get_uint8(tvb
, offset
);
159 proto_tree_add_item(lls_tree
, hf_lls_smt_payload_count
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
162 for(uint8_t i
= 0; i
< smt_payload_count
; i
++) {
163 uint16_t smt_entry_payload_length
= tvb_get_uint16(tvb
, offset
+ 2, ENC_BIG_ENDIAN
);
164 proto_item
*smt_entry_item
= proto_tree_add_item(lls_tree
, hf_lls_smt_entry
, tvb
, offset
, smt_entry_payload_length
+ 4, ENC_NA
);
165 proto_tree
*smt_entry_tree
= proto_item_add_subtree(smt_entry_item
, ett_lls_smt_entry
);
167 uint8_t smt_entry_table_id
= tvb_get_uint8(tvb
, offset
);
168 const char *table_type_short
= val_to_str_const(smt_entry_table_id
, hf_lls_table_type_short_vals
, "Unknown");
169 proto_item_append_text(smt_entry_item
, " (%u) Table ID=%u (%s)", i
, smt_entry_table_id
, table_type_short
);
170 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "/%s", table_type_short
);
171 proto_tree_add_item(smt_entry_tree
, hf_lls_table_id
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
174 proto_tree_add_item(smt_entry_tree
, hf_lls_table_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
177 proto_tree_add_item(smt_entry_tree
, hf_lls_smt_entry_payload_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
180 dissect_lls_table_payload(smt_entry_table_id
, tvb
, pinfo
, offset
, smt_entry_payload_length
, smt_entry_tree
);
181 offset
+= smt_entry_payload_length
;
184 uint16_t smt_signature_length
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
185 proto_tree_add_item(lls_tree
, hf_lls_smt_signature_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
188 proto_item
*smt_signature_item
= proto_tree_add_item(lls_tree
, hf_lls_smt_signature
, tvb
, offset
, smt_signature_length
, ENC_NA
);
190 proto_tree
*cms_tree
= proto_item_add_subtree(smt_signature_item
, ett_lls_smt_signature
);
191 tvbuff_t
*cms_tvb
= tvb_new_subset_length(tvb
, offset
, smt_signature_length
);
193 /* CMS dissector removes useful info from Protocol and Info columns so store it */
194 char *col_info_text
= wmem_strdup(pinfo
->pool
, col_get_text(pinfo
->cinfo
, COL_INFO
));
195 char *col_protocol_text
= wmem_strdup(pinfo
->pool
, col_get_text(pinfo
->cinfo
, COL_PROTOCOL
));
197 call_dissector(cms_handle
, cms_tvb
, pinfo
, cms_tree
);
199 /* Restore Protocol and Info columns */
200 col_set_str(pinfo
->cinfo
, COL_INFO
, col_info_text
);
201 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, col_protocol_text
);
204 int table_payload_length
= tvb_captured_length(tvb
) - 4;
205 dissect_lls_table_payload(lls_table_id
, tvb
, pinfo
, offset
, table_payload_length
, lls_tree
);
208 return tvb_captured_length(tvb
);
212 proto_register_lls(void)
214 static hf_register_info hf
[] = {
215 { &hf_lls_table_id
, {
216 "Table ID", "lls.table.id",
217 FT_UINT8
, BASE_DEC
, VALS(hf_lls_table_type_vals
), 0, NULL
, HFILL
219 { &hf_lls_group_id
, {
220 "Group ID", "lls.group.id",
221 FT_UINT8
, BASE_DEC
, 0, 0, NULL
, HFILL
223 { &hf_lls_group_count
, {
224 "Group Count", "lls.group.count",
225 FT_UINT16
, BASE_DEC
, 0, 0, NULL
, HFILL
227 { &hf_lls_table_version
, {
228 "Table Version", "lls.table.version",
229 FT_UINT8
, BASE_DEC
, 0, 0, NULL
, HFILL
231 { &hf_lls_table_payload
, {
232 "Table Payload", "lls.table.payload",
233 FT_NONE
, BASE_NONE
, 0, 0, NULL
, HFILL
235 { &hf_lls_table_payload_uncompressed
, {
236 "Table Payload Uncompressed", "lls.table.payload.uncompressed",
237 FT_STRING
, BASE_NONE
, 0, 0, NULL
, HFILL
241 { &hf_lls_smt_payload_count
, {
242 "Signed Multi Table Payload Count", "lls.smt.payload_count",
243 FT_UINT8
, BASE_DEC
, 0, 0, NULL
, HFILL
245 { &hf_lls_smt_entry
, {
246 "Signed Multi Table Entry", "lls.smt.entry",
247 FT_NONE
, BASE_NONE
, NULL
, 0, NULL
, HFILL
250 { &hf_lls_smt_entry_payload_length
, {
251 "Payload Length", "lls.smt.entry.payload_length",
252 FT_UINT16
, BASE_DEC
, 0, 0, NULL
, HFILL
255 { &hf_lls_smt_signature_length
, {
256 "Signed Multi Table Signature Length", "lls.smt.signature_length",
257 FT_UINT16
, BASE_DEC
, 0, 0, NULL
, HFILL
259 { &hf_lls_smt_signature
, {
260 "Signed Multi Table Signature", "lls.smt.signature",
261 FT_NONE
, BASE_NONE
, 0, 0, NULL
, HFILL
265 static int *ett
[] = {
268 &ett_lls_table_payload
,
269 &ett_lls_table_payload_xml
,
270 &ett_lls_smt_signature
,
273 static ei_register_info ei
[] = {
274 { &ei_lls_table_decompression_failed
,
275 { "lls.table.decompression.failed", PI_MALFORMED
, PI_ERROR
,
276 "LLS table payload decompression failed",
281 proto_lls
= proto_register_protocol("ATSC3 Low Level Signalling", "LLS", "lls");
283 expert_module_t
*expert_lls
= expert_register_protocol(proto_lls
);
284 expert_register_field_array(expert_lls
, ei
, array_length(ei
));
286 proto_register_field_array(proto_lls
, hf
, array_length(hf
));
287 proto_register_subtree_array(ett
, array_length(ett
));
291 proto_reg_handoff_lls(void)
293 lls_handle
= create_dissector_handle(dissect_lls
, proto_lls
);
294 xml_handle
= find_dissector_add_dependency("xml", proto_lls
);
295 cms_handle
= find_dissector_add_dependency("cms", proto_lls
);
296 dissector_add_uint_with_preference("udp.port", LLS_PORT
, lls_handle
);
301 * Editor modelines - https://www.wireshark.org/tools/modelines.html
306 * indent-tabs-mode: nil
309 * vi: set shiftwidth=4 tabstop=8 expandtab:
310 * :indentSize=4:tabSize=8:noTabs=true: