TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / epan / dissectors / packet-lls-slt.c
blob38ae297c6834cc22f30d6fed793660783a6dc195
1 /* packet-lls-slt.c
2 * Routines for ATSC3 LLS(Low Level Signalling) SLT table 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/
17 #include <epan/packet.h>
18 #include <epan/proto_data.h>
20 #include <wsutil/inet_addr.h>
21 #include <wsutil/strtoi.h>
23 #include "packet-lls.h"
24 #include "packet-xml.h"
27 /* Saved SLT Table to use it from another protocols (e.g. ALC/LCT) */
28 wmem_map_t *lls_slt_table;
30 /* Hash functions */
31 static int
32 lls_slt_key_equal(const void *v, const void *w)
34 const lls_slt_key_t *v1 = (const lls_slt_key_t *)v;
35 const lls_slt_key_t *v2 = (const lls_slt_key_t *)w;
36 int result;
37 result = (v1->src_ip == v2->src_ip &&
38 v1->dst_ip == v2->dst_ip &&
39 v1->dst_port == v2->dst_port);
40 return result;
43 static unsigned
44 lls_slt_key_hash(const void *v)
46 const lls_slt_key_t *key = (const lls_slt_key_t *)v;
47 unsigned hash_val = key->src_ip ^ key->dst_ip ^ (((uint32_t)(key->dst_port)) << 16);
48 return hash_val;
51 /* Init hash table */
52 static void
53 lls_check_init_slt_table(void) {
54 if(lls_slt_table == NULL) {
55 lls_slt_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), lls_slt_key_hash, lls_slt_key_equal);
59 static char *
60 xml_value_to_gchar(xml_frame_t *xml_frame, wmem_allocator_t *scope) {
61 char *value = NULL;
62 if (xml_frame->value != NULL) {
63 unsigned l = tvb_reported_length(xml_frame->value);
64 value = (char *)wmem_alloc0(scope, l + 1);
65 tvb_memcpy(xml_frame->value, value, 0, l);
67 return value;
70 void
71 lls_extract_save_slt_table(packet_info *pinfo, dissector_handle_t xml_handle)
73 /* Extract data saved by xml */
74 int proto_xml = dissector_handle_get_protocol_index(xml_handle);
75 xml_frame_t *xml_dissector_frame = (xml_frame_t *)p_get_proto_data(pinfo->pool, pinfo, proto_xml, 0);
76 if (xml_dissector_frame == NULL) {
77 return;
80 /* Data from XML dissector */
81 /* Root level, find SLT tag */
82 xml_frame_t *xml_frame = xml_dissector_frame->first_child;
83 xml_frame_t *xml_frame_slt = NULL;
84 while (xml_frame) {
85 if (xml_frame->type == XML_FRAME_TAG && g_strcmp0("SLT", xml_frame->name_orig_case) == 0) {
86 xml_frame_slt = xml_frame;
87 break; /* SLT tag found */
89 xml_frame = xml_frame->next_sibling;
92 if (xml_frame_slt == NULL)
93 return;
95 /* SLT level*/
96 xml_frame_t *slt_entry = xml_frame_slt->first_child;
97 while (slt_entry) {
98 if (!(slt_entry->type == XML_FRAME_TAG && g_strcmp0("Service", slt_entry->name_orig_case) == 0)) {
99 slt_entry = slt_entry->next_sibling;
100 continue;
103 /* Service level */
104 xml_frame_t *service_entry = slt_entry->first_child;
106 lls_slt_key_t slt_key = {0};
107 lls_slt_value_t slt_val = {0};
108 slt_val.major_channel_num = -1;
109 slt_val.minor_channel_num = -1;
110 while (service_entry) {
111 char *value = xml_value_to_gchar(service_entry, pinfo->pool);
112 if (service_entry->type == XML_FRAME_ATTRIB && value != NULL) {
113 if(g_strcmp0("serviceId", service_entry->name_orig_case) == 0) {
114 ws_strtou16(value, NULL, &slt_val.service_id);
115 } else if(g_strcmp0("majorChannelNo", service_entry->name_orig_case) == 0) {
116 ws_strtoi32(value, NULL, &slt_val.major_channel_num);
117 } else if(g_strcmp0("minorChannelNo", service_entry->name_orig_case) == 0) {
118 ws_strtoi32(value, NULL, &slt_val.minor_channel_num);
121 wmem_free(pinfo->pool, value);
123 if (service_entry->type == XML_FRAME_TAG && g_strcmp0("BroadcastSvcSignaling", service_entry->name_orig_case) == 0) {
124 /* Broadcast svc signalling level*/
125 xml_frame_t *bcast_svc_entry = service_entry->first_child;
127 while (bcast_svc_entry) {
128 value = xml_value_to_gchar(bcast_svc_entry, pinfo->pool);
129 if (bcast_svc_entry->type == XML_FRAME_ATTRIB && value != NULL) {
130 if (g_strcmp0("slsProtocol", bcast_svc_entry->name_orig_case) == 0) {
131 ws_strtou8(value, NULL, &slt_val.sls_protocol);
132 } else if (g_strcmp0("slsDestinationIpAddress", bcast_svc_entry->name_orig_case) == 0) {
133 ws_inet_pton4(value, &slt_key.dst_ip);
134 } else if (g_strcmp0("slsSourceIpAddress", bcast_svc_entry->name_orig_case) == 0) {
135 ws_inet_pton4(value, &slt_key.src_ip);
136 } else if (g_strcmp0("slsDestinationUdpPort", bcast_svc_entry->name_orig_case) == 0) {
137 ws_strtou16(value, NULL, &slt_key.dst_port);
140 wmem_free(pinfo->pool, value);
141 bcast_svc_entry = bcast_svc_entry->next_sibling;
145 service_entry = service_entry->next_sibling;
147 if (slt_key.dst_ip != 0) {
148 /* Save found service entry to hashmap */
149 lls_slt_key_t *slt_key_m = wmem_new(wmem_file_scope(), lls_slt_key_t);
150 lls_slt_value_t *slt_val_m = wmem_new(wmem_file_scope(), lls_slt_value_t);
151 *slt_key_m = slt_key;
152 *slt_val_m = slt_val;
153 lls_check_init_slt_table();
154 wmem_map_insert(lls_slt_table, (void *)slt_key_m, (void *)slt_val_m);
156 slt_entry = slt_entry->next_sibling;
160 static lls_slt_value_t *
161 get_lls_slt_val(packet_info *pinfo) {
162 /* This routine is for ATSC3 ALC/LCT packets (ipv4 only protocol by design)
163 so ipv6 is not supported by this test */
164 if (!(pinfo->net_src.type == AT_IPv4)) {
165 return NULL;
168 /* No ability to lookup a record */
169 if (lls_slt_table == NULL) {
170 return NULL;
173 /* Prepare for lookup in LLS SLT table */
174 lls_slt_key_t slt_key;
175 slt_key.src_ip = *(uint32_t *)pinfo->net_src.data;
176 slt_key.dst_ip = *(uint32_t *)pinfo->net_dst.data;
177 slt_key.dst_port = (uint16_t)pinfo->destport;
179 /* Try to lookup by src_ip + dst_ip + dst_port */
180 lls_slt_value_t *slt_val = (lls_slt_value_t *)wmem_map_lookup(lls_slt_table, (const void *)(&slt_key));
181 if(slt_val == NULL) {
182 /* No record in SLT table. src_ip is optional according to A/331 so try to lookup by dst ip + port */
183 slt_key.src_ip = 0; /* LLS SLT dissector sets it to 0 if source ip is not specified */
184 slt_val = (lls_slt_value_t *)wmem_map_lookup(lls_slt_table, (const void *)(&slt_key));
185 if (slt_val == NULL) {
186 /* Record not found by dst ip + port */
187 return NULL;
191 return slt_val;
194 /* Heuristics test. Checks if packet is ALC using LLS SLT table */
195 bool
196 test_alc_over_slt(packet_info *pinfo, tvbuff_t *tvb _U_, int offset _U_, void *data _U_)
198 lls_slt_value_t *slt_val = get_lls_slt_val(pinfo);
199 if (slt_val == NULL)
200 return false;
202 if (slt_val->sls_protocol == 1) {
203 /* slsProtocol=1 is ALC/LCT ROUTE/DASH */
204 return true;
205 } else {
206 /* ACL/LCT is used only for ROUTE/DASH so return false */
207 return false;
211 /* Returns channel info or NULL if no info in SLT table*/
212 char *
213 get_slt_channel_info(packet_info *pinfo)
215 lls_slt_value_t *slt_val = get_lls_slt_val(pinfo);
216 if (slt_val == NULL)
217 return NULL;
219 int32_t major_channel_num = slt_val->major_channel_num;
220 int32_t minor_channel_num = slt_val->minor_channel_num;
221 char *ret;
222 if (major_channel_num > 0 && minor_channel_num > 0) {
223 ret = wmem_strdup_printf(pinfo->pool, "ServiceID: %u Channel: %d.%d", slt_val->service_id,
224 major_channel_num, minor_channel_num);
225 } else {
226 ret = wmem_strdup_printf(pinfo->pool, "ServiceID: %u", slt_val->service_id);
229 return ret;