/src/wireshark/epan/dissectors/packet-mcdata.c
Line | Count | Source |
1 | | /* packet-mcdata.c |
2 | | * Routines for MCData dissection. |
3 | | * 3GPP TS 24.282 V18.8.0 MCData |
4 | | * |
5 | | * TODO: |
6 | | * Add support for OFF-NETWORK message and notification |
7 | | * Add support for DEFERRED LIST ACCESS messages |
8 | | * Add support for FD NETWORK NOTIFICATION message |
9 | | * Add support for GROUP EMERGENCY ALERT messages |
10 | | * Add support for COMMUNICATION RELEASE message |
11 | | * |
12 | | * Copyright 2026, Stefan Wenk |
13 | | * |
14 | | * SPDX-License-Identifier: GPL-2.0-or-later |
15 | | * |
16 | | */ |
17 | | |
18 | | #include <epan/expert.h> |
19 | | #include <epan/packet.h> |
20 | | #include <epan/proto.h> |
21 | | #include <gmodule.h> |
22 | | |
23 | | /* Protocol and Field Handles */ |
24 | | static int proto_mcdata = -1; |
25 | | static int hf_mcdata_message_auth; |
26 | | static int hf_mcdata_message_protected; |
27 | | static int hf_mcdata_message_type; |
28 | | static int hf_mcdata_num_payloads; |
29 | | static int hf_mcdata_payload_len; |
30 | | static int hf_mcdata_payload_cont_type; |
31 | | static int hf_mcdata_payload_val_text; |
32 | | static int hf_mcdata_payload_val_bytes; |
33 | | static int hf_mcdata_status_val; |
34 | | static int hf_mcdata_date_time; |
35 | | static int hf_mcdata_conv_id; |
36 | | static int hf_mcdata_message_id; |
37 | | static int hf_mcdata_sds_disposition_req_iei; |
38 | | static int hf_mcdata_sds_disposition_req_type; |
39 | | static int hf_mcdata_fd_disposition_req_iei; |
40 | | static int hf_mcdata_fd_disposition_req_type; |
41 | | static int hf_mcdata_mandatory_download_iei; |
42 | | static int hf_mcdata_mandatory_download_value; |
43 | | static int hf_mcdata_general_iei; |
44 | | static int hf_mcdata_in_reply_to_message_id; |
45 | | static int hf_mcdata_application_id; |
46 | | static int hf_mcdata_sds_disp_not_type; |
47 | | static int hf_mcdata_fd_disp_not_type; |
48 | | static int hf_mcdata_metadata; |
49 | | static int hf_mcdata_ext_app_id_cont_type; |
50 | | static int hf_mcdata_ext_app_id_data; |
51 | | static int hf_mcdata_user_location; |
52 | | static int hf_mcdata_org_name; |
53 | | static int hf_mcdata_deffered_fd_sig_payload; |
54 | | static int hf_mcdata_user_ID; |
55 | | static int hf_mcdata_termination_info_type; |
56 | | static int hf_mcdata_ext_response_type_iei; |
57 | | static int hf_mcdata_ext_response_type_value; |
58 | | static int hf_mcdata_release_response_type_iei; |
59 | | static int hf_mcdata_release_response_type_val; |
60 | | static int hf_mcdata_notification_type; |
61 | | static int hf_mcdata_app_metadata_container; |
62 | | static int hf_mcdata_group_id; |
63 | | |
64 | | static int ett_mcdata = -1; |
65 | | |
66 | | static expert_field ei_malformed_length; |
67 | | |
68 | | static ei_register_info expertitems[] = { |
69 | | {&ei_malformed_length, {"mcdata.malformed.length", PI_MALFORMED, PI_ERROR, "Malformed length", EXPFILL}}, |
70 | | }; |
71 | | |
72 | | // Table 15.2.2-1 |
73 | | static const value_string message_type_vals[] = { |
74 | | { 1, "SDS SIGNALLING PAYLOAD" }, |
75 | | { 2, "FD SIGNALLING PAYLOAD" }, |
76 | | { 3, "DATA PAYLOAD" }, |
77 | | { 5, "SDS NOTIFICATION" }, |
78 | | { 6, "FD NOTIFICATION" }, |
79 | | { 7, "SDS OFF-NETWORK MESSAGE" }, |
80 | | { 8, "SDS OFF-NETWORK NOTIFICATION" }, |
81 | | { 9, "FD NETWORK NOTIFICATION" }, |
82 | | { 10, "COMMUNICATION RELEASE" }, |
83 | | { 11, "DEFERRED LIST ACCESS REQUEST" }, |
84 | | { 12, "DEFERRED LIST ACCESS RESPONSE" }, |
85 | | { 13, "FD HTTP TERMINATION" }, |
86 | | { 17, "GROUP EMERGENCY ALERT" }, |
87 | | { 18, "GROUP EMERGENCY ALERT ACK" }, |
88 | | { 19, "GROUP EMERGENCY ALERT CANCEL" }, |
89 | | { 20, "GROUP EMERGENCY ALERT CANCEL ACK" }, |
90 | | { 0, NULL } |
91 | | }; |
92 | | |
93 | | // |
94 | | static const value_string payload_content_type_vals[] = { |
95 | | { 1, "TEXT" }, |
96 | | { 2, "BINARY" }, |
97 | | { 3, "HYPERLINKS" }, |
98 | | { 4, "FILEURL" }, |
99 | | { 5, "LOCATION" }, |
100 | | { 6, "ENHANCED STATUS" }, |
101 | | { 7, "Value allocated for use in interworking" }, |
102 | | { 8, "LOCATION ALTITUDE" }, |
103 | | { 9, "LOCATION TIMESTAMP" }, |
104 | | { 10, "CODED TEXT" }, |
105 | | { 0, NULL } |
106 | | }; |
107 | | |
108 | | // Table 15.2.3-1 |
109 | | static const value_string sds_disposition_req_type_vals[] = { |
110 | | { 1, "DELIVERY" }, |
111 | | { 2, "READ" }, |
112 | | { 3, "DELIVERY AND READ" }, |
113 | | { 0, NULL } |
114 | | }; |
115 | | |
116 | | // Table 15.2.4-1 |
117 | | static const value_string fd_disposition_req_type_vals[] = { |
118 | | { 1, "FILE DOWNLOAD COMPLETED UPDATE" }, |
119 | | { 0, NULL } |
120 | | }; |
121 | | |
122 | | // Table 15.2.16-1 |
123 | | static const value_string mand_download_vals[] = { |
124 | | { 1, "MANDATORY DOWNLOAD" }, |
125 | | { 0, NULL } |
126 | | }; |
127 | | |
128 | | // Table 15.2.24-2 |
129 | | static const value_string ext_app_id_content_type_vals[] = { |
130 | | { 1, "TEXT" }, |
131 | | { 2, "URI" }, |
132 | | { 0, NULL } |
133 | | }; |
134 | | |
135 | | static const value_string mcdata_general_iei_vals[] = { |
136 | | // TV IEIs |
137 | | { 0x21, "InReplyTo message ID" }, |
138 | | { 0x22, "Application ID" }, |
139 | | { 0x51, "Sender MCData user ID" }, |
140 | | { 0x52, "Deferred FD signalling payload" }, |
141 | | { 0x53, "Application metadata container" }, |
142 | | // TLV IEIs |
143 | | { 0x78, "Payload" }, |
144 | | { 0x79, "Metadata" }, |
145 | | { 0x7B, "MCData group ID" }, |
146 | | { 0x7C, "Recipient MCData user ID" }, |
147 | | { 0x7D, "Extended application ID" }, |
148 | | { 0x7E, "User location" }, |
149 | | { 0x7F, "Organization name" }, |
150 | | { 0, NULL } |
151 | | }; |
152 | | |
153 | | static const value_string application_id_value_vals[] = { |
154 | | { 1, "BROADBAND CALLOUT" }, |
155 | | { 0, NULL } |
156 | | }; |
157 | | |
158 | | // Table 15.2.5-1 |
159 | | static const value_string sds_disp_not_type_vals[] = { |
160 | | { 1, "UNDELIVERED" }, |
161 | | { 2, "DELIVERED" }, |
162 | | { 3, "READ" }, |
163 | | { 4, "DELIVERED AND READ" }, |
164 | | { 5, "DISPOSITION PREVENTED BY SYSTEM" }, |
165 | | { 0, NULL } |
166 | | }; |
167 | | |
168 | | // Table 15.2.6-1 |
169 | | static const value_string fd_disp_not_type_vals[] = { |
170 | | { 1, "FILE DOWNLOAD REQUEST ACCEPTED" }, |
171 | | { 2, "FILE DOWNLOAD REQUEST REJECTED" }, |
172 | | { 3, "FILE DOWNLOAD COMPLETED" }, |
173 | | { 4, "FILE DOWNLOAD DEFERRED" }, |
174 | | { 0, NULL } |
175 | | }; |
176 | | |
177 | | // Table 15.2.22-1 |
178 | | static const value_string term_info_type_vals[] = { |
179 | | { 1, "TERMINATION REQUEST" }, |
180 | | { 2, "TERMINATION RESPONSE" }, |
181 | | { 3, "TRANSMISSION STOPPED" }, |
182 | | { 4, "INTENT TO RELEASE COMM OVER HTTP" }, |
183 | | { 5, "EXTENSION REQUEST FOR COMM OVER HTTP" }, |
184 | | { 6, "EXTENSION RESPONSE FOR COMM OVER HTTP" }, |
185 | | { 7, "AUTH USER TERMINATION REQUEST FOR COMM OVER HTTP" }, |
186 | | { 0, NULL } |
187 | | }; |
188 | | |
189 | | // Table 15.2.21-1 |
190 | | static const value_string ext_respone_type_value_vals[] = { |
191 | | { 1, "ACCEPTED" }, |
192 | | { 2, "REJECTED" }, |
193 | | { 0, NULL } |
194 | | }; |
195 | | |
196 | | // Table 15.2.23-1 |
197 | | static const value_string rel_respone_type_vals[] = { |
198 | | { 1, "RELEASE SUCCESS" }, |
199 | | { 2, "RELEASE FAILED" }, |
200 | | { 0, NULL } |
201 | | }; |
202 | | |
203 | | // Table 15.2.18-1 |
204 | | static const value_string notification_type_vals[] = { |
205 | | { 1, "FILE EXPIRED UNAVAILABLE TO DOWNLOAD" }, |
206 | | { 2, "FILE DELETED UNAVAILABLE TO DOWNLOAD" }, |
207 | | { 0, NULL } |
208 | | }; |
209 | | |
210 | | |
211 | 0 | static unsigned dissect_payload(unsigned offset, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { |
212 | 0 | uint16_t len; |
213 | 0 | proto_tree_add_item_ret_uint16(tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
214 | 0 | offset += 2; |
215 | 0 | if ((tvb_reported_length_remaining(tvb, offset) < len) || len < 1) { |
216 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
217 | 0 | return len; |
218 | 0 | } |
219 | 0 | uint8_t payload_cont_type; |
220 | 0 | proto_tree_add_item_ret_uint8(tree, hf_mcdata_payload_cont_type, tvb, offset, 1, ENC_BIG_ENDIAN, &payload_cont_type); |
221 | 0 | offset += 1; |
222 | 0 | switch (payload_cont_type) { |
223 | 0 | case 1: // TEXT |
224 | 0 | case 3: // HYPERLINKS |
225 | 0 | case 4: // FILEURL |
226 | 0 | case 10: // CODED TEXT |
227 | 0 | proto_tree_add_item(tree, hf_mcdata_payload_val_text, tvb, offset, len - 1, ENC_UTF_8); |
228 | 0 | break; |
229 | 0 | case 6: // ENHANCED STATUS |
230 | 0 | proto_tree_add_item(tree, hf_mcdata_status_val, tvb, offset, 2, ENC_BIG_ENDIAN); |
231 | 0 | break; |
232 | 0 | case 7: // Value allocated for use in interworking |
233 | | //Todo: Usage of this value is described in 3GPP TS 29.582 |
234 | 0 | proto_tree_add_item(tree, hf_mcdata_payload_val_bytes, tvb, offset, len - 1, ENC_NA); |
235 | 0 | break; |
236 | 0 | case 8: // LOCATION ALTITUDE |
237 | | //Todo: The length of the location altitude payload content is 2 bytes coded as in clause 6.3 in 3GPP TS 23.032 |
238 | 0 | proto_tree_add_item(tree, hf_mcdata_payload_val_bytes, tvb, offset, len - 1, ENC_NA); |
239 | 0 | break; |
240 | 0 | case 9: // LOCATION TIMESTAMP |
241 | | //Todo: The length of location timestamp is contained as a binary value in the first octet of the payload |
242 | 0 | proto_tree_add_item(tree, hf_mcdata_payload_val_bytes, tvb, offset, len - 1, ENC_NA); |
243 | 0 | break; |
244 | 0 | default: |
245 | 0 | proto_tree_add_item(tree, hf_mcdata_payload_val_bytes, tvb, offset, len - 1, ENC_NA); |
246 | 0 | break; |
247 | 0 | } |
248 | 0 | return len + 2; |
249 | 0 | } |
250 | | |
251 | 0 | static void dissect_signalling_payload(uint8_t message_type, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned decoded_len ) { |
252 | 0 | unsigned offset = 0; |
253 | |
|
254 | 0 | proto_tree_add_item(tree, hf_mcdata_message_auth, tvb, offset, 1, ENC_BIG_ENDIAN); |
255 | 0 | proto_tree_add_item(tree, hf_mcdata_message_protected, tvb, offset, 1, ENC_BIG_ENDIAN); |
256 | 0 | proto_tree_add_item(tree, hf_mcdata_message_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
257 | 0 | offset += 1; |
258 | 0 | if (message_type == 5){ // SDS NOTIFICATION |
259 | 0 | proto_tree_add_item(tree, hf_mcdata_sds_disp_not_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
260 | 0 | offset += 1; |
261 | 0 | } |
262 | 0 | if (message_type == 6) { // FD NOTIFICATION |
263 | 0 | proto_tree_add_item(tree, hf_mcdata_fd_disp_not_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
264 | 0 | offset += 1; |
265 | 0 | } |
266 | 0 | if (message_type == 9) { // FD NETWORK NOTIFICATION |
267 | 0 | proto_tree_add_item(tree, hf_mcdata_notification_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
268 | 0 | offset += 1; |
269 | 0 | } |
270 | 0 | if (message_type !=13 ) { // FD HTTP TERMINATION |
271 | 0 | proto_tree_add_item(tree, hf_mcdata_date_time, tvb, offset, 5, ENC_TIME_SECS|ENC_BIG_ENDIAN); |
272 | 0 | offset += 5; |
273 | 0 | } |
274 | 0 | proto_tree_add_item(tree, hf_mcdata_conv_id, tvb, offset, FT_GUID_LEN, ENC_BIG_ENDIAN); |
275 | 0 | offset += FT_GUID_LEN; |
276 | 0 | proto_tree_add_item(tree, hf_mcdata_message_id, tvb, offset, FT_GUID_LEN, ENC_BIG_ENDIAN); |
277 | 0 | offset += FT_GUID_LEN; |
278 | 0 | if (message_type ==13 ) { // FD HTTP TERMINATION |
279 | 0 | proto_tree_add_item(tree, hf_mcdata_termination_info_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
280 | 0 | offset += 1; |
281 | 0 | } |
282 | |
|
283 | 0 | while (offset < decoded_len) { |
284 | 0 | unsigned iei = tvb_get_uint8(tvb, offset); |
285 | 0 | if ((iei & 0xF0) == 0x80) { // SDS disposition request type |
286 | 0 | proto_tree_add_item(tree, hf_mcdata_sds_disposition_req_iei, tvb, offset, 1, ENC_NA); |
287 | 0 | proto_tree_add_item(tree, hf_mcdata_sds_disposition_req_type, tvb, offset, 1, ENC_NA); |
288 | 0 | offset += 1; |
289 | 0 | } |
290 | 0 | else if ((iei & 0xF0) == 0x90) { // FD disposition request type |
291 | 0 | proto_tree_add_item(tree, hf_mcdata_fd_disposition_req_iei, tvb, offset, 1, ENC_NA); |
292 | 0 | proto_tree_add_item(tree, hf_mcdata_fd_disposition_req_type, tvb, offset, 1, ENC_NA); |
293 | 0 | offset += 1; |
294 | 0 | } |
295 | 0 | else if ((iei & 0xF0) == 0xA0) { // Mandatory download |
296 | 0 | proto_tree_add_item(tree, hf_mcdata_mandatory_download_iei, tvb, offset, 1, ENC_NA); |
297 | 0 | proto_tree_add_item(tree, hf_mcdata_mandatory_download_value, tvb, offset, 1, ENC_NA); |
298 | 0 | offset += 1; |
299 | 0 | } |
300 | 0 | else if ((iei & 0xF0) == 0xC0) { // Extension Response Type |
301 | 0 | proto_tree_add_item(tree, hf_mcdata_ext_response_type_iei, tvb, offset, 1, ENC_NA); |
302 | 0 | proto_tree_add_item(tree, hf_mcdata_ext_response_type_value, tvb, offset, 1, ENC_NA); |
303 | 0 | offset += 1; |
304 | 0 | } |
305 | 0 | else if ((iei & 0xF0) == 0xD0) { // Release Response Type |
306 | 0 | proto_tree_add_item(tree, hf_mcdata_release_response_type_iei, tvb, offset, 1, ENC_NA); |
307 | 0 | proto_tree_add_item(tree, hf_mcdata_release_response_type_val, tvb, offset, 1, ENC_NA); |
308 | 0 | offset += 1; |
309 | 0 | } |
310 | 0 | else { |
311 | 0 | proto_tree_add_item(tree, hf_mcdata_general_iei, tvb, offset, 1, ENC_NA); |
312 | 0 | offset += 1; |
313 | 0 | uint16_t len; |
314 | 0 | switch (iei) { |
315 | 0 | case 0x21: { // InReplyTo message ID |
316 | 0 | proto_tree_add_item(tree, hf_mcdata_in_reply_to_message_id, tvb, offset, FT_GUID_LEN, ENC_BIG_ENDIAN); |
317 | 0 | offset += FT_GUID_LEN; |
318 | 0 | break; |
319 | 0 | } |
320 | 0 | case 0x22: { // Application ID |
321 | 0 | proto_tree_add_item(tree, hf_mcdata_application_id, tvb, offset, 1, ENC_NA); |
322 | 0 | offset += 1; |
323 | 0 | break; |
324 | 0 | } |
325 | 0 | case 0x51: { // Sender MCData user ID |
326 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len) ; |
327 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
328 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
329 | 0 | } |
330 | 0 | proto_tree_add_item(tree, hf_mcdata_user_ID, tvb, offset + 2, len , ENC_UTF_8); |
331 | 0 | offset += len + 2; |
332 | 0 | break; |
333 | 0 | } |
334 | 0 | case 0x52: { // Deferred FD signalling payload |
335 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
336 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
337 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
338 | 0 | } |
339 | 0 | proto_tree_add_item(tree, hf_mcdata_deffered_fd_sig_payload, tvb, offset + 2, len , ENC_NA); |
340 | 0 | offset += len + 2; |
341 | 0 | break; |
342 | 0 | } |
343 | 0 | case 0x53: { // Application metadata container |
344 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
345 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
346 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
347 | 0 | } |
348 | 0 | proto_tree_add_item(tree, hf_mcdata_app_metadata_container, tvb, offset + 2, len , ENC_UTF_8); |
349 | 0 | offset += len + 2; |
350 | 0 | break; |
351 | 0 | } |
352 | 0 | case 0x78: { // Payload |
353 | 0 | offset += dissect_payload(offset, tvb, pinfo, tree); |
354 | 0 | break; |
355 | 0 | } |
356 | 0 | case 0x79: { // Metadata |
357 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
358 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
359 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
360 | 0 | } |
361 | 0 | proto_tree_add_item(tree, hf_mcdata_metadata, tvb, offset + 2, len , ENC_UTF_8); |
362 | 0 | offset += len + 2; |
363 | 0 | break; |
364 | 0 | } |
365 | 0 | case 0x7B: { // MCData group ID |
366 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
367 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
368 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
369 | 0 | } |
370 | 0 | proto_tree_add_item(tree, hf_mcdata_group_id, tvb, offset + 2, len , ENC_NA); |
371 | 0 | offset += len + 2; |
372 | 0 | break; |
373 | 0 | } |
374 | 0 | case 0x7C: { // Recipient MCData user ID |
375 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
376 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
377 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
378 | 0 | } |
379 | 0 | proto_tree_add_item(tree, hf_mcdata_user_ID, tvb, offset + 2, len , ENC_UTF_8); |
380 | 0 | offset += len + 2; |
381 | 0 | break; |
382 | 0 | } |
383 | 0 | case 0x7D: { // Extended application ID |
384 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
385 | 0 | if (tvb_reported_length_remaining(tvb, offset + 3) < (unsigned) len) { |
386 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
387 | 0 | } |
388 | 0 | proto_tree_add_item(tree, hf_mcdata_ext_app_id_cont_type, tvb, offset + 2, 1, ENC_BIG_ENDIAN); |
389 | 0 | proto_tree_add_item(tree, hf_mcdata_ext_app_id_data, tvb, offset + 3, len - 1, ENC_UTF_8); |
390 | 0 | offset += len + 3; |
391 | 0 | break; |
392 | 0 | } |
393 | 0 | case 0x7E: { // User location |
394 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
395 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
396 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
397 | 0 | } |
398 | | // Todo: The User location information element contains the LocationInfo structure defined in clause 7.4 of 3GPP TS 29.199-09 |
399 | 0 | proto_tree_add_item(tree, hf_mcdata_user_location, tvb, offset + 2, len , ENC_NA); |
400 | 0 | offset += len + 2; |
401 | 0 | break; |
402 | 0 | } |
403 | 0 | case 0x7F: { // Organization name |
404 | 0 | proto_tree_add_item_ret_uint16 (tree, hf_mcdata_payload_len, tvb, offset, 2, ENC_BIG_ENDIAN, &len); |
405 | 0 | if (tvb_reported_length_remaining(tvb, offset + 2) < (unsigned) len) { |
406 | 0 | expert_add_info(pinfo, tree, &ei_malformed_length); |
407 | 0 | } |
408 | 0 | proto_tree_add_item(tree, hf_mcdata_org_name, tvb, offset + 2, len , ENC_UTF_8); |
409 | 0 | offset += len + 2; |
410 | 0 | break; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | |
|
415 | 0 | } |
416 | |
|
417 | 0 | } |
418 | | |
419 | | /* Dissector Implementation */ |
420 | 0 | static int dissect_mcdata(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { |
421 | 0 | unsigned offset = 0; |
422 | 0 | unsigned decoded_len = tvb_captured_length(tvb); |
423 | 0 | uint8_t message_type = tvb_get_uint8(tvb, offset) & 0x3F; |
424 | |
|
425 | 0 | add_new_data_source(pinfo, tvb, "MCData"); |
426 | 0 | proto_item *ti = proto_tree_add_item(tree, proto_mcdata, tvb, 0, -1, ENC_NA); |
427 | 0 | proto_tree *mcdata_tree = proto_item_add_subtree(ti, ett_mcdata); |
428 | |
|
429 | 0 | switch (message_type) { |
430 | 0 | case 1: // SDS SIGNALLING PAYLOAD |
431 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| SDS Signalling Payload"); |
432 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
433 | 0 | break; |
434 | 0 | case 2: // FD SIGNALLING PAYLOAD |
435 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| FD Signalling Payload"); |
436 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
437 | 0 | break; |
438 | 0 | case 3: // DATA PAYLOAD |
439 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Data Payload"); |
440 | 0 | proto_tree_add_item(mcdata_tree, hf_mcdata_message_auth, tvb, offset, 1, ENC_BIG_ENDIAN); |
441 | 0 | proto_tree_add_item(mcdata_tree, hf_mcdata_message_protected, tvb, offset, 1, ENC_BIG_ENDIAN); |
442 | 0 | proto_tree_add_item(mcdata_tree, hf_mcdata_message_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
443 | 0 | offset += 1; |
444 | 0 | proto_tree_add_item(mcdata_tree, hf_mcdata_num_payloads, tvb, offset, 1, ENC_BIG_ENDIAN); |
445 | 0 | uint8_t num_payload = tvb_get_uint8(tvb, offset); |
446 | 0 | offset += 1; |
447 | 0 | for (uint8_t i=1; i<=num_payload; i++) { |
448 | 0 | proto_tree_add_item(mcdata_tree, hf_mcdata_general_iei, tvb, offset, 1, ENC_NA); |
449 | 0 | offset += 1; |
450 | 0 | offset += dissect_payload(offset, tvb, pinfo, mcdata_tree); |
451 | 0 | } |
452 | 0 | break; |
453 | 0 | case 5: // SDS NOTIFICATION |
454 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| SDS Notification"); |
455 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
456 | 0 | break; |
457 | 0 | case 6: // FD NOTIFICATION |
458 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| FD Notification"); |
459 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
460 | 0 | break; |
461 | 0 | case 7: // SDS OFF-NETWORK MESSAGE |
462 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| SDS Off-Network Message"); |
463 | 0 | break; |
464 | 0 | case 8: // SDS OFF-NETWORK NOTIFICATION |
465 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| SDS Off-Network Notification"); |
466 | 0 | break; |
467 | 0 | case 9: // FD NETWORK NOTIFICATION |
468 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| FD Network Notification"); |
469 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
470 | 0 | break; |
471 | 0 | case 10: // COMMUNICATION RELEASE |
472 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Communication Release"); |
473 | 0 | break; |
474 | 0 | case 11: // DEFERRED LIST ACCESS REQUEST |
475 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Deferred list access request"); |
476 | 0 | break; |
477 | 0 | case 12: // DEFERRED LIST ACCESS RESPONSE |
478 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Deferred list access response"); |
479 | 0 | break; |
480 | 0 | case 13: // FD HTTP TERMINATION |
481 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| FD HTTP termination"); |
482 | 0 | dissect_signalling_payload(message_type, tvb, pinfo, mcdata_tree, decoded_len); |
483 | 0 | break; |
484 | 0 | case 17: // GROUP EMERGENCY ALERT |
485 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Group emergency alert"); |
486 | 0 | break; |
487 | 0 | case 18: // GROUP EMERGENCY ALERT ACK |
488 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Group emergency alert ack"); |
489 | 0 | break; |
490 | 0 | case 19: // GROUP EMERGENCY ALERT CANCEL |
491 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Group emergency alert cancel"); |
492 | 0 | break; |
493 | 0 | case 20: // GROUP EMERGENCY ALERT CANCEL ACK |
494 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Group emergency alert cancel ack"); |
495 | 0 | break; |
496 | 0 | default: |
497 | 0 | col_append_str(pinfo->cinfo, COL_INFO, "| Unknown Message Type"); |
498 | 0 | break; |
499 | 0 | } |
500 | | |
501 | 0 | return tvb_captured_length(tvb); |
502 | 0 | } |
503 | | |
504 | | /* Registration */ |
505 | 16 | void proto_register_mcdata(void) { |
506 | 16 | static hf_register_info hf[] = { |
507 | 16 | { &hf_mcdata_message_auth, { "Message authenticated", "mcdata.message.authenticated", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }}, |
508 | 16 | { &hf_mcdata_message_protected, { "Message protected", "mcdata.message.protected", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }}, |
509 | 16 | { &hf_mcdata_message_type, { "Message type", "mcdata.message.type", FT_UINT8, BASE_DEC, VALS(message_type_vals), 0x3F, NULL, HFILL }}, |
510 | 16 | { &hf_mcdata_num_payloads, { "Number of payloads", "mcdata.pl.num.payloads", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
511 | 16 | { &hf_mcdata_payload_len, { "Payload length", "mcdata.pl.payload.len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
512 | 16 | { &hf_mcdata_payload_cont_type, { "Payload content type", "mcdata.pl.payload.content.type", FT_UINT8, BASE_DEC, VALS(payload_content_type_vals), 0x0, NULL, HFILL }}, |
513 | 16 | { &hf_mcdata_payload_val_text, { "Payload text value", "mcdata.pl.payload.text.val", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
514 | 16 | { &hf_mcdata_payload_val_bytes, { "Payload value", "mcdata.pl.payload.val", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
515 | 16 | { &hf_mcdata_status_val, { "Enhanced status value", "mcdata.pl.status.val", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
516 | 16 | { &hf_mcdata_date_time, { "Date and time", "mcdata.sig.date.and.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,NULL, HFILL }}, |
517 | 16 | { &hf_mcdata_conv_id, { "Conversation ID", "mcdata.sig.conv.id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
518 | 16 | { &hf_mcdata_message_id, { "Message ID", "mcdata.sig.message.id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
519 | 16 | { &hf_mcdata_sds_disposition_req_iei, { "SDS disposition request IEI", "mcdata.sig.sds.disp.req.iei", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }}, |
520 | 16 | { &hf_mcdata_sds_disposition_req_type, { "SDS disposition request type", "mcdata.sig.sds.disp.req.type", FT_UINT8, BASE_DEC, VALS(sds_disposition_req_type_vals), 0x0F, NULL, HFILL }}, |
521 | 16 | { &hf_mcdata_fd_disposition_req_iei, { "FD disposition request IEI", "mcdata.sig.fd.disp.req.iei", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }}, |
522 | 16 | { &hf_mcdata_fd_disposition_req_type, { "FD disposition request type", "mcdata.sig.fd.disp.req.type", FT_UINT8, BASE_DEC, VALS(fd_disposition_req_type_vals), 0x0F, NULL, HFILL }}, |
523 | 16 | { &hf_mcdata_mandatory_download_iei, { "Mandatory download IEI", "mcdata.sig.mand.download.iei", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }}, |
524 | 16 | { &hf_mcdata_mandatory_download_value, { "Mandatory download value", "mcdata.sig.mand.download.value", FT_UINT8, BASE_DEC, VALS(mand_download_vals), 0x0F, NULL, HFILL }}, |
525 | 16 | { &hf_mcdata_general_iei, { "MCData general IEI", "mcdata.general.iei", FT_UINT8, BASE_HEX, VALS(mcdata_general_iei_vals), 0x0, NULL, HFILL }}, |
526 | 16 | { &hf_mcdata_in_reply_to_message_id, { "In reply to message ID", "mcdata.sig.in.reply.to.message.id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
527 | 16 | { &hf_mcdata_application_id, { "Application ID value", "mcdata.sig.appl.id.value", FT_UINT8, BASE_DEC, VALS(application_id_value_vals), 0x0, NULL, HFILL }}, |
528 | 16 | { &hf_mcdata_sds_disp_not_type, { "SDS disposition notification type", "mcdata.sig.sds.disp.not.type", FT_UINT8, BASE_DEC, VALS(sds_disp_not_type_vals), 0, NULL, HFILL }}, |
529 | 16 | { &hf_mcdata_fd_disp_not_type, { "FD disposition notification type", "mcdata.sig.fd.disp.not.type", FT_UINT8, BASE_DEC, VALS(fd_disp_not_type_vals), 0, NULL, HFILL }}, |
530 | 16 | { &hf_mcdata_metadata, { "Metadata", "mcdata.sig.metadata", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
531 | 16 | { &hf_mcdata_ext_app_id_cont_type, { "Extended application id content type", "mcdata.sig.ext.app.id.cont.type", FT_UINT8, BASE_HEX, VALS(ext_app_id_content_type_vals), 0x0, NULL, HFILL }}, |
532 | 16 | { &hf_mcdata_ext_app_id_data, { "Extended application id data", "mcdata.sig.ext.app.id.data", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
533 | 16 | { &hf_mcdata_user_location, { "User location", "mcdata.sig.user.location", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
534 | 16 | { &hf_mcdata_org_name, { "Organization name", "mcdata.org.name", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
535 | 16 | { &hf_mcdata_deffered_fd_sig_payload, { "Deferred FD signalling payload", "mcdata.sig.def.fd.sig.payload", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
536 | 16 | { &hf_mcdata_user_ID, { "MCData user ID", "mcdata.sig.user.id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
537 | 16 | { &hf_mcdata_termination_info_type, { "Termination information type", "mcdata.sig.term.info.type", FT_UINT8, BASE_DEC, VALS(term_info_type_vals), 0, NULL, HFILL }}, |
538 | 16 | { &hf_mcdata_ext_response_type_iei, { "Extension response type IEI", "mcdata.sig.ext.resp.type.iei", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }}, |
539 | 16 | { &hf_mcdata_ext_response_type_value, { "Extension response type value", "mcdata.sig.ext.resp.type.value", FT_UINT8, BASE_HEX, VALS(ext_respone_type_value_vals), 0xF0, NULL, HFILL }}, |
540 | 16 | { &hf_mcdata_release_response_type_iei, { "Release response type IEI", "mcdata.sig.rel.resp.type.iei", FT_UINT8, BASE_HEX, NULL, 0xF0, NULL, HFILL }}, |
541 | 16 | { &hf_mcdata_release_response_type_val, { "Release response type value", "mcdata.sig.rel.resp.type.value", FT_UINT8, BASE_HEX, VALS(rel_respone_type_vals), 0xF0, NULL, HFILL }}, |
542 | 16 | { &hf_mcdata_notification_type, { "Notification type", "mcdata.sig.notification.type", FT_UINT8, BASE_DEC, VALS(notification_type_vals), 0, NULL, HFILL }}, |
543 | 16 | { &hf_mcdata_app_metadata_container, { "Application metadata container", "mcdata.sig.metadata.container", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
544 | 16 | { &hf_mcdata_group_id, { "MCData group id", "mcdata.sig.mcdata.group.id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
545 | 16 | }; |
546 | 16 | static int *ett[] = { &ett_mcdata }; |
547 | | |
548 | 16 | proto_mcdata = proto_register_protocol("Mission critical data", "MCData", "mcdata"); |
549 | 16 | proto_register_field_array(proto_mcdata, hf, array_length(hf)); |
550 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
551 | 16 | expert_module_t *expert = expert_register_protocol(proto_mcdata); |
552 | 16 | expert_register_field_array(expert, expertitems, array_length(expertitems)); |
553 | | |
554 | 16 | } |
555 | | |
556 | 16 | void proto_reg_handoff_mcdata(void) { |
557 | 16 | static dissector_handle_t mcdata_handle; |
558 | 16 | mcdata_handle = create_dissector_handle(dissect_mcdata, proto_mcdata); |
559 | 16 | dissector_add_string("media_type", "application/vnd.3gpp.mcdata-payload", mcdata_handle); |
560 | 16 | dissector_add_string("media_type", "application/vnd.3gpp.mcdata-signalling", mcdata_handle); |
561 | | // The protocol never appears on top of UDP in the wild, but we allow it for testing purposes using "Decode As": |
562 | 16 | dissector_add_for_decode_as_with_preference("udp.port", mcdata_handle); |
563 | 16 | } |