/src/wireshark/epan/dissectors/packet-at.c
Line | Count | Source |
1 | | /* packet-at.c |
2 | | * Dissector for AT Commands |
3 | | * |
4 | | * Copyright 2011, Tyson Key <tyson.key@gmail.com> |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | * |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | |
16 | | #include <stdio.h> /* for sscanf() */ |
17 | | |
18 | | #include <epan/packet.h> |
19 | | #include <epan/conversation.h> |
20 | | #include <epan/expert.h> |
21 | | #include <epan/proto_data.h> |
22 | | #include <epan/strutil.h> |
23 | | |
24 | | #include "packet-e212.h" |
25 | | |
26 | | void proto_register_at_command(void); |
27 | | void proto_reg_handoff_at_command(void); |
28 | | |
29 | | static int proto_at; |
30 | | |
31 | | static dissector_handle_t gsm_sim_handle; |
32 | | static dissector_handle_t gsm_sms_handle; |
33 | | |
34 | | static int hf_command; |
35 | | static int hf_data_part; |
36 | | static int hf_parameters; |
37 | | static int hf_role; |
38 | | static int hf_at_cmd; |
39 | | static int hf_at_cmd_type; |
40 | | static int hf_at_command_line_prefix; |
41 | | static int hf_at_ignored; |
42 | | static int hf_parameter; |
43 | | static int hf_unknown_parameter; |
44 | | static int hf_data; |
45 | | static int hf_chld_mode; |
46 | | static int hf_chld_mode_1x; |
47 | | static int hf_chld_mode_2x; |
48 | | static int hf_chld_supported_modes; |
49 | | static int hf_cimi_imsi; |
50 | | static int hf_cmer_mode; |
51 | | static int hf_cmer_keyp; |
52 | | static int hf_cmer_disp; |
53 | | static int hf_cmer_ind; |
54 | | static int hf_cmer_bfr; |
55 | | static int hf_cmee; |
56 | | static int hf_cme_error; |
57 | | static int hf_cme_error_verbose; |
58 | | static int hf_cmgl_req_status; |
59 | | static int hf_cmgl_msg_index; |
60 | | static int hf_cmgl_msg_status; |
61 | | static int hf_cmgl_msg_originator_name; |
62 | | static int hf_cmgl_msg_length; |
63 | | static int hf_cmgl_msg_pdu; |
64 | | static int hf_cmgr_address; |
65 | | static int hf_cmgr_mode; |
66 | | static int hf_cmgr_msg_index; |
67 | | static int hf_cmgr_msg_length; |
68 | | static int hf_cmgr_msg_pdu; |
69 | | static int hf_cmgr_stat; |
70 | | static int hf_cmux_k; |
71 | | static int hf_cmux_n1; |
72 | | static int hf_cmux_n2; |
73 | | static int hf_cmux_port_speed; |
74 | | static int hf_cmux_subset; |
75 | | static int hf_cmux_t1; |
76 | | static int hf_cmux_t2; |
77 | | static int hf_cmux_t3; |
78 | | static int hf_cmux_transparency; |
79 | | static int hf_cnum_speed; |
80 | | static int hf_cnum_service; |
81 | | static int hf_cnum_itc; |
82 | | static int hf_ciev_indicator_index; |
83 | | static int hf_vts_dtmf; |
84 | | static int hf_vts_duration; |
85 | | static int hf_cops_mode; |
86 | | static int hf_cops_format; |
87 | | static int hf_cops_operator; |
88 | | static int hf_cops_act; |
89 | | static int hf_cpin_code; |
90 | | static int hf_cpin_newpin; |
91 | | static int hf_cpin_pin; |
92 | | static int hf_cpms_mem1; |
93 | | static int hf_cpms_mem2; |
94 | | static int hf_cpms_mem3; |
95 | | static int hf_cpms_used1; |
96 | | static int hf_cpms_used2; |
97 | | static int hf_cpms_used3; |
98 | | static int hf_cpms_total1; |
99 | | static int hf_cpms_total2; |
100 | | static int hf_cpms_total3; |
101 | | static int hf_cscs_chset; |
102 | | static int hf_csim_command; |
103 | | static int hf_csim_length; |
104 | | static int hf_csim_response; |
105 | | static int hf_csq_ber; |
106 | | static int hf_csq_rssi; |
107 | | static int hf_at_number; |
108 | | static int hf_at_type; |
109 | | static int hf_at_subaddress; |
110 | | static int hf_at_subaddress_type; |
111 | | static int hf_at_alpha; |
112 | | static int hf_at_priority; |
113 | | static int hf_at_cli_validity; |
114 | | static int hf_clip_mode; |
115 | | static int hf_clip_status; |
116 | | static int hf_clcc_id; |
117 | | static int hf_clcc_dir; |
118 | | static int hf_clcc_stat; |
119 | | static int hf_clcc_mode; |
120 | | static int hf_clcc_mpty; |
121 | | static int hf_ccwa_show_result_code; |
122 | | static int hf_ccwa_mode; |
123 | | static int hf_ccwa_class; |
124 | | static int hf_cfun_fun; |
125 | | static int hf_cfun_rst; |
126 | | static int hf_cgdcont_cid; |
127 | | static int hf_cgdcont_pdp_type; |
128 | | static int hf_cgdcont_apn; |
129 | | static int hf_cgdcont_pdp_addr; |
130 | | static int hf_cgdcont_d_comp; |
131 | | static int hf_cgdcont_h_comp; |
132 | | static int hf_cgmi_manufacturer_id; |
133 | | static int hf_cgmm_model_id; |
134 | | static int hf_cgmr_revision_id; |
135 | | static int hf_gmi_manufacturer_id; |
136 | | static int hf_gmm_model_id; |
137 | | static int hf_gmr_revision_id; |
138 | | static int hf_zpas_network; |
139 | | static int hf_zpas_srv_domain; |
140 | | static int hf_zusim_usim_card; |
141 | | static int hf_indicator[20]; |
142 | | |
143 | | static expert_field ei_unknown_command; |
144 | | static expert_field ei_invalid_usage; |
145 | | static expert_field ei_unknown_parameter; |
146 | | static expert_field ei_cmer_mode; |
147 | | static expert_field ei_cmer_keyp; |
148 | | static expert_field ei_cmer_disp; |
149 | | static expert_field ei_cmer_ind; |
150 | | static expert_field ei_cmer_bfr; |
151 | | static expert_field ei_chld_mode; |
152 | | static expert_field ei_ciev_indicator; |
153 | | static expert_field ei_cfun_res_fun; |
154 | | static expert_field ei_cfun_range_fun; |
155 | | static expert_field ei_cfun_rst; |
156 | | static expert_field ei_vts_dtmf; |
157 | | static expert_field ei_at_type; |
158 | | static expert_field ei_cnum_service; |
159 | | static expert_field ei_cnum_itc; |
160 | | static expert_field ei_empty_hex; |
161 | | static expert_field ei_invalid_hex; |
162 | | static expert_field ei_odd_len; |
163 | | static expert_field ei_csq_ber; |
164 | | static expert_field ei_csq_rssi; |
165 | | |
166 | | |
167 | | /* Subtree handles: set by register_subtree_array */ |
168 | | static int ett_at; |
169 | | static int ett_at_command; |
170 | | static int ett_at_data_part; |
171 | | static int ett_at_parameters; |
172 | | |
173 | 0 | #define ROLE_UNKNOWN 0 |
174 | 0 | #define ROLE_DCE 1 |
175 | 0 | #define ROLE_DTE 2 |
176 | | |
177 | 0 | #define TYPE_UNKNOWN 0x0000 |
178 | 0 | #define TYPE_RESPONSE_ACK 0x0d0a |
179 | 0 | #define TYPE_RESPONSE 0x003a |
180 | 0 | #define TYPE_ACTION 0x003d |
181 | 0 | #define TYPE_ACTION_SIMPLY 0x000d |
182 | 0 | #define TYPE_READ 0x003f |
183 | 0 | #define TYPE_TEST 0x3d3f |
184 | | |
185 | 0 | #define STORE_COMMAND_MAX_LEN 20 |
186 | | |
187 | | static int at_role = ROLE_UNKNOWN; |
188 | | |
189 | | static const value_string role_vals[] = { |
190 | | { ROLE_UNKNOWN, "Unknown" }, |
191 | | { ROLE_DCE, "DCE - Data Circuit terminating Equipment (Modem)" }, |
192 | | { ROLE_DTE, "DTE - Data Terminal Equipment (PC)" }, |
193 | | { 0, NULL } |
194 | | }; |
195 | | |
196 | | static const enum_val_t pref_at_role[] = { |
197 | | { "off", "Off", ROLE_UNKNOWN }, |
198 | | { "dte", "Sent is DTE, Rcvd is DCE", ROLE_DTE }, |
199 | | { "dce", "Sent is DCE, Rcvd is DTE", ROLE_DCE }, |
200 | | { NULL, NULL, 0 } |
201 | | }; |
202 | | |
203 | | static const value_string at_cmd_type_vals[] = { |
204 | | { 0x0d, "Action Command" }, |
205 | | { 0x3a, "Response" }, |
206 | | { 0x3d, "Action Command" }, |
207 | | { 0x3f, "Read Command" }, |
208 | | { 0x0d0a, "Response" }, |
209 | | { 0x3d3f, "Test Command" }, |
210 | | { 0, NULL } |
211 | | }; |
212 | | |
213 | | static const value_string cfun_fun_vals[] = { |
214 | | { 0, "Minimum functionality" }, |
215 | | { 1, "Full functionality" }, |
216 | | { 2, "Disable phone transmit RF circuits only" }, |
217 | | { 3, "Disable phone receive RF circuits only" }, |
218 | | { 4, "Disable phone both transmit and receive RF circuits" }, |
219 | | { 0, NULL } |
220 | | }; |
221 | | |
222 | | static const value_string cfun_rst_vals[] = { |
223 | | { 0, "Do not reset the MT before setting it to the requested power level" }, |
224 | | { 1, "Reset the MT before setting it to the requested power level" }, |
225 | | { 0, NULL } |
226 | | }; |
227 | | |
228 | | static const value_string cme_error_vals[] = { |
229 | | { 0, "Phone/AG failure" }, |
230 | | { 1, "No Connection to Phone" }, |
231 | | { 2, "Phone-adaptor Link Reserved" }, |
232 | | { 3, "Operation not Allowed" }, |
233 | | { 4, "Operation not Supported" }, |
234 | | { 5, "PH-SIM PIN required" }, |
235 | | { 6, "PH-FSIM PIN Required" }, |
236 | | { 7, "PH-FSIM PUK Required" }, |
237 | | { 10, "SIM not Inserted" }, |
238 | | { 11, "SIM PIN Required" }, |
239 | | { 12, "SIM PUK Required" }, |
240 | | { 13, "SIM Failure" }, |
241 | | { 14, "SIM Busy" }, |
242 | | { 15, "SIM Wrong" }, |
243 | | { 16, "Incorrect Password" }, |
244 | | { 17, "SIM PIN2 Required" }, |
245 | | { 18, "SIM PUK2 Required" }, |
246 | | { 20, "Memory Full" }, |
247 | | { 21, "Invalid Index" }, |
248 | | { 22, "Not Found" }, |
249 | | { 23, "Memory Failure" }, |
250 | | { 24, "Text String too Long" }, |
251 | | { 25, "Invalid Characters in Text String" }, |
252 | | { 26, "Dial String too Long" }, |
253 | | { 27, "Invalid Characters in Dial String" }, |
254 | | { 30, "No Network Service" }, |
255 | | { 31, "Network Timeout" }, |
256 | | { 32, "Network not Allowed - Emergency Calls Only" }, |
257 | | { 40, "Network Personalization PIN Required" }, |
258 | | { 41, "Network Personalization PUK Required" }, |
259 | | { 42, "Network Subset Personalization PIN Required" }, |
260 | | { 43, "Network Subset Personalization PUK Required" }, |
261 | | { 44, "Service Provider Personalization PIN Required" }, |
262 | | { 45, "Service Provider Personalization PUK Required" }, |
263 | | { 46, "Corporate Personalization PIN Required" }, |
264 | | { 47, "Corporate Personalization PUK Required" }, |
265 | | { 48, "Hidden Key Required" }, |
266 | | { 49, "EAP Method not Supported" }, |
267 | | { 50, "Incorrect Parameters" }, |
268 | | { 100, "Unknown" }, |
269 | | { 0, NULL } |
270 | | }; |
271 | | |
272 | | static const value_string cmee_vals[] = { |
273 | | { 0, "Disabled" }, |
274 | | { 1, "Enabled" }, |
275 | | { 2, "Verbose" }, |
276 | | { 0, NULL } |
277 | | }; |
278 | | |
279 | | static const value_string cmux_port_speed_vals[] = { |
280 | | { 1, "9,600 bit/s" }, |
281 | | { 2, "19,200 bit/s" }, |
282 | | { 3, "38,400 bit/s" }, |
283 | | { 4, "57,600 bit/s" }, |
284 | | { 5, "115,200 bit/s" }, |
285 | | { 6, "230,400 bit/s" }, |
286 | | { 0, NULL } |
287 | | }; |
288 | | |
289 | | static const value_string cmux_subset_vals[] = { |
290 | | { 0, "UIH frames used only" }, |
291 | | { 1, "UI frames used only" }, |
292 | | { 2, "I frames used only" }, |
293 | | { 0, NULL } |
294 | | }; |
295 | | |
296 | | static const value_string cmux_transparency_vals[] = { |
297 | | { 0, "Basic option" }, |
298 | | { 1, "Advanced option" }, |
299 | | { 0, NULL } |
300 | | }; |
301 | | |
302 | | static const value_string chld_vals[] = { |
303 | | { 0, "Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call" }, |
304 | | { 1, "Releases all active calls (if any exist) and accepts the other (held or waiting) call" }, |
305 | | { 2, "Places all active calls (if any exist) on hold and accepts the other (held or waiting) call" }, |
306 | | { 3, "Adds a held call to the conversation" }, |
307 | | { 4, "Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)" }, |
308 | | { 0, NULL } |
309 | | }; |
310 | | |
311 | | static const value_string cops_mode_vals[] = { |
312 | | { 0, "Automatic" }, |
313 | | { 1, "Manual" }, |
314 | | { 2, "Deregister from Network" }, |
315 | | { 3, "Set Only Format" }, |
316 | | { 4, "Manual/Automatic" }, |
317 | | { 0, NULL } |
318 | | }; |
319 | | |
320 | | static const value_string cops_format_vals[] = { |
321 | | { 0, "Long Format Alphanumeric" }, |
322 | | { 1, "Short Format Alphanumeric" }, |
323 | | { 2, "Numeric" }, |
324 | | { 0, NULL } |
325 | | }; |
326 | | |
327 | | static const value_string cops_act_vals[] = { |
328 | | { 0, "GSM" }, |
329 | | { 1, "GSM Compact" }, |
330 | | { 2, "UTRAN" }, |
331 | | { 3, "GSM with EGPRS" }, |
332 | | { 4, "UTRAN with HSDPA" }, |
333 | | { 5, "UTRAN with HSUPA" }, |
334 | | { 6, "UTRAN with HSDPA and HSUPA" }, |
335 | | { 7, "E-UTRAN" }, |
336 | | { 8, "EC-GSM-IoT (A/Gb mode)" }, |
337 | | { 9, "E-UTRAN (NB-S1 mode)" }, |
338 | | { 10, "E-UTRA connected to a 5GCN" }, |
339 | | { 11, "NR connected to a 5GCCN" }, |
340 | | { 12, "NR connected to an EPS core" }, |
341 | | { 13, "NG-RAN" }, |
342 | | { 14, "E-UTRA-NR dual connectivity" }, |
343 | | { 0, NULL } |
344 | | }; |
345 | | |
346 | | static const range_string at_type_vals[] = { |
347 | | { 128, 143, "The phone number format may be a national or international format, and may contain prefix and/or escape digits. No changes on the number presentation are required." }, |
348 | | { 144, 159, "The phone number format is an international number, including the country code prefix. If the plus sign (\"+\") is not included as part of the number and shall be added by the AG as needed." }, |
349 | | { 160, 175, "National number. No prefix nor escape digits included." }, |
350 | | { 0, 0, NULL } |
351 | | }; |
352 | | |
353 | | static const value_string cli_validity_vals[] = { |
354 | | { 0, "CLI Valid" }, |
355 | | { 1, "CLI has been withheld by the originator" }, |
356 | | { 2, "CLI is not available due to interworking problems or limitations of originating network" }, |
357 | | { 0, NULL } |
358 | | }; |
359 | | |
360 | | static const value_string cnum_service_vals[] = { |
361 | | { 0, "Asynchronous Modem" }, |
362 | | { 1, "Synchronous Modem" }, |
363 | | { 2, "PAD Access" }, |
364 | | { 3, "Packet Access" }, |
365 | | { 4, "Voice" }, |
366 | | { 5, "Fax" }, |
367 | | { 0, NULL } |
368 | | }; |
369 | | |
370 | | static const value_string cnum_itc_vals[] = { |
371 | | { 0, "3.1 kHz" }, |
372 | | { 1, "UDI" }, |
373 | | { 0, NULL } |
374 | | }; |
375 | | |
376 | | static const value_string clip_mode_vals[] = { |
377 | | { 0, "Disabled" }, |
378 | | { 1, "Enabled" }, |
379 | | { 0, NULL } |
380 | | }; |
381 | | |
382 | | static const value_string clip_status_vals[] = { |
383 | | { 0, "CLIP not Provisioned" }, |
384 | | { 1, "CLIP Provisioned" }, |
385 | | { 2, "Unknown" }, |
386 | | { 0, NULL } |
387 | | }; |
388 | | |
389 | | static const value_string clcc_dir_vals[] = { |
390 | | { 0, "Mobile Originated" }, |
391 | | { 1, "Mobile Terminated" }, |
392 | | { 0, NULL } |
393 | | }; |
394 | | |
395 | | static const value_string clcc_stat_vals[] = { |
396 | | { 0, "Active" }, |
397 | | { 1, "Held" }, |
398 | | { 2, "Dialing" }, |
399 | | { 3, "Alerting" }, |
400 | | { 4, "Incoming" }, |
401 | | { 5, "Waiting" }, |
402 | | { 0, NULL } |
403 | | }; |
404 | | |
405 | | static const value_string clcc_mode_vals[] = { |
406 | | { 0, "Voice" }, |
407 | | { 1, "Data" }, |
408 | | { 2, "Fax" }, |
409 | | { 3, "Voice Followed by Data, Voice Mode" }, |
410 | | { 4, "Alternating Voice/Data, Voice Mode" }, |
411 | | { 5, "Alternating Voice/Fax, Voice Mode" }, |
412 | | { 6, "Voice Followed by Data, Data Mode" }, |
413 | | { 7, "Alternating Voice/Data, Data Mode" }, |
414 | | { 8, "Alternating Voice/Fax, Fax Mode" }, |
415 | | { 9, "Unknown" }, |
416 | | { 0, NULL } |
417 | | }; |
418 | | |
419 | | static const value_string clcc_mpty_vals[] = { |
420 | | { 0, "Call is not one of multiparty (conference) call parties" }, |
421 | | { 1, "Call is one of multiparty (conference) call parties" }, |
422 | | { 0, NULL } |
423 | | }; |
424 | | |
425 | | static const value_string cmgr_mode_vals[] = { |
426 | | { 0, "Normal (Change unread to read)" }, |
427 | | { 1, "Do not change unread to read" }, |
428 | | { 0, NULL } |
429 | | }; |
430 | | |
431 | | static const value_string cmgr_stat_vals[] = { |
432 | | { 0, "Received unread (i.e. new message)" }, |
433 | | { 1, "Received read" }, |
434 | | { 2, "Stored unsent" }, |
435 | | { 3, "Stored sent" }, |
436 | | { 4, "All" }, |
437 | | { 0, NULL } |
438 | | }; |
439 | | |
440 | | static const value_string ccwa_show_result_code_vals[] = { |
441 | | { 0, "Disabled" }, |
442 | | { 1, "Enabled" }, |
443 | | { 0, NULL } |
444 | | }; |
445 | | |
446 | | static const value_string ccwa_mode_vals[] = { |
447 | | { 0, "Disabled" }, |
448 | | { 1, "Enabled" }, |
449 | | { 2, "Query Status" }, |
450 | | { 0, NULL } |
451 | | }; |
452 | | |
453 | | static const value_string ccwa_class_vals[] = { |
454 | | { 1, "Voice" }, |
455 | | { 2, "Data" }, |
456 | | { 4, "Fax" }, |
457 | | { 8, "Short Message Service" }, |
458 | | { 16, "Data Circuit Sync" }, |
459 | | { 32, "Data Circuit Async" }, |
460 | | { 64, "Dedicated Packet Access" }, |
461 | | { 128, "Dedicated PAD Access" }, |
462 | | { 0, NULL } |
463 | | }; |
464 | | |
465 | | static const value_string csq_ber_vals[] = { |
466 | | { 0, "Less than 0.2 %" }, |
467 | | { 1, "Between 0.2 % and 0.4 %" }, |
468 | | { 2, "Between 0.4 % and 0.8 %" }, |
469 | | { 3, "Between 0.8 % and 1.6 %" }, |
470 | | { 4, "Between 1.6 % and 3.2 %" }, |
471 | | { 5, "Between 3.2 % and 6.4 %" }, |
472 | | { 6, "Between 6.4 % and 12.8 %" }, |
473 | | { 7, "Greater than 12.8 %" }, |
474 | | { 99, "Not known or not detectable" }, |
475 | | { 0, NULL } |
476 | | }; |
477 | | |
478 | | static const value_string csq_rssi_vals[] = { |
479 | | { 0, "-113 dBm or less" }, |
480 | | { 1, "-111 dBm" }, |
481 | | { 2, "-109 dBm" }, |
482 | | { 3, "-107 dBm" }, |
483 | | { 4, "-105 dBm" }, |
484 | | { 5, "-103 dBm" }, |
485 | | { 6, "-101 dBm" }, |
486 | | { 7, "-99 dBm" }, |
487 | | { 8, "-97 dBm" }, |
488 | | { 9, "-95 dBm" }, |
489 | | { 10, "-93 dBm" }, |
490 | | { 11, "-91 dBm" }, |
491 | | { 12, "-89 dBm" }, |
492 | | { 13, "-87 dBm" }, |
493 | | { 14, "-85 dBm" }, |
494 | | { 15, "-83 dBm" }, |
495 | | { 16, "-81 dBm" }, |
496 | | { 17, "-79 dBm" }, |
497 | | { 18, "-77 dBm" }, |
498 | | { 19, "-75 dBm" }, |
499 | | { 20, "-73 dBm" }, |
500 | | { 21, "-71 dBm" }, |
501 | | { 22, "-69 dBm" }, |
502 | | { 23, "-67 dBm" }, |
503 | | { 24, "-65 dBm" }, |
504 | | { 25, "-63 dBm" }, |
505 | | { 26, "-61 dBm" }, |
506 | | { 27, "-59 dBm" }, |
507 | | { 28, "-57 dBm" }, |
508 | | { 29, "-55 dBm" }, |
509 | | { 30, "-53 dBm" }, |
510 | | { 31, "-51 dBm or greater" }, |
511 | | { 99, "Not known or not detectable" }, |
512 | | { 0, NULL } |
513 | | }; |
514 | | |
515 | | static const value_string zusim_usim_card_vals[] = { |
516 | | { 0, "SIM" }, |
517 | | { 1, "USIM" }, |
518 | | { 0, NULL } |
519 | | }; |
520 | | |
521 | | extern value_string_ext csd_data_rate_vals_ext; |
522 | | |
523 | | struct _at_packet_info_t; |
524 | | |
525 | | /* A command that either finished or is currently being processed */ |
526 | | typedef struct _at_processed_cmd_t { |
527 | | char name[STORE_COMMAND_MAX_LEN]; |
528 | | uint16_t type; |
529 | | /* Indicates how many more textual data lines are we expecting */ |
530 | | uint32_t expected_data_parts; |
531 | | /* Indicates how many textual data lines were already processed */ |
532 | | uint32_t consumed_data_parts; |
533 | | /* Index of the command in within the original AT packet */ |
534 | | uint32_t cmd_indx; |
535 | | /* Handler for textual data lines */ |
536 | | bool (*dissect_data)(tvbuff_t *tvb, packet_info *pinfo, |
537 | | proto_tree *tree, int offset, int role, uint16_t type, |
538 | | uint8_t *data_part_stream, unsigned data_part_number, |
539 | | int data_part_length, struct _at_packet_info_t *at_info); |
540 | | } at_processed_cmd_t; |
541 | | |
542 | | typedef struct _at_conv_info_t { |
543 | | at_processed_cmd_t dte_command; |
544 | | at_processed_cmd_t dce_command; |
545 | | } at_conv_info_t; |
546 | | |
547 | | typedef struct _at_packet_info_t { |
548 | | at_processed_cmd_t initial_dte_command; |
549 | | at_processed_cmd_t initial_dce_command; |
550 | | at_processed_cmd_t current_dte_command; |
551 | | at_processed_cmd_t current_dce_command; |
552 | | } at_packet_info_t; |
553 | | |
554 | | typedef struct _at_cmd_t { |
555 | | const char *name; |
556 | | const char *long_name; |
557 | | |
558 | | bool (*check_command)(int role, uint16_t type); |
559 | | bool (*dissect_parameter)(tvbuff_t *tvb, packet_info *pinfo, |
560 | | proto_tree *tree, int offset, int role, uint16_t type, |
561 | | uint8_t *parameter_stream, unsigned parameter_number, |
562 | | int parameter_length, at_packet_info_t *at_info, void **data); |
563 | | } at_cmd_t; |
564 | | |
565 | | static at_conv_info_t * |
566 | | get_at_conv_info(conversation_t *conversation) |
567 | 0 | { |
568 | 0 | if (!conversation) |
569 | 0 | return NULL; |
570 | 0 | at_conv_info_t *at_conv_info; |
571 | | /* do we have conversation specific data ? */ |
572 | 0 | at_conv_info = (at_conv_info_t *)conversation_get_proto_data(conversation, proto_at); |
573 | 0 | if (!at_conv_info) { |
574 | | /* no not yet so create some */ |
575 | 0 | at_conv_info = wmem_new0(wmem_file_scope(), at_conv_info_t); |
576 | 0 | conversation_add_proto_data(conversation, proto_at, at_conv_info); |
577 | 0 | } |
578 | 0 | return at_conv_info; |
579 | 0 | } |
580 | | |
581 | | static at_packet_info_t * |
582 | | get_at_packet_info(packet_info *pinfo, at_conv_info_t *at_conv) |
583 | 0 | { |
584 | 0 | at_packet_info_t *at_info; |
585 | 0 | at_info = (at_packet_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_at, 0); |
586 | 0 | if (!at_info) { |
587 | 0 | at_info = wmem_new0(wmem_file_scope(), at_packet_info_t); |
588 | 0 | p_add_proto_data(wmem_file_scope(), pinfo, proto_at, 0, at_info); |
589 | 0 | if(at_conv) { |
590 | 0 | at_info->initial_dce_command = at_conv->dce_command; |
591 | 0 | at_info->initial_dte_command = at_conv->dte_command; |
592 | 0 | } |
593 | 0 | } |
594 | 0 | at_info->current_dce_command = at_info->initial_dce_command; |
595 | 0 | at_info->current_dte_command = at_info->initial_dte_command; |
596 | 0 | return at_info; |
597 | 0 | } |
598 | | |
599 | | static void |
600 | | set_at_packet_info(packet_info *pinfo, at_conv_info_t *at_conv, at_packet_info_t *at_info) |
601 | 0 | { |
602 | 0 | if(at_conv && !PINFO_FD_VISITED(pinfo)) |
603 | 0 | { |
604 | 0 | at_conv->dce_command = at_info->current_dce_command; |
605 | 0 | at_conv->dte_command = at_info->current_dte_command; |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | | static at_processed_cmd_t *get_current_role_last_command(at_packet_info_t *at_info, uint32_t role) |
610 | 0 | { |
611 | 0 | if(!at_info) return NULL; |
612 | 0 | return role == ROLE_DCE ? &at_info->current_dce_command : &at_info->current_dte_command; |
613 | 0 | } |
614 | | |
615 | | static uint32_t get_uint_parameter(wmem_allocator_t *pool, uint8_t *parameter_stream, int parameter_length) |
616 | 0 | { |
617 | 0 | uint32_t value; |
618 | 0 | char *val; |
619 | |
|
620 | 0 | val = (char*) wmem_alloc(pool, parameter_length + 1); |
621 | 0 | memcpy(val, parameter_stream, parameter_length); |
622 | 0 | val[parameter_length] = '\0'; |
623 | 0 | value = (uint32_t) g_ascii_strtoull(val, NULL, 10); |
624 | |
|
625 | 0 | return value; |
626 | 0 | } |
627 | | |
628 | 0 | static bool check_only_dce_role(int role, uint16_t type) { |
629 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE_ACK) return true; |
630 | | |
631 | 0 | return false; |
632 | 0 | } |
633 | | |
634 | 0 | static bool check_only_dte_role(int role, uint16_t type) { |
635 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) return true; |
636 | | |
637 | 0 | return false; |
638 | 0 | } |
639 | | |
640 | 0 | static bool check_ccwa(int role, uint16_t type) { |
641 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
642 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
643 | | |
644 | 0 | return false; |
645 | 0 | } |
646 | | |
647 | 0 | static bool check_cfun(int role, uint16_t type) { |
648 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
649 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
650 | | |
651 | 0 | return false; |
652 | 0 | } |
653 | | |
654 | 0 | static bool check_cgdcont(int role, uint16_t type) { |
655 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_ACTION_SIMPLY || |
656 | 0 | type == TYPE_READ || type == TYPE_TEST)) return true; |
657 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
658 | | |
659 | 0 | return false; |
660 | 0 | } |
661 | | |
662 | 0 | static bool check_cgmi(int role, uint16_t type) { |
663 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
664 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
665 | | |
666 | 0 | return false; |
667 | 0 | } |
668 | | |
669 | 0 | static bool check_cgmm(int role, uint16_t type) { |
670 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
671 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
672 | | |
673 | 0 | return false; |
674 | 0 | } |
675 | | |
676 | 0 | static bool check_cgmr(int role, uint16_t type) { |
677 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
678 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
679 | | |
680 | 0 | return false; |
681 | 0 | } |
682 | | |
683 | 0 | static bool check_cgsn(int role, uint16_t type) { |
684 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
685 | | |
686 | 0 | return false; |
687 | 0 | } |
688 | | |
689 | 0 | static bool check_chld(int role, uint16_t type) { |
690 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true; |
691 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
692 | | |
693 | 0 | return false; |
694 | 0 | } |
695 | | |
696 | 0 | static bool check_chup(int role, uint16_t type) { |
697 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
698 | | |
699 | 0 | return false; |
700 | 0 | } |
701 | | |
702 | 0 | static bool check_ciev(int role, uint16_t type) { |
703 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
704 | | |
705 | 0 | return false; |
706 | 0 | } |
707 | | |
708 | 0 | static bool check_cimi(int role, uint16_t type) { |
709 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
710 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
711 | | |
712 | 0 | return false; |
713 | 0 | } |
714 | | |
715 | 0 | static bool check_cind(int role, uint16_t type) { |
716 | 0 | if (role == ROLE_DTE && (type == TYPE_READ || type == TYPE_TEST)) return true; |
717 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
718 | | |
719 | 0 | return false; |
720 | 0 | } |
721 | | |
722 | 0 | static bool check_clac(int role, uint16_t type) { |
723 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
724 | | |
725 | 0 | return false; |
726 | 0 | } |
727 | | |
728 | 0 | static bool check_clcc(int role, uint16_t type) { |
729 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
730 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
731 | | |
732 | 0 | return false; |
733 | 0 | } |
734 | | |
735 | 0 | static bool check_clip(int role, uint16_t type) { |
736 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
737 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
738 | | |
739 | 0 | return false; |
740 | 0 | } |
741 | | |
742 | 0 | static bool check_cme(int role, uint16_t type) { |
743 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
744 | | |
745 | 0 | return false; |
746 | 0 | } |
747 | | |
748 | 0 | static bool check_cmee(int role, uint16_t type) { |
749 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_ACTION_SIMPLY || |
750 | 0 | type == TYPE_TEST || type == TYPE_READ)) return true; |
751 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
752 | | |
753 | 0 | return false; |
754 | 0 | } |
755 | | |
756 | 0 | static bool check_cmer(int role, uint16_t type) { |
757 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
758 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
759 | | |
760 | 0 | return false; |
761 | 0 | } |
762 | | |
763 | 0 | static bool check_cmgl(int role, uint16_t type) { |
764 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
765 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
766 | | |
767 | 0 | return false; |
768 | 0 | } |
769 | | |
770 | 0 | static bool check_cmgr(int role, uint16_t type) { |
771 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true; |
772 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
773 | | |
774 | 0 | return false; |
775 | 0 | } |
776 | | |
777 | 0 | static bool check_cmux(int role, uint16_t type) { |
778 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
779 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
780 | | |
781 | 0 | return false; |
782 | 0 | } |
783 | | |
784 | 0 | static bool check_cnum(int role, uint16_t type) { |
785 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) return true; |
786 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
787 | | |
788 | 0 | return false; |
789 | 0 | } |
790 | | |
791 | 0 | static bool check_cops(int role, uint16_t type) { |
792 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ)) return true; |
793 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
794 | | |
795 | 0 | return false; |
796 | 0 | } |
797 | | |
798 | 0 | static bool check_cpin(int role, uint16_t type) { |
799 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
800 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
801 | | |
802 | 0 | return false; |
803 | 0 | } |
804 | | |
805 | 0 | static bool check_cpms(int role, uint16_t type) { |
806 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
807 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
808 | | |
809 | 0 | return false; |
810 | 0 | } |
811 | | |
812 | 0 | static bool check_cscs(int role, uint16_t type) { |
813 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true; |
814 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
815 | | |
816 | 0 | return false; |
817 | 0 | } |
818 | | |
819 | 0 | static bool check_csim(int role, uint16_t type) { |
820 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true; |
821 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
822 | | |
823 | 0 | return false; |
824 | 0 | } |
825 | | |
826 | 0 | static bool check_csq(int role, uint16_t type) { |
827 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
828 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
829 | | |
830 | 0 | return false; |
831 | 0 | } |
832 | | |
833 | 0 | static bool check_csupi(int role, uint16_t type) { |
834 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
835 | | |
836 | 0 | return false; |
837 | 0 | } |
838 | | |
839 | 0 | static bool check_gmi(int role, uint16_t type) { |
840 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
841 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
842 | | |
843 | 0 | return false; |
844 | 0 | } |
845 | | |
846 | 0 | static bool check_gmm(int role, uint16_t type) { |
847 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
848 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
849 | | |
850 | 0 | return false; |
851 | 0 | } |
852 | | |
853 | 0 | static bool check_gmr(int role, uint16_t type) { |
854 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
855 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
856 | | |
857 | 0 | return false; |
858 | 0 | } |
859 | | |
860 | 0 | static bool check_gsn(int role, uint16_t type) { |
861 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true; |
862 | | |
863 | 0 | return false; |
864 | 0 | } |
865 | | |
866 | 0 | static bool check_vts(int role, uint16_t type) { |
867 | 0 | if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true; |
868 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
869 | | |
870 | 0 | return false; |
871 | 0 | } |
872 | | |
873 | 0 | static bool check_zpas(int role, uint16_t type) { |
874 | 0 | if (role == ROLE_DTE && type == TYPE_READ) return true; |
875 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
876 | | |
877 | 0 | return false; |
878 | 0 | } |
879 | | |
880 | 0 | static bool check_zusim(int role, uint16_t type) { |
881 | 0 | if (role == ROLE_DTE && type == TYPE_TEST) return true; |
882 | 0 | if (role == ROLE_DCE && type == TYPE_RESPONSE) return true; |
883 | | |
884 | 0 | return false; |
885 | 0 | } |
886 | | |
887 | | static bool |
888 | | dissect_ccwa_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
889 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
890 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
891 | 0 | { |
892 | 0 | proto_item *pitem; |
893 | 0 | uint32_t value; |
894 | |
|
895 | 0 | if (!check_ccwa(role, type)) return false; |
896 | | |
897 | 0 | if (role == ROLE_DTE && parameter_number > 2) return false; |
898 | 0 | if (role == ROLE_DCE && parameter_number > 7) return false; |
899 | | |
900 | 0 | if (role == ROLE_DTE) switch (parameter_number) { |
901 | 0 | case 0: |
902 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
903 | 0 | proto_tree_add_uint(tree, hf_ccwa_show_result_code, tvb, offset, parameter_length, value); |
904 | 0 | break; |
905 | 0 | case 1: |
906 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
907 | 0 | proto_tree_add_uint(tree, hf_ccwa_mode, tvb, offset, parameter_length, value); |
908 | 0 | break; |
909 | 0 | case 2: |
910 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
911 | 0 | proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value); |
912 | 0 | break; |
913 | 0 | } |
914 | | |
915 | | /* If AT+CCWA = 1 */ |
916 | 0 | if (role == ROLE_DCE) switch (parameter_number) { |
917 | 0 | case 0: |
918 | 0 | proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_ASCII); |
919 | 0 | break; |
920 | 0 | case 1: |
921 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
922 | 0 | pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value); |
923 | 0 | if (value < 128 || value > 175) |
924 | 0 | expert_add_info(pinfo, pitem, &ei_at_type); |
925 | 0 | break; |
926 | 0 | case 2: |
927 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
928 | 0 | proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value); |
929 | 0 | break; |
930 | 0 | case 3: |
931 | 0 | proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_ASCII); |
932 | 0 | break; |
933 | 0 | case 4: |
934 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
935 | 0 | proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value); |
936 | 0 | break; |
937 | 0 | case 5: |
938 | 0 | proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_ASCII); |
939 | 0 | break; |
940 | 0 | case 6: |
941 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
942 | 0 | proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value); |
943 | 0 | break; |
944 | 0 | case 7: |
945 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
946 | 0 | proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value); |
947 | 0 | break; |
948 | 0 | } |
949 | | |
950 | 0 | return true; |
951 | 0 | } |
952 | | |
953 | | static bool |
954 | | dissect_cfun_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
955 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
956 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
957 | 0 | { |
958 | 0 | proto_item *pitem; |
959 | 0 | uint32_t value; |
960 | |
|
961 | 0 | if (!check_cfun(role, type)) return false; |
962 | | |
963 | 0 | if (parameter_number > 1) return false; |
964 | | |
965 | 0 | if (role == ROLE_DTE) switch (parameter_number) { |
966 | 0 | case 0: |
967 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
968 | 0 | pitem = proto_tree_add_uint(tree, hf_cfun_fun, tvb, offset, parameter_length, value); |
969 | 0 | if (value > 4 && value < 128) |
970 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_res_fun); |
971 | 0 | else if (value >= 128) |
972 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_range_fun); |
973 | 0 | break; |
974 | 0 | case 1: |
975 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
976 | 0 | pitem = proto_tree_add_uint(tree, hf_cfun_rst, tvb, offset, parameter_length, value); |
977 | 0 | if (value > 1) |
978 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_rst); |
979 | 0 | break; |
980 | 0 | } |
981 | | |
982 | | /* TODO: Currently assuming response is for READ command, add support for |
983 | | * TEST commands response */ |
984 | 0 | if (role == ROLE_DCE) switch (parameter_number) { |
985 | 0 | case 0: |
986 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
987 | 0 | pitem = proto_tree_add_uint(tree, hf_cfun_fun, tvb, offset, parameter_length, value); |
988 | 0 | if (value > 4 && value < 128) |
989 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_res_fun); |
990 | 0 | else if (value >= 128) |
991 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_range_fun); |
992 | 0 | break; |
993 | 0 | case 1: |
994 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
995 | 0 | pitem = proto_tree_add_uint(tree, hf_cfun_rst, tvb, offset, parameter_length, value); |
996 | 0 | if (value > 1) |
997 | 0 | expert_add_info(pinfo, pitem, &ei_cfun_rst); |
998 | 0 | break; |
999 | 0 | } |
1000 | | |
1001 | 0 | return true; |
1002 | 0 | } |
1003 | | |
1004 | | static bool |
1005 | | dissect_cgdcont_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1006 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1007 | | unsigned parameter_number, int parameter_length, |
1008 | | at_packet_info_t *at_info _U_, void **data _U_) |
1009 | 0 | { |
1010 | 0 | uint32_t value; |
1011 | |
|
1012 | 0 | if (!check_cgdcont(role, type)) return false; |
1013 | | |
1014 | 0 | switch (parameter_number) { |
1015 | 0 | case 0: |
1016 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1017 | 0 | proto_tree_add_uint(tree, hf_cgdcont_cid, tvb, offset, parameter_length, value); |
1018 | 0 | break; |
1019 | 0 | case 1: |
1020 | 0 | proto_tree_add_item(tree, hf_cgdcont_pdp_type, tvb, offset, parameter_length, ENC_ASCII); |
1021 | 0 | break; |
1022 | 0 | case 2: |
1023 | 0 | proto_tree_add_item(tree, hf_cgdcont_apn, tvb, offset, parameter_length, ENC_ASCII); |
1024 | 0 | break; |
1025 | 0 | case 3: |
1026 | 0 | proto_tree_add_item(tree, hf_cgdcont_pdp_addr, tvb, offset, parameter_length, ENC_ASCII); |
1027 | 0 | break; |
1028 | 0 | case 4: |
1029 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1030 | 0 | proto_tree_add_uint(tree, hf_cgdcont_d_comp, tvb, offset, parameter_length, value); |
1031 | 0 | break; |
1032 | 0 | case 5: |
1033 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1034 | 0 | proto_tree_add_uint(tree, hf_cgdcont_h_comp, tvb, offset, parameter_length, value); |
1035 | 0 | break; |
1036 | 0 | default: |
1037 | 0 | proto_tree_add_item(tree, hf_parameter, tvb, offset, parameter_length, ENC_ASCII); |
1038 | 0 | break; |
1039 | 0 | } |
1040 | | |
1041 | 0 | return true; |
1042 | 0 | } |
1043 | | |
1044 | | static bool |
1045 | | dissect_cgmi_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1046 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1047 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1048 | 0 | { |
1049 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1050 | 0 | return false; |
1051 | 0 | } |
1052 | | |
1053 | 0 | if (parameter_number > 1) return false; |
1054 | | |
1055 | 0 | proto_tree_add_item(tree, hf_cgmi_manufacturer_id, tvb, offset, parameter_length, ENC_ASCII); |
1056 | |
|
1057 | 0 | return true; |
1058 | 0 | } |
1059 | | |
1060 | | static bool |
1061 | | dissect_cgmm_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1062 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1063 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1064 | 0 | { |
1065 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1066 | 0 | return false; |
1067 | 0 | } |
1068 | | |
1069 | 0 | if (parameter_number > 1) return false; |
1070 | | |
1071 | 0 | proto_tree_add_item(tree, hf_cgmm_model_id, tvb, offset, parameter_length, ENC_ASCII); |
1072 | |
|
1073 | 0 | return true; |
1074 | 0 | } |
1075 | | |
1076 | | static bool |
1077 | | dissect_cgmr_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1078 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1079 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1080 | 0 | { |
1081 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1082 | 0 | return false; |
1083 | 0 | } |
1084 | | |
1085 | 0 | if (parameter_number > 1) return false; |
1086 | | |
1087 | 0 | proto_tree_add_item(tree, hf_cgmr_revision_id, tvb, offset, parameter_length, ENC_ASCII); |
1088 | |
|
1089 | 0 | return true; |
1090 | 0 | } |
1091 | | |
1092 | | static bool |
1093 | | dissect_chld_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1094 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1095 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1096 | 0 | { |
1097 | 0 | uint32_t value; |
1098 | |
|
1099 | 0 | if (!check_chld(role, type)) return false; |
1100 | | |
1101 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number == 0) { |
1102 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, 1); |
1103 | |
|
1104 | 0 | if (parameter_length >= 2) { |
1105 | 0 | if (tvb_get_uint8(tvb, offset + 1) == 'x') { |
1106 | 0 | if (value == 1) |
1107 | 0 | proto_tree_add_item(tree, hf_chld_mode_1x, tvb, offset, parameter_length, ENC_ASCII); |
1108 | 0 | else if (value == 2) |
1109 | 0 | proto_tree_add_item(tree, hf_chld_mode_2x, tvb, offset, parameter_length, ENC_ASCII); |
1110 | 0 | } |
1111 | |
|
1112 | 0 | if (tvb_get_uint8(tvb, offset + 1) != 'x' || value > 4) { |
1113 | 0 | proto_tree_add_expert(tree, pinfo, &ei_chld_mode, tvb, offset, parameter_length); |
1114 | 0 | } |
1115 | 0 | } |
1116 | |
|
1117 | 0 | proto_tree_add_uint(tree, hf_chld_mode, tvb, offset, parameter_length, value); |
1118 | 0 | return true; |
1119 | 0 | } |
1120 | | |
1121 | | /* Type == Test */ |
1122 | 0 | proto_tree_add_item(tree, hf_chld_supported_modes, tvb, offset, |
1123 | 0 | parameter_length, ENC_ASCII); |
1124 | |
|
1125 | 0 | return true; |
1126 | 0 | } |
1127 | | |
1128 | | static bool |
1129 | | dissect_ciev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1130 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1131 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data) |
1132 | 0 | { |
1133 | 0 | uint32_t value; |
1134 | 0 | unsigned indicator_index; |
1135 | |
|
1136 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return true; |
1137 | 0 | if (parameter_number > 1) return false; |
1138 | | |
1139 | 0 | switch (parameter_number) { |
1140 | 0 | case 0: |
1141 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1142 | 0 | proto_tree_add_uint(tree, hf_ciev_indicator_index, tvb, offset, parameter_length, value); |
1143 | 0 | *data = wmem_alloc(pinfo->pool, sizeof(unsigned)); |
1144 | 0 | *((unsigned *) *data) = value; |
1145 | 0 | break; |
1146 | 0 | case 1: |
1147 | 0 | indicator_index = *((unsigned *) *data) - 1; |
1148 | 0 | if (indicator_index > 19) { |
1149 | 0 | proto_tree_add_expert(tree, pinfo, &ei_ciev_indicator, tvb, offset, parameter_length); |
1150 | 0 | } else { |
1151 | 0 | proto_tree_add_item(tree, hf_indicator[indicator_index], tvb, offset, parameter_length, ENC_NA | ENC_ASCII); |
1152 | 0 | } |
1153 | 0 | break; |
1154 | 0 | } |
1155 | | |
1156 | 0 | return true; |
1157 | 0 | } |
1158 | | |
1159 | | static bool |
1160 | | dissect_cimi_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1161 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1162 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1163 | 0 | { |
1164 | 0 | proto_item *pitem; |
1165 | |
|
1166 | 0 | if (!check_cimi(role, type)) return false; |
1167 | | |
1168 | 0 | if (role == ROLE_DTE) return false; |
1169 | 0 | if (parameter_number > 0) return false; |
1170 | | |
1171 | | /* Only parameter is found in the response from DCE - the IMSI */ |
1172 | 0 | pitem = proto_tree_add_item(tree, hf_cimi_imsi, tvb, offset, parameter_length, ENC_ASCII); |
1173 | | /* Hiding the AT IMSI item because we are showing the detailed E.212 item */ |
1174 | 0 | proto_item_set_hidden(pitem); |
1175 | 0 | dissect_e212_utf8_imsi(tvb, pinfo, tree, offset, parameter_length); |
1176 | |
|
1177 | 0 | return true; |
1178 | 0 | } |
1179 | | |
1180 | | static bool |
1181 | | dissect_cind_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1182 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1183 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1184 | 0 | { |
1185 | 0 | if (!check_cind(role, type)) return false; |
1186 | 0 | if (parameter_number > 19) return false; |
1187 | | |
1188 | 0 | proto_tree_add_item(tree, hf_indicator[parameter_number], tvb, offset, |
1189 | 0 | parameter_length, ENC_NA | ENC_ASCII); |
1190 | |
|
1191 | 0 | return true; |
1192 | 0 | } |
1193 | | |
1194 | | static bool |
1195 | | dissect_clcc_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1196 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1197 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1198 | 0 | { |
1199 | 0 | proto_item *pitem; |
1200 | 0 | uint32_t value; |
1201 | |
|
1202 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) || |
1203 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1204 | 0 | return false; |
1205 | 0 | } |
1206 | | |
1207 | 0 | if (parameter_number > 8) return false; |
1208 | | |
1209 | 0 | switch (parameter_number) { |
1210 | 0 | case 0: |
1211 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1212 | 0 | proto_tree_add_uint(tree, hf_clcc_id, tvb, offset, parameter_length, value); |
1213 | 0 | break; |
1214 | 0 | case 1: |
1215 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1216 | 0 | proto_tree_add_uint(tree, hf_clcc_dir, tvb, offset, parameter_length, value); |
1217 | 0 | break; |
1218 | 0 | case 2: |
1219 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1220 | 0 | proto_tree_add_uint(tree, hf_clcc_stat, tvb, offset, parameter_length, value); |
1221 | 0 | break; |
1222 | 0 | case 3: |
1223 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1224 | 0 | proto_tree_add_uint(tree, hf_clcc_mode, tvb, offset, parameter_length, value); |
1225 | 0 | break; |
1226 | 0 | case 4: |
1227 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1228 | 0 | proto_tree_add_uint(tree, hf_clcc_mpty, tvb, offset, parameter_length, value); |
1229 | 0 | break; |
1230 | 0 | case 5: |
1231 | 0 | proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_ASCII); |
1232 | 0 | break; |
1233 | 0 | case 6: |
1234 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1235 | 0 | pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value); |
1236 | 0 | if (value < 128 || value > 175) |
1237 | 0 | expert_add_info(pinfo, pitem, &ei_at_type); |
1238 | 0 | break; |
1239 | 0 | case 7: |
1240 | 0 | proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_ASCII); |
1241 | 0 | break; |
1242 | 0 | case 8: |
1243 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1244 | 0 | proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value); |
1245 | 0 | break; |
1246 | 0 | } |
1247 | | |
1248 | 0 | return true; |
1249 | 0 | } |
1250 | | |
1251 | | static bool |
1252 | | dissect_clip_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1253 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1254 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1255 | 0 | { |
1256 | 0 | proto_item *pitem; |
1257 | 0 | uint32_t value; |
1258 | |
|
1259 | 0 | if (!check_clip(role, type)) |
1260 | 0 | return false; |
1261 | | |
1262 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number > 1) |
1263 | 0 | return false; |
1264 | 0 | else if (role == ROLE_DCE && parameter_number > 5) |
1265 | 0 | return false; |
1266 | | |
1267 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION) switch (parameter_number) { |
1268 | 0 | case 0: |
1269 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1270 | 0 | proto_tree_add_uint(tree, hf_clip_mode, tvb, offset, parameter_length, value); |
1271 | 0 | break; |
1272 | 0 | case 1: |
1273 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1274 | 0 | proto_tree_add_uint(tree, hf_clip_status, tvb, offset, parameter_length, value); |
1275 | 0 | break; |
1276 | 0 | } else { |
1277 | 0 | switch (parameter_number) { |
1278 | 0 | case 0: |
1279 | 0 | proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_ASCII); |
1280 | 0 | break; |
1281 | 0 | case 1: |
1282 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1283 | 0 | pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value); |
1284 | 0 | if (value < 128 || value > 175) |
1285 | 0 | expert_add_info(pinfo, pitem, &ei_at_type); |
1286 | 0 | break; |
1287 | 0 | case 2: |
1288 | 0 | proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_ASCII); |
1289 | 0 | break; |
1290 | 0 | case 3: |
1291 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1292 | 0 | proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value); |
1293 | 0 | break; |
1294 | 0 | case 4: |
1295 | 0 | proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_ASCII); |
1296 | 0 | break; |
1297 | 0 | case 5: |
1298 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1299 | 0 | proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value); |
1300 | 0 | break; |
1301 | 0 | } |
1302 | 0 | } |
1303 | | |
1304 | 0 | return true; |
1305 | 0 | } |
1306 | | |
1307 | | static bool |
1308 | | dissect_cme_error_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1309 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1310 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1311 | 0 | { |
1312 | 0 | uint32_t value; |
1313 | 0 | int i; |
1314 | 0 | char curr_char; |
1315 | |
|
1316 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1317 | 0 | return false; |
1318 | 0 | } |
1319 | | |
1320 | 0 | if (parameter_number > 0) return false; |
1321 | | |
1322 | | /* CME Error might work in 2 modes: Numeric error codes or Verbose error messages */ |
1323 | | /* if the parameter stream contains anything but digits and whitespaces, assume verbose */ |
1324 | 0 | for (i = 0; i < parameter_length; i++) { |
1325 | 0 | curr_char = parameter_stream[i]; |
1326 | 0 | if (!g_ascii_isdigit(curr_char) && curr_char != ' ') { |
1327 | 0 | proto_tree_add_item(tree, hf_cme_error_verbose, tvb, offset, parameter_length, ENC_ASCII); |
1328 | 0 | return true; |
1329 | 0 | } |
1330 | 0 | } |
1331 | | /* Assume numeric error code*/ |
1332 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1333 | 0 | proto_tree_add_uint(tree, hf_cme_error, tvb, offset, parameter_length, value); |
1334 | |
|
1335 | 0 | return true; |
1336 | 0 | } |
1337 | | |
1338 | | static bool |
1339 | | dissect_cmee_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1340 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1341 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1342 | 0 | { |
1343 | 0 | uint32_t value; |
1344 | |
|
1345 | 0 | if (!(role == ROLE_DTE && type == TYPE_ACTION) && |
1346 | 0 | !(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1347 | 0 | return false; |
1348 | 0 | } |
1349 | | |
1350 | 0 | if (parameter_number > 0) return false; |
1351 | | |
1352 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1353 | 0 | proto_tree_add_uint(tree, hf_cmee, tvb, offset, parameter_length, value); |
1354 | |
|
1355 | 0 | return true; |
1356 | 0 | } |
1357 | | |
1358 | | static bool |
1359 | | dissect_cmer_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1360 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1361 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1362 | 0 | { |
1363 | 0 | proto_item *pitem; |
1364 | 0 | uint32_t value; |
1365 | |
|
1366 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION))) { |
1367 | 0 | return false; |
1368 | 0 | } |
1369 | | |
1370 | 0 | if (parameter_number > 4) return false; |
1371 | | |
1372 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1373 | |
|
1374 | 0 | switch (parameter_number) { |
1375 | 0 | case 0: |
1376 | 0 | pitem = proto_tree_add_uint(tree, hf_cmer_mode, tvb, offset, parameter_length, value); |
1377 | 0 | if (value > 3) |
1378 | 0 | expert_add_info(pinfo, pitem, &ei_cmer_mode); |
1379 | 0 | break; |
1380 | 0 | case 1: |
1381 | 0 | pitem = proto_tree_add_uint(tree, hf_cmer_keyp, tvb, offset, parameter_length, value); |
1382 | 0 | if (value > 2) |
1383 | 0 | expert_add_info(pinfo, pitem, &ei_cmer_keyp); |
1384 | 0 | break; |
1385 | 0 | case 2: |
1386 | 0 | pitem = proto_tree_add_uint(tree, hf_cmer_disp, tvb, offset, parameter_length, value); |
1387 | 0 | if (value > 2) |
1388 | 0 | expert_add_info(pinfo, pitem, &ei_cmer_disp); |
1389 | 0 | break; |
1390 | 0 | case 3: |
1391 | 0 | pitem = proto_tree_add_uint(tree, hf_cmer_ind, tvb, offset, parameter_length, value); |
1392 | 0 | if (value > 2) |
1393 | 0 | expert_add_info(pinfo, pitem, &ei_cmer_ind); |
1394 | 0 | break; |
1395 | 0 | case 4: |
1396 | 0 | pitem = proto_tree_add_uint(tree, hf_cmer_bfr, tvb, offset, parameter_length, value); |
1397 | 0 | if (value > 1) |
1398 | 0 | expert_add_info(pinfo, pitem, &ei_cmer_bfr); |
1399 | 0 | break; |
1400 | 0 | } |
1401 | | |
1402 | 0 | return true; |
1403 | 0 | } |
1404 | | |
1405 | | static bool |
1406 | | dissect_cmgl_data_part(tvbuff_t *tvb, packet_info *pinfo, |
1407 | | proto_tree *tree, int offset, int role, uint16_t type, |
1408 | | uint8_t *data_part_stream _U_, unsigned data_part_number _U_, |
1409 | | int data_part_length, at_packet_info_t *at_info _U_) |
1410 | 0 | { |
1411 | 0 | proto_item *pitem; |
1412 | 0 | int hex_length; |
1413 | 0 | int bytes_count; |
1414 | 0 | int i; |
1415 | 0 | uint8_t *final_arr; |
1416 | 0 | tvbuff_t *final_tvb = NULL; |
1417 | |
|
1418 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1419 | 0 | return false; |
1420 | 0 | } |
1421 | 0 | pitem = proto_tree_add_item(tree, hf_cmgl_msg_pdu, tvb, offset, data_part_length, ENC_ASCII); |
1422 | |
|
1423 | 0 | hex_length = data_part_length; |
1424 | 0 | if (hex_length % 2 == 1) { |
1425 | 0 | expert_add_info(pinfo, pitem, &ei_odd_len); |
1426 | 0 | return true; |
1427 | 0 | } |
1428 | 0 | if (hex_length < 1) { |
1429 | 0 | expert_add_info(pinfo, pitem, &ei_empty_hex); |
1430 | 0 | return true; |
1431 | 0 | } |
1432 | 0 | bytes_count = hex_length / 2; |
1433 | 0 | final_arr = wmem_alloc0_array(pinfo->pool, uint8_t, bytes_count + 1); |
1434 | | /* Try to parse the hex string into a byte array */ |
1435 | 0 | uint8_t *pos = data_part_stream; |
1436 | 0 | pos += 16; |
1437 | 0 | for (i = 8; i < bytes_count; i++) { |
1438 | 0 | if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) { |
1439 | | /* Either current or next char isn't a hex character */ |
1440 | 0 | expert_add_info(pinfo, pitem, &ei_invalid_hex); |
1441 | 0 | return true; |
1442 | 0 | } |
1443 | 0 | sscanf((char *)pos, "%2hhx", &(final_arr[i-8])); |
1444 | 0 | pos += 2; |
1445 | 0 | } |
1446 | 0 | final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count); |
1447 | 0 | add_new_data_source(pinfo, final_tvb, "GSM SMS payload"); |
1448 | | |
1449 | | /* Adjusting P2P direction as it is read by the SMS dissector */ |
1450 | 0 | int at_dir = pinfo->p2p_dir; |
1451 | 0 | pinfo->p2p_dir = P2P_DIR_SENT; |
1452 | | |
1453 | | /* Call GSM SMS dissector*/ |
1454 | 0 | call_dissector_only(gsm_sms_handle, final_tvb, pinfo, tree, NULL); |
1455 | | |
1456 | | /* Restoring P2P direction */ |
1457 | 0 | pinfo->p2p_dir = at_dir; |
1458 | 0 | return true; |
1459 | 0 | } |
1460 | | |
1461 | | static bool |
1462 | | dissect_cmgl_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1463 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1464 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info, void **data _U_) |
1465 | 0 | { |
1466 | 0 | uint32_t value = 0; |
1467 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1468 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1469 | 0 | return false; |
1470 | 0 | } |
1471 | | |
1472 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number > 0) |
1473 | 0 | return false; |
1474 | 0 | else if (role == ROLE_DCE && parameter_number > 3) |
1475 | 0 | return false; |
1476 | | |
1477 | 0 | if (role == ROLE_DTE && type == TYPE_ACTION) { |
1478 | 0 | proto_tree_add_item(tree, hf_cmgl_req_status, tvb, offset, parameter_length, ENC_ASCII); |
1479 | 0 | } else { |
1480 | 0 | switch (parameter_number) { |
1481 | 0 | case 0: |
1482 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1483 | 0 | proto_tree_add_uint(tree, hf_cmgl_msg_index, tvb, offset, parameter_length, value); |
1484 | 0 | break; |
1485 | 0 | case 1: |
1486 | 0 | proto_tree_add_item(tree, hf_cmgl_msg_status, tvb, offset, parameter_length, ENC_ASCII); |
1487 | 0 | break; |
1488 | 0 | case 2: |
1489 | 0 | proto_tree_add_item(tree, hf_cmgl_msg_originator_name, tvb, offset, parameter_length, ENC_ASCII); |
1490 | 0 | break; |
1491 | 0 | case 3: |
1492 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1493 | 0 | proto_tree_add_uint(tree, hf_cmgl_msg_length, tvb, offset, parameter_length, value); |
1494 | | // If we reached the length parameter we are |
1495 | | // expecting the next line to be our encoded data |
1496 | 0 | at_processed_cmd_t * at_cmd = get_current_role_last_command(at_info, role); |
1497 | 0 | if (!at_cmd) |
1498 | 0 | break; |
1499 | 0 | at_cmd->type = type; |
1500 | 0 | at_cmd->expected_data_parts = 1; |
1501 | 0 | at_cmd->consumed_data_parts = 0; |
1502 | 0 | at_cmd->dissect_data = dissect_cmgl_data_part; |
1503 | 0 | break; |
1504 | 0 | } |
1505 | 0 | } |
1506 | | |
1507 | 0 | return true; |
1508 | 0 | } |
1509 | | |
1510 | | static bool |
1511 | | dissect_cmgr_data_part(tvbuff_t *tvb, packet_info *pinfo, |
1512 | | proto_tree *tree, int offset, int role, uint16_t type, |
1513 | | uint8_t *data_part_stream _U_, unsigned data_part_number _U_, |
1514 | | int data_part_length, at_packet_info_t *at_info _U_) |
1515 | 0 | { |
1516 | 0 | proto_item *pitem; |
1517 | 0 | int hex_length; |
1518 | 0 | int bytes_count; |
1519 | 0 | int i; |
1520 | 0 | uint8_t *final_arr; |
1521 | 0 | tvbuff_t *final_tvb = NULL; |
1522 | |
|
1523 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1524 | 0 | return false; |
1525 | 0 | } |
1526 | 0 | pitem = proto_tree_add_item(tree, hf_cmgr_msg_pdu, tvb, offset, data_part_length, ENC_ASCII); |
1527 | |
|
1528 | 0 | hex_length = data_part_length; |
1529 | 0 | if (hex_length % 2 == 1) { |
1530 | 0 | expert_add_info(pinfo, pitem, &ei_odd_len); |
1531 | 0 | return true; |
1532 | 0 | } |
1533 | 0 | if (hex_length < 1) { |
1534 | 0 | expert_add_info(pinfo, pitem, &ei_empty_hex); |
1535 | 0 | return true; |
1536 | 0 | } |
1537 | 0 | bytes_count = hex_length / 2; |
1538 | 0 | final_arr = wmem_alloc0_array(pinfo->pool, uint8_t, bytes_count + 1); |
1539 | | /* Try to parse the hex string into a byte array */ |
1540 | 0 | uint8_t *pos = data_part_stream; |
1541 | 0 | pos += 16; |
1542 | 0 | for (i = 8; i < bytes_count; i++) { |
1543 | 0 | if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) { |
1544 | | /* Either current or next char isn't a hex character */ |
1545 | 0 | expert_add_info(pinfo, pitem, &ei_invalid_hex); |
1546 | 0 | return true; |
1547 | 0 | } |
1548 | 0 | sscanf((char *)pos, "%2hhx", &(final_arr[i-8])); |
1549 | 0 | pos += 2; |
1550 | 0 | } |
1551 | 0 | final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count); |
1552 | 0 | add_new_data_source(pinfo, final_tvb, "GSM SMS payload"); |
1553 | | |
1554 | | /* Adjusting P2P direction as it is read by the SMS dissector */ |
1555 | 0 | int at_dir = pinfo->p2p_dir; |
1556 | 0 | pinfo->p2p_dir = P2P_DIR_SENT; |
1557 | | |
1558 | | /* Call GSM SMS dissector*/ |
1559 | 0 | call_dissector_only(gsm_sms_handle, final_tvb, pinfo, tree, NULL); |
1560 | | |
1561 | | /* Restoring P2P direction */ |
1562 | 0 | pinfo->p2p_dir = at_dir; |
1563 | 0 | return true; |
1564 | 0 | } |
1565 | | |
1566 | | static bool |
1567 | | dissect_cmgr_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1568 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1569 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info, void **data _U_) |
1570 | 0 | { |
1571 | 0 | uint32_t value = 0; |
1572 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1573 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1574 | 0 | return false; |
1575 | 0 | } |
1576 | | |
1577 | 0 | if (role == ROLE_DTE && parameter_number > 1) |
1578 | 0 | return false; |
1579 | 0 | else if (role == ROLE_DCE && parameter_number > 3) |
1580 | 0 | return false; |
1581 | | |
1582 | 0 | if (role == ROLE_DTE) { |
1583 | 0 | switch (parameter_number) { |
1584 | 0 | case 0: |
1585 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1586 | 0 | proto_tree_add_uint(tree, hf_cmgr_msg_index, tvb, offset, parameter_length, value); |
1587 | 0 | break; |
1588 | 0 | case 1: |
1589 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1590 | 0 | proto_tree_add_uint(tree, hf_cmgr_mode, tvb, offset, parameter_length, value); |
1591 | 0 | break; |
1592 | 0 | } |
1593 | 0 | } else { |
1594 | 0 | switch (parameter_number) { |
1595 | 0 | case 0: |
1596 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1597 | 0 | proto_tree_add_uint(tree, hf_cmgr_stat, tvb, offset, parameter_length, value); |
1598 | 0 | break; |
1599 | 0 | case 1: |
1600 | 0 | proto_tree_add_item(tree, hf_cmgr_address, tvb, offset, parameter_length, ENC_ASCII); |
1601 | 0 | break; |
1602 | 0 | case 2: |
1603 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1604 | 0 | proto_tree_add_uint(tree, hf_cmgr_msg_length, tvb, offset, parameter_length, value); |
1605 | | // If we reached the length parameter we are |
1606 | | // expecting the next line to be our encoded data |
1607 | 0 | at_processed_cmd_t * at_cmd = get_current_role_last_command(at_info, role); |
1608 | 0 | if (!at_cmd) |
1609 | 0 | break; |
1610 | 0 | at_cmd->type = type; |
1611 | 0 | at_cmd->expected_data_parts = 1; |
1612 | 0 | at_cmd->consumed_data_parts = 0; |
1613 | 0 | at_cmd->dissect_data = dissect_cmgr_data_part; |
1614 | 0 | break; |
1615 | 0 | } |
1616 | 0 | } |
1617 | | |
1618 | 0 | return true; |
1619 | 0 | } |
1620 | | |
1621 | | static bool |
1622 | | dissect_cmux_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1623 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1624 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1625 | 0 | { |
1626 | 0 | uint32_t value = 0; |
1627 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1628 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1629 | 0 | return false; |
1630 | 0 | } |
1631 | | |
1632 | 0 | if (parameter_number > 8) return false; |
1633 | | |
1634 | | /* Parameters are the same for both ACTION and RESPONSE */ |
1635 | 0 | if (parameter_length != 0) { |
1636 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1637 | 0 | } |
1638 | 0 | switch (parameter_number) { |
1639 | 0 | case 0: |
1640 | 0 | proto_tree_add_uint(tree, hf_cmux_transparency, tvb, offset, parameter_length, value); |
1641 | 0 | break; |
1642 | 0 | case 1: |
1643 | | /* In the RESPONSE, the subset parameter might be missing */ |
1644 | 0 | if (type == TYPE_ACTION || parameter_length != 0) { |
1645 | 0 | proto_tree_add_uint(tree, hf_cmux_subset, tvb, offset, parameter_length, value); |
1646 | 0 | } |
1647 | 0 | break; |
1648 | 0 | case 2: |
1649 | 0 | proto_tree_add_item(tree, hf_cmux_port_speed, tvb, offset, parameter_length, ENC_NA); |
1650 | 0 | break; |
1651 | 0 | case 3: |
1652 | 0 | proto_tree_add_uint(tree, hf_cmux_n1, tvb, offset, parameter_length, value); |
1653 | 0 | break; |
1654 | 0 | case 4: |
1655 | 0 | proto_tree_add_uint(tree, hf_cmux_t1, tvb, offset, parameter_length, value); |
1656 | 0 | break; |
1657 | 0 | case 5: |
1658 | 0 | proto_tree_add_uint(tree, hf_cmux_n2, tvb, offset, parameter_length, value); |
1659 | 0 | break; |
1660 | 0 | case 6: |
1661 | 0 | proto_tree_add_uint(tree, hf_cmux_t2, tvb, offset, parameter_length, value); |
1662 | 0 | break; |
1663 | 0 | case 7: |
1664 | 0 | proto_tree_add_uint(tree, hf_cmux_t3, tvb, offset, parameter_length, value); |
1665 | 0 | break; |
1666 | 0 | case 8: |
1667 | 0 | proto_tree_add_uint(tree, hf_cmux_k, tvb, offset, parameter_length, value); |
1668 | 0 | break; |
1669 | 0 | } |
1670 | | |
1671 | 0 | return true; |
1672 | 0 | } |
1673 | | |
1674 | | static bool |
1675 | | dissect_cnum_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1676 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1677 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1678 | 0 | { |
1679 | 0 | proto_item *pitem; |
1680 | 0 | uint32_t value; |
1681 | |
|
1682 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return false; |
1683 | 0 | if (parameter_number > 5) return false; |
1684 | | |
1685 | 0 | switch (parameter_number) { |
1686 | 0 | case 0: |
1687 | 0 | proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_ASCII); |
1688 | 0 | break; |
1689 | 0 | case 1: |
1690 | 0 | proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_ASCII); |
1691 | 0 | break; |
1692 | 0 | case 2: |
1693 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1694 | 0 | pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value); |
1695 | 0 | if (value < 128 || value > 175) |
1696 | 0 | expert_add_info(pinfo, pitem, &ei_at_type); |
1697 | 0 | break; |
1698 | 0 | case 3: |
1699 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1700 | 0 | proto_tree_add_uint(tree, hf_cnum_speed, tvb, offset, parameter_length, value); |
1701 | 0 | break; |
1702 | 0 | case 4: |
1703 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1704 | 0 | pitem = proto_tree_add_uint(tree, hf_cnum_service, tvb, offset, parameter_length, value); |
1705 | 0 | if (value > 5) |
1706 | 0 | expert_add_info(pinfo, pitem, &ei_cnum_service); |
1707 | 0 | break; |
1708 | 0 | case 5: |
1709 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1710 | 0 | pitem = proto_tree_add_uint(tree, hf_cnum_itc, tvb, offset, parameter_length, value); |
1711 | 0 | if (value > 1) |
1712 | 0 | expert_add_info(pinfo, pitem, &ei_cnum_itc); |
1713 | 0 | break; |
1714 | 0 | } |
1715 | | |
1716 | 0 | return true; |
1717 | 0 | } |
1718 | | |
1719 | | static bool |
1720 | | dissect_cops_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1721 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1722 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1723 | 0 | { |
1724 | 0 | uint32_t value; |
1725 | |
|
1726 | 0 | if (!((role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ)) || |
1727 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1728 | 0 | return false; |
1729 | 0 | } |
1730 | | |
1731 | 0 | if (parameter_number > 3) return false; |
1732 | | |
1733 | 0 | switch (parameter_number) { |
1734 | 0 | case 0: |
1735 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1736 | 0 | proto_tree_add_uint(tree, hf_cops_mode, tvb, offset, parameter_length, value); |
1737 | 0 | break; |
1738 | 0 | case 1: |
1739 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1740 | 0 | proto_tree_add_uint(tree, hf_cops_format, tvb, offset, parameter_length, value); |
1741 | 0 | break; |
1742 | 0 | case 2: |
1743 | 0 | proto_tree_add_item(tree, hf_cops_operator, tvb, offset, parameter_length, ENC_ASCII); |
1744 | 0 | break; |
1745 | 0 | case 3: |
1746 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1747 | 0 | proto_tree_add_uint(tree, hf_cops_act, tvb, offset, parameter_length, value); |
1748 | 0 | break; |
1749 | 0 | } |
1750 | | |
1751 | 0 | return true; |
1752 | 0 | } |
1753 | | |
1754 | | static bool |
1755 | | dissect_cpin_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1756 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1757 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1758 | 0 | { |
1759 | 0 | proto_item *pitem; |
1760 | 0 | bool is_ready; |
1761 | 0 | char *pin_type; |
1762 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1763 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1764 | 0 | return false; |
1765 | 0 | } |
1766 | | |
1767 | 0 | if (type == TYPE_ACTION) { |
1768 | 0 | switch (parameter_number) { |
1769 | 0 | case 0: |
1770 | 0 | proto_tree_add_item(tree, hf_cpin_pin, tvb, offset, parameter_length, ENC_ASCII); |
1771 | 0 | break; |
1772 | 0 | case 1: |
1773 | 0 | proto_tree_add_item(tree, hf_cpin_newpin, tvb, offset, parameter_length, ENC_ASCII); |
1774 | 0 | break; |
1775 | 0 | default: |
1776 | 0 | return false; |
1777 | 0 | } |
1778 | 0 | return true; |
1779 | 0 | } |
1780 | | |
1781 | | /* type is TYPE_RESPONSE */ |
1782 | 0 | if (parameter_number == 0) { |
1783 | 0 | pitem = proto_tree_add_item(tree, hf_cpin_code, tvb, offset, parameter_length, ENC_ASCII); |
1784 | 0 | is_ready = g_ascii_strncasecmp("READY", (char*)parameter_stream, parameter_length) == 0; |
1785 | 0 | if (is_ready) { |
1786 | 0 | proto_item_append_text(pitem, " (MT is not pending for any password)"); |
1787 | 0 | } |
1788 | 0 | else { |
1789 | 0 | pin_type = wmem_strndup(pinfo->pool, (char*)parameter_stream, parameter_length); |
1790 | 0 | proto_item_append_text(pitem, " (MT is waiting %s to be given)", pin_type); |
1791 | 0 | } |
1792 | 0 | return true; |
1793 | 0 | } |
1794 | 0 | return false; |
1795 | 0 | } |
1796 | | |
1797 | | static bool |
1798 | | dissect_cpms_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1799 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1800 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1801 | 0 | { |
1802 | 0 | uint32_t value; |
1803 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1804 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1805 | 0 | return false; |
1806 | 0 | } |
1807 | | |
1808 | 0 | if (type == TYPE_ACTION) { |
1809 | 0 | switch (parameter_number) { |
1810 | 0 | case 0: |
1811 | 0 | proto_tree_add_item(tree, hf_cpms_mem1, tvb, offset, parameter_length, ENC_ASCII); |
1812 | 0 | break; |
1813 | 0 | case 1: |
1814 | 0 | proto_tree_add_item(tree, hf_cpms_mem2, tvb, offset, parameter_length, ENC_ASCII); |
1815 | 0 | break; |
1816 | 0 | case 2: |
1817 | 0 | proto_tree_add_item(tree, hf_cpms_mem3, tvb, offset, parameter_length, ENC_ASCII); |
1818 | 0 | break; |
1819 | 0 | default: |
1820 | 0 | return false; |
1821 | 0 | } |
1822 | 0 | return true; |
1823 | 0 | } |
1824 | 0 | else { |
1825 | | // TODO: Assuming response is for ACTION command, need to support |
1826 | | // responses for READ and QUERY |
1827 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1828 | 0 | switch (parameter_number) { |
1829 | 0 | case 0: |
1830 | 0 | proto_tree_add_uint(tree, hf_cpms_used1, tvb, offset, parameter_length, value); |
1831 | 0 | break; |
1832 | 0 | case 1: |
1833 | 0 | proto_tree_add_uint(tree, hf_cpms_total1, tvb, offset, parameter_length, value); |
1834 | 0 | break; |
1835 | 0 | case 2: |
1836 | 0 | proto_tree_add_uint(tree, hf_cpms_used2, tvb, offset, parameter_length, value); |
1837 | 0 | break; |
1838 | 0 | case 3: |
1839 | 0 | proto_tree_add_uint(tree, hf_cpms_total2, tvb, offset, parameter_length, value); |
1840 | 0 | break; |
1841 | 0 | case 4: |
1842 | 0 | proto_tree_add_uint(tree, hf_cpms_used3, tvb, offset, parameter_length, value); |
1843 | 0 | break; |
1844 | 0 | case 5: |
1845 | 0 | proto_tree_add_uint(tree, hf_cpms_total3, tvb, offset, parameter_length, value); |
1846 | 0 | break; |
1847 | 0 | default: |
1848 | 0 | return false; |
1849 | 0 | } |
1850 | 0 | return true; |
1851 | 0 | } |
1852 | 0 | } |
1853 | | |
1854 | | static bool |
1855 | | dissect_cscs_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1856 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1857 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1858 | 0 | { |
1859 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1860 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1861 | 0 | return false; |
1862 | 0 | } |
1863 | | |
1864 | 0 | if (parameter_number > 0) { |
1865 | 0 | return false; |
1866 | 0 | } |
1867 | | |
1868 | | /* For both ACTION and RESPONSE the first |
1869 | | * and only parameter is the character set */ |
1870 | 0 | proto_tree_add_item(tree, hf_cscs_chset, tvb, offset, parameter_length, ENC_ASCII); |
1871 | 0 | return true; |
1872 | 0 | } |
1873 | | |
1874 | | static bool |
1875 | | dissect_csim_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1876 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1877 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data) |
1878 | 0 | { |
1879 | 0 | proto_item *pitem; |
1880 | 0 | uint32_t value; |
1881 | 0 | int hex_length; |
1882 | 0 | int bytes_count; |
1883 | 0 | int i; |
1884 | 0 | uint8_t *final_arr; |
1885 | 0 | tvbuff_t *final_tvb=NULL; |
1886 | |
|
1887 | 0 | if (!((role == ROLE_DTE && type == TYPE_ACTION) || |
1888 | 0 | (role == ROLE_DCE && type == TYPE_RESPONSE))) { |
1889 | 0 | return false; |
1890 | 0 | } |
1891 | | |
1892 | 0 | if (parameter_number > 1) return true; |
1893 | | |
1894 | 0 | switch (parameter_number) { |
1895 | 0 | case 0: |
1896 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1897 | 0 | proto_tree_add_uint(tree, hf_csim_length, tvb, offset, parameter_length, value); |
1898 | 0 | break; |
1899 | 0 | case 1: |
1900 | 0 | if(role == ROLE_DTE) { |
1901 | 0 | pitem = proto_tree_add_item(tree, hf_csim_command, tvb, offset, |
1902 | 0 | parameter_length, ENC_ASCII); |
1903 | 0 | } |
1904 | 0 | else { |
1905 | 0 | pitem = proto_tree_add_item(tree, hf_csim_response, tvb, offset, |
1906 | 0 | parameter_length, ENC_ASCII); |
1907 | 0 | } |
1908 | 0 | hex_length = (parameter_length - 2); /* ignoring leading and trailing quotes */ |
1909 | 0 | if (hex_length % 2 == 1) { |
1910 | 0 | expert_add_info(pinfo, pitem, &ei_odd_len); |
1911 | 0 | return true; |
1912 | 0 | } |
1913 | 0 | if(hex_length < 1) { |
1914 | 0 | expert_add_info(pinfo, pitem, &ei_empty_hex); |
1915 | 0 | return true; |
1916 | 0 | } |
1917 | 0 | bytes_count = hex_length / 2; |
1918 | 0 | final_arr = wmem_alloc0_array(pinfo->pool,uint8_t,bytes_count); |
1919 | | /* Try to parse the hex string into a byte array */ |
1920 | 0 | uint8_t *pos = parameter_stream; |
1921 | 0 | pos++; /* skipping first quotes */ |
1922 | 0 | for (i = 0; i < bytes_count; i++) { |
1923 | 0 | if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) { |
1924 | | /* Either current or next char isn't a hex character */ |
1925 | 0 | expert_add_info(pinfo, pitem, &ei_invalid_hex); |
1926 | 0 | return true; |
1927 | 0 | } |
1928 | 0 | sscanf((char *)pos, "%2hhx", &(final_arr[i])); |
1929 | 0 | pos += 2; |
1930 | 0 | } |
1931 | 0 | final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count); |
1932 | 0 | add_new_data_source(pinfo, final_tvb, "GSM SIM payload"); |
1933 | | /* Call GSM SIM dissector*/ |
1934 | 0 | col_append_str(pinfo->cinfo, COL_INFO, " | "); |
1935 | 0 | call_dissector_with_data(gsm_sim_handle, final_tvb, pinfo, tree, data); |
1936 | 0 | break; |
1937 | 0 | } |
1938 | | |
1939 | 0 | return true; |
1940 | 0 | } |
1941 | | |
1942 | | static bool |
1943 | | dissect_csq_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
1944 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
1945 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1946 | 0 | { |
1947 | 0 | proto_item *pitem; |
1948 | 0 | uint32_t value; |
1949 | |
|
1950 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return false; |
1951 | | |
1952 | 0 | if (parameter_number > 1) return false; |
1953 | | |
1954 | 0 | switch (parameter_number) { |
1955 | 0 | case 0: |
1956 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1957 | 0 | pitem = proto_tree_add_uint(tree, hf_csq_rssi, tvb, offset, parameter_length, value); |
1958 | 0 | if (value > 31 && value != 99) |
1959 | 0 | expert_add_info(pinfo, pitem, &ei_csq_rssi); |
1960 | 0 | break; |
1961 | 0 | case 1: |
1962 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
1963 | 0 | pitem = proto_tree_add_uint(tree, hf_csq_ber, tvb, offset, parameter_length, value); |
1964 | 0 | if (value > 7 && value != 99) |
1965 | 0 | expert_add_info(pinfo, pitem, &ei_csq_ber); |
1966 | 0 | break; |
1967 | 0 | } |
1968 | | |
1969 | 0 | return true; |
1970 | 0 | } |
1971 | | |
1972 | | static bool |
1973 | | dissect_gmi_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1974 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1975 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1976 | 0 | { |
1977 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1978 | 0 | return false; |
1979 | 0 | } |
1980 | | |
1981 | 0 | if (parameter_number > 1) return false; |
1982 | | |
1983 | 0 | proto_tree_add_item(tree, hf_gmi_manufacturer_id, tvb, offset, parameter_length, ENC_ASCII); |
1984 | |
|
1985 | 0 | return true; |
1986 | 0 | } |
1987 | | |
1988 | | static bool |
1989 | | dissect_gmm_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
1990 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
1991 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
1992 | 0 | { |
1993 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
1994 | 0 | return false; |
1995 | 0 | } |
1996 | | |
1997 | 0 | if (parameter_number > 1) return false; |
1998 | | |
1999 | 0 | proto_tree_add_item(tree, hf_gmm_model_id, tvb, offset, parameter_length, ENC_ASCII); |
2000 | |
|
2001 | 0 | return true; |
2002 | 0 | } |
2003 | | |
2004 | | static bool |
2005 | | dissect_gmr_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
2006 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
2007 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
2008 | 0 | { |
2009 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
2010 | 0 | return false; |
2011 | 0 | } |
2012 | | |
2013 | 0 | if (parameter_number > 1) return false; |
2014 | | |
2015 | 0 | proto_tree_add_item(tree, hf_gmr_revision_id, tvb, offset, parameter_length, ENC_ASCII); |
2016 | |
|
2017 | 0 | return true; |
2018 | 0 | } |
2019 | | |
2020 | | static bool |
2021 | | dissect_vts_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
2022 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
2023 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
2024 | 0 | { |
2025 | 0 | proto_item *pitem; |
2026 | 0 | uint32_t value; |
2027 | |
|
2028 | 0 | if (!(role == ROLE_DTE && type == TYPE_ACTION)) return false; |
2029 | 0 | if (parameter_number > 1) return false; |
2030 | | |
2031 | 0 | switch (parameter_number) { |
2032 | 0 | case 0: |
2033 | 0 | pitem = proto_tree_add_item(tree, hf_vts_dtmf, tvb, offset, parameter_length, ENC_ASCII); |
2034 | 0 | if (parameter_length != 1) |
2035 | 0 | expert_add_info(pinfo, pitem, &ei_vts_dtmf); |
2036 | 0 | break; |
2037 | 0 | case 1: |
2038 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
2039 | 0 | proto_tree_add_uint(tree, hf_vts_duration, tvb, offset, parameter_length, value); |
2040 | 0 | break; |
2041 | 0 | } |
2042 | | |
2043 | 0 | return true; |
2044 | 0 | } |
2045 | | |
2046 | | static bool |
2047 | | dissect_zpas_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
2048 | | int offset, int role, uint16_t type, uint8_t *parameter_stream _U_, |
2049 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
2050 | 0 | { |
2051 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
2052 | 0 | return false; |
2053 | 0 | } |
2054 | | |
2055 | 0 | if (parameter_number > 1) return false; |
2056 | | |
2057 | 0 | switch(parameter_number) |
2058 | 0 | { |
2059 | 0 | case 0: |
2060 | 0 | proto_tree_add_item(tree, hf_zpas_network, tvb, offset, parameter_length, ENC_ASCII); |
2061 | 0 | break; |
2062 | 0 | case 1: |
2063 | 0 | proto_tree_add_item(tree, hf_zpas_srv_domain, tvb, offset, parameter_length, ENC_ASCII); |
2064 | 0 | break; |
2065 | 0 | } |
2066 | | |
2067 | 0 | return true; |
2068 | 0 | } |
2069 | | |
2070 | | static bool |
2071 | | dissect_zusim_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, |
2072 | | int offset, int role, uint16_t type, uint8_t *parameter_stream, |
2073 | | unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_) |
2074 | 0 | { |
2075 | 0 | uint32_t value; |
2076 | |
|
2077 | 0 | if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) { |
2078 | 0 | return false; |
2079 | 0 | } |
2080 | | |
2081 | 0 | if (parameter_number > 0) return false; |
2082 | | |
2083 | 0 | value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length); |
2084 | 0 | proto_tree_add_uint(tree, hf_zusim_usim_card, tvb, offset, parameter_length, value); |
2085 | |
|
2086 | 0 | return true; |
2087 | 0 | } |
2088 | | |
2089 | | static bool |
2090 | | dissect_no_parameter(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, |
2091 | | int offset _U_, int role _U_, uint16_t type _U_, uint8_t *parameter_stream _U_, |
2092 | | unsigned parameter_number _U_, int parameter_length _U_, at_packet_info_t *at_info _U_, void **data _U_) |
2093 | 0 | { |
2094 | 0 | return false; |
2095 | 0 | } |
2096 | | |
2097 | | /* TODO: Some commands need to save request command type (request with TYPE_READ vs TYPE_TEST, etc.) |
2098 | | to properly dissect response parameters. |
2099 | | Some commands can use TYPE_TEST response to properly dissect parameters, |
2100 | | for example: AT+CIND=?, AT+CIND? */ |
2101 | | static const at_cmd_t at_cmds[] = { |
2102 | | { "+CCWA", "Call Waiting Notification", check_ccwa, dissect_ccwa_parameter }, |
2103 | | { "+CFUN", "Set Phone Functionality", check_cfun, dissect_cfun_parameter }, |
2104 | | { "+CGDCONT", "PDP context define", check_cgdcont, dissect_cgdcont_parameter }, |
2105 | | { "+CGMI", "Request manufacturer identification", check_cgmi, dissect_cgmi_parameter }, |
2106 | | { "+CGMM", "Request model identification", check_cgmm, dissect_cgmm_parameter }, |
2107 | | { "+CGMR", "Request revision identification", check_cgmr, dissect_cgmr_parameter }, |
2108 | | { "+CGSN", "Request Product Serial Number Identification (ESN/IMEI)", check_cgsn, dissect_no_parameter }, |
2109 | | { "+CHLD", "Call Hold and Multiparty Handling", check_chld, dissect_chld_parameter }, |
2110 | | { "+CHUP", "Call Hang-up", check_chup, dissect_no_parameter }, |
2111 | | { "+CIEV", "Indicator Events Reporting", check_ciev, dissect_ciev_parameter }, |
2112 | | { "+CIMI", "Request International Mobile Subscriber Identity (IMSI)", check_cimi, dissect_cimi_parameter }, |
2113 | | { "^CIMI", "Request International Mobile Subscriber Identity (IMSI)", check_cimi, dissect_cimi_parameter }, |
2114 | | { "+CIND", "Phone Indicators", check_cind, dissect_cind_parameter }, |
2115 | | { "+CLAC", "List All Available AT Commands", check_clac, dissect_no_parameter }, |
2116 | | { "+CLCC", "Current Calls", check_clcc, dissect_clcc_parameter }, |
2117 | | { "+CLIP", "Calling Line Identification Notification", check_clip, dissect_clip_parameter }, |
2118 | | { "+CME ERROR", "Mobile Termination Error Result Code", check_cme, dissect_cme_error_parameter }, |
2119 | | { "+CMEE", "Mobile Equipment Error", check_cmee, dissect_cmee_parameter }, |
2120 | | { "+CMER", "Event Reporting Activation/Deactivation", check_cmer, dissect_cmer_parameter }, |
2121 | | { "+CMGL", "List SMS messages", check_cmgl, dissect_cmgl_parameter }, |
2122 | | { "+CMGR", "Read SMS message", check_cmgr, dissect_cmgr_parameter }, |
2123 | | { "+CMUX", "Multiplexing mode", check_cmux, dissect_cmux_parameter }, |
2124 | | { "+CNUM", "Subscriber Number Information", check_cnum, dissect_cnum_parameter }, |
2125 | | { "+COPS", "Reading Network Operator", check_cops, dissect_cops_parameter }, |
2126 | | { "+CPIN", "Enter SIM PIN", check_cpin, dissect_cpin_parameter }, |
2127 | | { "+CPMS", "Preferred Message Storage", check_cpms, dissect_cpms_parameter }, |
2128 | | { "+CSCS", "Select TE Character Set", check_cscs, dissect_cscs_parameter }, |
2129 | | { "+CSIM", "Generic SIM access", check_csim, dissect_csim_parameter }, |
2130 | | { "+CSQ", "Signal Quality", check_csq, dissect_csq_parameter }, |
2131 | | { "+CSUPI", "Request 5G subscription permanent identifier", check_csupi, dissect_no_parameter }, |
2132 | | { "+GMI", "Request manufacturer identification", check_gmi, dissect_gmi_parameter }, |
2133 | | { "+GMM", "Request model identification", check_gmm, dissect_gmm_parameter }, |
2134 | | { "+GMR", "Request revision identification", check_gmr, dissect_gmr_parameter }, |
2135 | | { "+GSN", "Request Product Serial Number Identification (ESN/IMEI)", check_gsn, dissect_no_parameter }, |
2136 | | { "+VTS", "DTMF and tone generation", check_vts, dissect_vts_parameter }, |
2137 | | { "+ZPAS", "Check Card Status", check_zpas, dissect_zpas_parameter }, |
2138 | | { "+ZUSIM", "Check USIM Card Type", check_zusim, dissect_zusim_parameter }, |
2139 | | { "ERROR", "ERROR", check_only_dce_role, dissect_no_parameter }, |
2140 | | { "RING", "Incoming Call Indication", check_only_dce_role, dissect_no_parameter }, |
2141 | | { "OK", "OK", check_only_dce_role, dissect_no_parameter }, |
2142 | | { "D", "Dial", check_only_dte_role, NULL }, |
2143 | | { "A", "Call Answer", check_only_dte_role, dissect_no_parameter }, |
2144 | | { "E0", "Disable Echo", check_only_dte_role, dissect_no_parameter }, |
2145 | | { "E1", "Enable Echo", check_only_dte_role, dissect_no_parameter }, |
2146 | | { "I", "Product Identification Information", check_only_dte_role, dissect_no_parameter }, |
2147 | | { NULL, NULL, NULL, NULL } |
2148 | | }; |
2149 | | |
2150 | | static int |
2151 | | dissect_at_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
2152 | | int offset, uint32_t role, int command_number, at_packet_info_t *at_info) |
2153 | 0 | { |
2154 | 0 | proto_item *pitem; |
2155 | 0 | proto_tree *command_item = NULL; |
2156 | 0 | proto_item *command_tree = NULL; |
2157 | 0 | proto_tree *parameters_item = NULL; |
2158 | 0 | proto_item *parameters_tree = NULL; |
2159 | 0 | char *at_stream; |
2160 | 0 | char *at_command = NULL; |
2161 | 0 | char *name; |
2162 | 0 | int i_char = 0; |
2163 | 0 | unsigned i_char_fix = 0; |
2164 | 0 | int length; |
2165 | 0 | int leftover_length; |
2166 | 0 | const at_cmd_t *i_at_cmd; |
2167 | 0 | int parameter_length; |
2168 | 0 | unsigned parameter_number = 0; |
2169 | 0 | int first_parameter_offset = offset; |
2170 | 0 | int last_parameter_offset = offset; |
2171 | 0 | uint16_t type = TYPE_UNKNOWN; |
2172 | 0 | uint32_t brackets; |
2173 | 0 | bool quotation; |
2174 | 0 | bool next; |
2175 | 0 | void *data; |
2176 | 0 | at_processed_cmd_t *last_command; |
2177 | |
|
2178 | 0 | length = tvb_reported_length_remaining(tvb, offset); |
2179 | 0 | if (length <= 0) |
2180 | 0 | return tvb_reported_length(tvb); |
2181 | | |
2182 | 0 | if (!command_number) { |
2183 | 0 | proto_tree_add_item(tree, hf_data, tvb, offset, length, ENC_ASCII); |
2184 | 0 | } |
2185 | |
|
2186 | 0 | at_stream = (char *)wmem_alloc(pinfo->pool, length + 1); |
2187 | 0 | tvb_memcpy(tvb, at_stream, offset, length); |
2188 | 0 | at_stream[length] = '\0'; |
2189 | |
|
2190 | 0 | while (at_stream[i_char]) { |
2191 | 0 | at_stream[i_char] = g_ascii_toupper(at_stream[i_char]); |
2192 | 0 | i_char += 1; |
2193 | 0 | } |
2194 | |
|
2195 | 0 | if (role == ROLE_DTE) { |
2196 | 0 | if (command_number) { |
2197 | 0 | at_command = at_stream; |
2198 | 0 | i_char = 0; |
2199 | 0 | } else { |
2200 | 0 | at_command = g_strstr_len(at_stream, length, "AT"); |
2201 | 0 | if (at_command) { |
2202 | 0 | command_item = proto_tree_add_none_format(tree, hf_command, tvb, |
2203 | 0 | offset, 0, "Command %u", command_number); |
2204 | 0 | command_tree = proto_item_add_subtree(command_item, ett_at_command); |
2205 | |
|
2206 | 0 | i_char = (unsigned) (at_command - at_stream); |
2207 | 0 | if (i_char) { |
2208 | 0 | proto_tree_add_item(command_tree, hf_at_ignored, tvb, offset, |
2209 | 0 | i_char, ENC_NA); |
2210 | 0 | offset += i_char; |
2211 | 0 | } |
2212 | |
|
2213 | 0 | proto_tree_add_item(command_tree, hf_at_command_line_prefix, |
2214 | 0 | tvb, offset, 2, ENC_ASCII); |
2215 | 0 | offset += 2; |
2216 | 0 | i_char += 2; |
2217 | 0 | at_command = at_stream; |
2218 | 0 | at_command += i_char; |
2219 | 0 | length -= i_char; |
2220 | 0 | i_char_fix += i_char; |
2221 | 0 | i_char = 0; |
2222 | 0 | } |
2223 | 0 | } |
2224 | 0 | } else { |
2225 | 0 | command_item = proto_tree_add_none_format(tree, hf_command, tvb, |
2226 | 0 | offset, 0, "Command %u", command_number); |
2227 | 0 | command_tree = proto_item_add_subtree(command_item, ett_at_command); |
2228 | |
|
2229 | 0 | at_command = at_stream; |
2230 | 0 | i_char = 0; |
2231 | 0 | while (i_char <= length && |
2232 | 0 | (at_command[i_char] == '\r' || at_command[i_char] == '\n' || |
2233 | 0 | at_command[i_char] == ' ' || at_command[i_char] == '\t')) { |
2234 | | /* ignore white characters */ |
2235 | 0 | i_char += 1; |
2236 | 0 | } |
2237 | |
|
2238 | 0 | offset += i_char; |
2239 | 0 | at_command += i_char; |
2240 | 0 | length -= i_char; |
2241 | 0 | i_char_fix += i_char; |
2242 | 0 | i_char = 0; |
2243 | 0 | } |
2244 | |
|
2245 | 0 | if (at_command) { |
2246 | |
|
2247 | 0 | while (i_char < length && |
2248 | 0 | (at_command[i_char] != '\r' && at_command[i_char] != '=' && |
2249 | 0 | at_command[i_char] != ';' && at_command[i_char] != '?' && |
2250 | 0 | at_command[i_char] != ':')) { |
2251 | 0 | i_char += 1; |
2252 | 0 | } |
2253 | |
|
2254 | 0 | i_at_cmd = at_cmds; |
2255 | 0 | if (at_command[0] == '\r') { |
2256 | 0 | pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset - 2, |
2257 | 0 | 2, ENC_ASCII); |
2258 | 0 | i_at_cmd = NULL; |
2259 | 0 | } else { |
2260 | 0 | pitem = NULL; |
2261 | 0 | while (i_at_cmd->name) { |
2262 | 0 | if (g_str_has_prefix(&at_command[0], i_at_cmd->name)) { |
2263 | 0 | pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset, |
2264 | 0 | (int) strlen(i_at_cmd->name), ENC_ASCII); |
2265 | 0 | proto_item_append_text(pitem, " (%s)", i_at_cmd->long_name); |
2266 | 0 | break; |
2267 | 0 | } |
2268 | 0 | i_at_cmd += 1; |
2269 | 0 | } |
2270 | |
|
2271 | 0 | if (!pitem) { |
2272 | 0 | pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset, |
2273 | 0 | i_char, ENC_ASCII); |
2274 | 0 | } |
2275 | 0 | } |
2276 | |
|
2277 | 0 | name = format_text(pinfo->pool, at_command, i_char + 1); |
2278 | |
|
2279 | 0 | if (i_at_cmd && i_at_cmd->name == NULL) { |
2280 | 0 | proto_item_append_text(command_item, ": %s (Unknown)", name); |
2281 | 0 | proto_item_append_text(pitem, " (Unknown)"); |
2282 | 0 | expert_add_info(pinfo, pitem, &ei_unknown_command); |
2283 | 0 | } else if (i_at_cmd == NULL) { |
2284 | 0 | proto_item_append_text(command_item, ": AT"); |
2285 | 0 | } else { |
2286 | 0 | proto_item_append_text(command_item, ": %s", i_at_cmd->name); |
2287 | 0 | } |
2288 | |
|
2289 | 0 | offset += i_char; |
2290 | |
|
2291 | 0 | leftover_length = length - i_char; |
2292 | 0 | if (i_at_cmd && g_strcmp0(i_at_cmd->name, "D")) { |
2293 | 0 | if (leftover_length >= 2 && at_command[i_char] == '=' && at_command[i_char + 1] == '?') { |
2294 | 0 | type = at_command[i_char] << 8 | at_command[i_char + 1]; |
2295 | 0 | proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type); |
2296 | 0 | offset += 2; |
2297 | 0 | i_char += 2; |
2298 | 0 | } else if (role == ROLE_DCE && leftover_length >= 2 && at_command[i_char] == '\r' && at_command[i_char + 1] == '\n') { |
2299 | 0 | type = at_command[i_char] << 8 | at_command[i_char + 1]; |
2300 | 0 | proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type); |
2301 | 0 | offset += 2; |
2302 | 0 | i_char += 2; |
2303 | 0 | } else if (leftover_length >= 1 && (at_command[i_char] == '=' || |
2304 | 0 | at_command[i_char] == '\r' || |
2305 | 0 | at_command[i_char] == ':' || |
2306 | 0 | at_command[i_char] == '?')) { |
2307 | 0 | type = at_command[i_char]; |
2308 | 0 | proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 1, type); |
2309 | 0 | offset += 1; |
2310 | 0 | i_char += 1; |
2311 | 0 | } |
2312 | 0 | else if (leftover_length == 0) { |
2313 | | /* No suffix, assume line break (which translates to 'ACTION_SIMPLY') */ |
2314 | 0 | type = TYPE_ACTION_SIMPLY; |
2315 | 0 | pitem = proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 0, type); |
2316 | 0 | proto_item_set_generated(pitem); |
2317 | 0 | } |
2318 | 0 | } |
2319 | | |
2320 | | /* Setting new command's info in the Last Command field */ |
2321 | 0 | last_command = get_current_role_last_command(at_info, role); |
2322 | 0 | if (last_command) { |
2323 | 0 | g_strlcpy(last_command->name, name, STORE_COMMAND_MAX_LEN); |
2324 | 0 | last_command->type = type; |
2325 | 0 | last_command->expected_data_parts = 0; |
2326 | 0 | last_command->consumed_data_parts = 0; |
2327 | 0 | } |
2328 | |
|
2329 | 0 | if (i_at_cmd && i_at_cmd->check_command && !i_at_cmd->check_command(role, type)) { |
2330 | 0 | expert_add_info(pinfo, command_item, &ei_invalid_usage); |
2331 | 0 | } |
2332 | |
|
2333 | 0 | parameters_item = proto_tree_add_none_format(command_tree, hf_parameters, tvb, |
2334 | 0 | offset, 0, "Parameters"); |
2335 | 0 | parameters_tree = proto_item_add_subtree(parameters_item, ett_at_parameters); |
2336 | 0 | first_parameter_offset = offset; |
2337 | |
|
2338 | 0 | data = NULL; |
2339 | |
|
2340 | 0 | while (i_char < length) { |
2341 | |
|
2342 | 0 | while (at_command[i_char] == ' ' || at_command[i_char] == '\t') { |
2343 | 0 | offset += 1; |
2344 | 0 | i_char += 1; |
2345 | 0 | } |
2346 | |
|
2347 | 0 | parameter_length = 0; |
2348 | 0 | brackets = 0; |
2349 | 0 | quotation = false; |
2350 | 0 | next = false; |
2351 | |
|
2352 | 0 | if (at_command[i_char + parameter_length] != '\r') { |
2353 | 0 | while (i_char + parameter_length < length && |
2354 | 0 | at_command[i_char + parameter_length] != '\r') { |
2355 | |
|
2356 | 0 | if (at_command[i_char + parameter_length] == ';') { |
2357 | 0 | next = true; |
2358 | 0 | break; |
2359 | 0 | } |
2360 | | |
2361 | 0 | if (at_command[i_char + parameter_length] == '"') { |
2362 | 0 | quotation = quotation ? false : true; |
2363 | 0 | } |
2364 | |
|
2365 | 0 | if (quotation == true) { |
2366 | 0 | parameter_length += 1; |
2367 | 0 | continue; |
2368 | 0 | } |
2369 | | |
2370 | 0 | if (at_command[i_char + parameter_length] == '(') { |
2371 | 0 | brackets += 1; |
2372 | 0 | } |
2373 | 0 | if (at_command[i_char + parameter_length] == ')') { |
2374 | 0 | brackets -= 1; |
2375 | 0 | } |
2376 | |
|
2377 | 0 | if (brackets == 0 && at_command[i_char + parameter_length] == ',') { |
2378 | 0 | break; |
2379 | 0 | } |
2380 | | |
2381 | 0 | parameter_length += 1; |
2382 | 0 | } |
2383 | |
|
2384 | 0 | if (type == TYPE_ACTION || type == TYPE_RESPONSE) { |
2385 | 0 | if (i_at_cmd && (i_at_cmd->dissect_parameter != NULL && |
2386 | 0 | !i_at_cmd->dissect_parameter(tvb, pinfo, parameters_tree, offset, role, |
2387 | 0 | type, (uint8_t*)&at_command[i_char], parameter_number, parameter_length, at_info, &data) )) { |
2388 | 0 | pitem = proto_tree_add_item(parameters_tree, |
2389 | 0 | hf_unknown_parameter, tvb, offset, |
2390 | 0 | parameter_length, ENC_ASCII); |
2391 | 0 | expert_add_info(pinfo, pitem, &ei_unknown_parameter); |
2392 | 0 | } else if (i_at_cmd && i_at_cmd->dissect_parameter == NULL) { |
2393 | 0 | proto_tree_add_item(parameters_tree, hf_parameter, tvb, offset, |
2394 | 0 | parameter_length, ENC_ASCII); |
2395 | 0 | } |
2396 | 0 | } |
2397 | 0 | } |
2398 | |
|
2399 | 0 | if (type != TYPE_ACTION_SIMPLY && type != TYPE_RESPONSE_ACK && type != TYPE_TEST && type != TYPE_READ) |
2400 | 0 | parameter_number += 1; |
2401 | 0 | i_char += parameter_length; |
2402 | 0 | offset += parameter_length; |
2403 | 0 | last_parameter_offset = offset; |
2404 | |
|
2405 | 0 | if (role == ROLE_DCE && |
2406 | 0 | i_char + 1 <= length && |
2407 | 0 | at_command[i_char] == '\r' && |
2408 | 0 | at_command[i_char + 1] == '\n') { |
2409 | 0 | offset += 2; |
2410 | 0 | i_char += 2; |
2411 | 0 | break; |
2412 | 0 | } else if (at_command[i_char] == ',' || |
2413 | 0 | at_command[i_char] == '\r' || |
2414 | 0 | at_command[i_char] == ';') { |
2415 | 0 | i_char += 1; |
2416 | 0 | offset += 1; |
2417 | 0 | } |
2418 | | |
2419 | 0 | if (next) break; |
2420 | 0 | } |
2421 | |
|
2422 | 0 | i_char += i_char_fix; |
2423 | 0 | proto_item_set_len(command_item, i_char); |
2424 | 0 | } else { |
2425 | 0 | length = tvb_reported_length_remaining(tvb, offset); |
2426 | 0 | if (length < 0) |
2427 | 0 | length = 0; |
2428 | 0 | offset += length; |
2429 | 0 | } |
2430 | |
|
2431 | 0 | if (parameter_number > 0 && last_parameter_offset - first_parameter_offset > 0) |
2432 | 0 | proto_item_set_len(parameters_item, last_parameter_offset - first_parameter_offset); |
2433 | 0 | else |
2434 | 0 | proto_item_append_text(parameters_item, ": No"); |
2435 | |
|
2436 | 0 | return offset; |
2437 | 0 | } |
2438 | | |
2439 | | static int |
2440 | | dissect_at_command_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
2441 | | int offset, uint32_t role, int command_number, at_packet_info_t *at_info) |
2442 | 0 | { |
2443 | 0 | at_processed_cmd_t *cmd; |
2444 | 0 | proto_item *data_part_item; |
2445 | 0 | proto_item *data_part_tree; |
2446 | 0 | proto_item *pitem; |
2447 | 0 | uint8_t *data_stream; |
2448 | 0 | int data_part_index; |
2449 | 0 | int length; |
2450 | 0 | int data_part_length = 0; |
2451 | |
|
2452 | 0 | cmd = get_current_role_last_command(at_info, role); |
2453 | 0 | if (!cmd) |
2454 | 0 | return offset; |
2455 | 0 | data_part_index = cmd->consumed_data_parts; |
2456 | |
|
2457 | 0 | length = tvb_reported_length_remaining(tvb, offset); |
2458 | 0 | if (length <= 0) |
2459 | 0 | return tvb_reported_length(tvb); |
2460 | | |
2461 | 0 | data_stream = (uint8_t *) wmem_alloc(pinfo->pool, length + 1); |
2462 | 0 | tvb_memcpy(tvb, data_stream, offset, length); |
2463 | 0 | data_stream[length] = '\0'; |
2464 | |
|
2465 | 0 | while (data_part_length < length && data_stream[data_part_length] != '\r') { |
2466 | 0 | data_part_length += 1; |
2467 | 0 | } |
2468 | |
|
2469 | 0 | data_part_item = proto_tree_add_none_format(tree, hf_data_part, tvb, |
2470 | 0 | offset, data_part_length, "Command %u's Data Part %u", command_number, data_part_index); |
2471 | 0 | data_part_tree = proto_item_add_subtree(data_part_item, ett_at_data_part); |
2472 | |
|
2473 | 0 | if (cmd && (cmd->dissect_data != NULL && |
2474 | 0 | !cmd->dissect_data(tvb, pinfo, data_part_tree, offset, role, cmd->type, |
2475 | 0 | data_stream, data_part_index, data_part_length, |
2476 | 0 | at_info) )) { |
2477 | 0 | pitem = proto_tree_add_item(data_part_tree, hf_unknown_parameter, tvb, offset, |
2478 | 0 | data_part_length, ENC_ASCII); |
2479 | 0 | expert_add_info(pinfo, pitem, &ei_unknown_parameter); |
2480 | 0 | } |
2481 | 0 | offset += data_part_length; |
2482 | 0 | return offset; |
2483 | 0 | } |
2484 | | |
2485 | | /* The dissector itself */ |
2486 | | static int dissect_at(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
2487 | 0 | { |
2488 | 0 | proto_item *item; |
2489 | 0 | proto_tree *at_tree; |
2490 | 0 | char *string; |
2491 | 0 | uint32_t role = ROLE_UNKNOWN; |
2492 | 0 | int offset; |
2493 | 0 | int len; |
2494 | 0 | uint32_t cmd_indx; |
2495 | 0 | conversation_t *conversation; |
2496 | 0 | at_conv_info_t *at_conv; |
2497 | 0 | at_packet_info_t *at_info; |
2498 | 0 | at_processed_cmd_t *last_command; |
2499 | |
|
2500 | 0 | string = tvb_format_text_wsp(pinfo->pool, tvb, 0, tvb_captured_length(tvb)); |
2501 | 0 | col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "AT"); |
2502 | 0 | switch (pinfo->p2p_dir) { |
2503 | 0 | case P2P_DIR_SENT: |
2504 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Sent "); |
2505 | 0 | break; |
2506 | 0 | case P2P_DIR_RECV: |
2507 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Rcvd "); |
2508 | 0 | break; |
2509 | 0 | default: |
2510 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "UnknownDirection "); |
2511 | 0 | break; |
2512 | 0 | } |
2513 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, "AT Command: %s", string); |
2514 | | |
2515 | | /* Check if user forces roles using preferences */ |
2516 | 0 | if ((at_role == ROLE_DCE && pinfo->p2p_dir == P2P_DIR_SENT) || |
2517 | 0 | (at_role == ROLE_DTE && pinfo->p2p_dir == P2P_DIR_RECV)) { |
2518 | 0 | role = ROLE_DCE; |
2519 | 0 | } else if (at_role != ROLE_UNKNOWN) { |
2520 | 0 | role = ROLE_DTE; |
2521 | 0 | } |
2522 | | |
2523 | | /* If no roles are forced, assume SENT from PC and RECV from device */ |
2524 | 0 | if (role == ROLE_UNKNOWN) { |
2525 | 0 | if (pinfo->p2p_dir == P2P_DIR_SENT) { |
2526 | 0 | role = ROLE_DTE; |
2527 | 0 | } else { |
2528 | 0 | role = ROLE_DCE; |
2529 | 0 | } |
2530 | 0 | } |
2531 | | |
2532 | | /* Start with a top-level item to add everything else to */ |
2533 | 0 | item = proto_tree_add_item(tree, proto_at, tvb, 0, -1, ENC_NA); |
2534 | 0 | proto_item_append_text(item, ": %s", string); |
2535 | 0 | at_tree = proto_item_add_subtree(item, ett_at); |
2536 | | |
2537 | | /* Show role in tree */ |
2538 | 0 | item = proto_tree_add_uint(at_tree, hf_role, tvb, 0, 0, role); |
2539 | 0 | proto_item_set_generated(item); |
2540 | | |
2541 | | |
2542 | | /* Dissect command(s) */ |
2543 | 0 | len = tvb_captured_length(tvb); |
2544 | 0 | offset = 0; |
2545 | 0 | cmd_indx = 0; |
2546 | |
|
2547 | 0 | conversation = find_conversation(pinfo->num, |
2548 | 0 | &pinfo->src, &pinfo->dst, |
2549 | 0 | conversation_pt_to_conversation_type(pinfo->ptype), |
2550 | 0 | pinfo->srcport, pinfo->destport, 0); |
2551 | 0 | at_conv = get_at_conv_info(conversation); |
2552 | 0 | at_info = get_at_packet_info(pinfo, at_conv); |
2553 | |
|
2554 | 0 | while(offset < len) { |
2555 | 0 | last_command = get_current_role_last_command(at_info, role); |
2556 | 0 | if (last_command && last_command->expected_data_parts > last_command->consumed_data_parts) { |
2557 | | // Continuing a previous command |
2558 | 0 | offset = dissect_at_command_continuation(tvb, pinfo, at_tree, offset, role, last_command->cmd_indx, at_info); |
2559 | 0 | last_command->consumed_data_parts++; |
2560 | 0 | } |
2561 | 0 | else { |
2562 | | // New Command |
2563 | 0 | offset = dissect_at_command(tvb, pinfo, at_tree, offset, role, cmd_indx, at_info); |
2564 | | /* Only if the command is expecting data parts save its index */ |
2565 | 0 | last_command = get_current_role_last_command(at_info, role); |
2566 | 0 | if (last_command && last_command->expected_data_parts > last_command->consumed_data_parts) { |
2567 | 0 | last_command->cmd_indx = cmd_indx; |
2568 | 0 | } |
2569 | 0 | cmd_indx++; |
2570 | 0 | } |
2571 | 0 | } |
2572 | 0 | set_at_packet_info(pinfo, at_conv, at_info); |
2573 | 0 | return tvb_captured_length(tvb); |
2574 | 0 | } |
2575 | | |
2576 | | static int allowed_chars_len(tvbuff_t *tvb, int captured_len) |
2577 | 0 | { |
2578 | 0 | int offset; |
2579 | 0 | uint8_t val; |
2580 | | |
2581 | | /* Get the amount of characters within the TVB which are ASCII, |
2582 | | * cartridge return or new line */ |
2583 | 0 | for (offset = 0; offset < captured_len; offset++) { |
2584 | 0 | val = tvb_get_uint8(tvb, offset); |
2585 | 0 | if (!(g_ascii_isprint(val) || (val == 0x0a) || (val == 0x0d))) |
2586 | 0 | return offset; |
2587 | 0 | } |
2588 | 0 | return captured_len; |
2589 | 0 | } |
2590 | | static bool is_padded(tvbuff_t *tvb, int captured_len, int first_pad_offset) |
2591 | 0 | { |
2592 | 0 | int offset; |
2593 | 0 | uint8_t val; |
2594 | | |
2595 | | /* Check if the rest of the packet is 0x00 padding |
2596 | | * and no other values*/ |
2597 | 0 | for (offset = first_pad_offset; offset < captured_len; offset++) { |
2598 | 0 | val = tvb_get_uint8(tvb, offset); |
2599 | 0 | if (val != 0x00) |
2600 | 0 | return false; |
2601 | 0 | } |
2602 | 0 | return true; |
2603 | 0 | } |
2604 | | |
2605 | 0 | #define MIN_PADDED_ALLOWED_CHARS 4 |
2606 | | /* Experimental approach based upon the one used for PPP */ |
2607 | | static bool heur_dissect_at(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
2608 | 1 | { |
2609 | 1 | static const uint8_t at_magic1[2] = {0x0d, 0x0a}; |
2610 | 1 | static const uint8_t at_magic2[3] = {0x0d, 0x0d, 0x0a}; |
2611 | 1 | static const uint8_t at_magic3[2] = {0x41, 0x54}; /* 'A' 'T' */ |
2612 | 1 | int len, allwd_chars_len; |
2613 | 1 | tvbuff_t *tvb_no_padding; |
2614 | | |
2615 | 1 | if ((tvb_memeql(tvb, 0, at_magic1, sizeof(at_magic1)) == 0) || |
2616 | 1 | (tvb_memeql(tvb, 0, at_magic2, sizeof(at_magic2)) == 0) || |
2617 | 1 | (tvb_memeql(tvb, 0, at_magic3, sizeof(at_magic3)) == 0)){ |
2618 | 0 | len = tvb_captured_length(tvb); |
2619 | 0 | allwd_chars_len = allowed_chars_len(tvb,len); |
2620 | 0 | if(allwd_chars_len < len && allwd_chars_len > MIN_PADDED_ALLOWED_CHARS) { |
2621 | | /* Found some valid characters, check if rest is padding */ |
2622 | 0 | if(is_padded(tvb,len,allwd_chars_len)) { |
2623 | | /* This is a padded AT Command */ |
2624 | 0 | tvb_no_padding = tvb_new_subset_length(tvb, 0, allwd_chars_len); |
2625 | 0 | dissect_at(tvb_no_padding, pinfo, tree, data); |
2626 | 0 | return true; |
2627 | 0 | } |
2628 | 0 | } |
2629 | 0 | else if(allwd_chars_len == len) { |
2630 | | /* This is an (unpadded) AT Command */ |
2631 | 0 | dissect_at(tvb, pinfo, tree, data); |
2632 | 0 | return true; |
2633 | 0 | } |
2634 | 0 | } |
2635 | 1 | return false; |
2636 | 1 | } |
2637 | | |
2638 | | void |
2639 | | proto_register_at_command(void) |
2640 | 14 | { |
2641 | 14 | module_t *module; |
2642 | 14 | expert_module_t *expert_at; |
2643 | | |
2644 | 14 | static hf_register_info hf[] = { |
2645 | 14 | { &hf_command, |
2646 | 14 | { "Command", "at.command", |
2647 | 14 | FT_NONE, BASE_NONE, NULL, 0, |
2648 | 14 | NULL, HFILL} |
2649 | 14 | }, |
2650 | 14 | { &hf_data_part, |
2651 | 14 | { "Data Part", "at.data_part", |
2652 | 14 | FT_NONE, BASE_NONE, NULL, 0, |
2653 | 14 | NULL, HFILL} |
2654 | 14 | }, |
2655 | 14 | { &hf_parameters, |
2656 | 14 | { "Parameters", "at.parameters", |
2657 | 14 | FT_NONE, BASE_NONE, NULL, 0, |
2658 | 14 | NULL, HFILL} |
2659 | 14 | }, |
2660 | 14 | { &hf_data, |
2661 | 14 | { "AT Stream", "at.data", |
2662 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2663 | 14 | NULL, HFILL} |
2664 | 14 | }, |
2665 | 14 | { &hf_at_ignored, |
2666 | 14 | { "Ignored", "at.ignored", |
2667 | 14 | FT_BYTES, BASE_NONE, NULL, 0, |
2668 | 14 | NULL, HFILL} |
2669 | 14 | }, |
2670 | 14 | { &hf_at_cmd, |
2671 | 14 | { "Command", "at.cmd", |
2672 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2673 | 14 | NULL, HFILL} |
2674 | 14 | }, |
2675 | 14 | { &hf_at_cmd_type, |
2676 | 14 | { "Type", "at.cmd.type", |
2677 | 14 | FT_UINT16, BASE_HEX, VALS(at_cmd_type_vals), 0, |
2678 | 14 | NULL, HFILL} |
2679 | 14 | }, |
2680 | 14 | { &hf_at_command_line_prefix, |
2681 | 14 | { "Command Line Prefix", "at.command_line_prefix", |
2682 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2683 | 14 | NULL, HFILL} |
2684 | 14 | }, |
2685 | 14 | { &hf_parameter, |
2686 | 14 | { "Parameter", "at.parameter", |
2687 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2688 | 14 | NULL, HFILL} |
2689 | 14 | }, |
2690 | 14 | { &hf_unknown_parameter, |
2691 | 14 | { "Unknown Parameter", "at.unknown_parameter", |
2692 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2693 | 14 | NULL, HFILL} |
2694 | 14 | }, |
2695 | 14 | { &hf_role, |
2696 | 14 | { "Role", "at.role", |
2697 | 14 | FT_UINT8, BASE_DEC, VALS(role_vals), 0, |
2698 | 14 | NULL, HFILL} |
2699 | 14 | }, |
2700 | 14 | { &hf_cmer_mode, |
2701 | 14 | { "Mode", "at.cmer.mode", |
2702 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2703 | 14 | NULL, HFILL} |
2704 | 14 | }, |
2705 | 14 | { &hf_cmer_keyp, |
2706 | 14 | { "Keypad", "at.cmer.keyp", |
2707 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2708 | 14 | NULL, HFILL} |
2709 | 14 | }, |
2710 | 14 | { &hf_cmer_disp, |
2711 | 14 | { "Display", "at.cmer.disp", |
2712 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2713 | 14 | NULL, HFILL} |
2714 | 14 | }, |
2715 | 14 | { &hf_cmer_ind, |
2716 | 14 | { "Indicator", "at.cmer.ind", |
2717 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2718 | 14 | NULL, HFILL} |
2719 | 14 | }, |
2720 | 14 | { &hf_cmer_bfr, |
2721 | 14 | { "Buffer", "at.cmer.bfr", |
2722 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2723 | 14 | NULL, HFILL} |
2724 | 14 | }, |
2725 | 14 | { &hf_cme_error, |
2726 | 14 | { "CME Error (Numeric)", "at.cme_error", |
2727 | 14 | FT_UINT8, BASE_DEC, VALS(cme_error_vals), 0, |
2728 | 14 | NULL, HFILL} |
2729 | 14 | }, |
2730 | 14 | { &hf_cme_error_verbose, |
2731 | 14 | { "CME Error (Verbose)", "at.cme_error_verbose", |
2732 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2733 | 14 | NULL, HFILL} |
2734 | 14 | }, |
2735 | 14 | { &hf_cmee, |
2736 | 14 | { "Mode", "at.cmee", |
2737 | 14 | FT_UINT8, BASE_DEC, VALS(cmee_vals), 0, |
2738 | 14 | NULL, HFILL} |
2739 | 14 | }, |
2740 | 14 | { &hf_cmgl_req_status, |
2741 | 14 | { "Requested Status", "at.cmgl.req_status", |
2742 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2743 | 14 | "Status of the requested messages to list", |
2744 | 14 | HFILL} |
2745 | 14 | }, |
2746 | 14 | { &hf_cmgl_msg_index, |
2747 | 14 | { "Index", "at.cmgl.msg_index", |
2748 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2749 | 14 | "Index of the message", |
2750 | 14 | HFILL} |
2751 | 14 | }, |
2752 | 14 | { &hf_cmgl_msg_status, |
2753 | 14 | { "Status", "at.cmgl.msg_status", |
2754 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2755 | 14 | "Status of the message", |
2756 | 14 | HFILL} |
2757 | 14 | }, |
2758 | 14 | { &hf_cmgl_msg_originator_name, |
2759 | 14 | { "Originator Name", "at.cmgl.originator_name", |
2760 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2761 | 14 | "Originator name as saved in the phonebook", |
2762 | 14 | HFILL} |
2763 | 14 | }, |
2764 | 14 | { &hf_cmgl_msg_length, |
2765 | 14 | { "Length", "at.cmgl.pdu_length", |
2766 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2767 | 14 | "PDU Length", |
2768 | 14 | HFILL} |
2769 | 14 | }, |
2770 | 14 | { &hf_cmgl_msg_pdu, |
2771 | 14 | { "SMS PDU", "at.cmgl.pdu", |
2772 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2773 | 14 | NULL, HFILL} |
2774 | 14 | }, |
2775 | 14 | { &hf_cmgr_address, |
2776 | 14 | { "Address", "at.cmgr.address", |
2777 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2778 | 14 | NULL, HFILL} |
2779 | 14 | }, |
2780 | 14 | { &hf_cmgr_mode, |
2781 | 14 | { "Mode", "at.cmgr.mode", |
2782 | 14 | FT_UINT16, BASE_DEC, VALS(cmgr_mode_vals), 0, |
2783 | 14 | "Reading mode", |
2784 | 14 | HFILL} |
2785 | 14 | }, |
2786 | 14 | { &hf_cmgr_msg_index, |
2787 | 14 | { "Index", "at.cmgr.msg_index", |
2788 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2789 | 14 | "Index of the message", |
2790 | 14 | HFILL} |
2791 | 14 | }, |
2792 | 14 | { &hf_cmgr_msg_length, |
2793 | 14 | { "Length", "at.cmgr.pdu_length", |
2794 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2795 | 14 | "PDU Length", |
2796 | 14 | HFILL} |
2797 | 14 | }, |
2798 | 14 | { &hf_cmgr_msg_pdu, |
2799 | 14 | { "SMS PDU", "at.cmgr.pdu", |
2800 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2801 | 14 | NULL, HFILL} |
2802 | 14 | }, |
2803 | 14 | { &hf_cmgr_stat, |
2804 | 14 | { "Status", "at.cmgr.status", |
2805 | 14 | FT_UINT32, BASE_DEC, VALS(cmgr_stat_vals), 0, |
2806 | 14 | "Status of the returned message", |
2807 | 14 | HFILL} |
2808 | 14 | }, |
2809 | 14 | { &hf_cmux_k, |
2810 | 14 | { "Window Size", "at.k", |
2811 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2812 | 14 | "Window Size for Advanced option with Error-Recovery Mode", |
2813 | 14 | HFILL} |
2814 | 14 | }, |
2815 | 14 | { &hf_cmux_n1, |
2816 | 14 | { "Maximum Frame Size", "at.n1", |
2817 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2818 | 14 | NULL, HFILL} |
2819 | 14 | }, |
2820 | 14 | { &hf_cmux_n2, |
2821 | 14 | { "Maximum Number of Re-transmissions", "at.n2", |
2822 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2823 | 14 | NULL, HFILL} |
2824 | 14 | }, |
2825 | 14 | { &hf_cmux_port_speed, |
2826 | 14 | { "Transmission Rate", "at.port_speed", |
2827 | 14 | FT_UINT8, BASE_DEC, VALS(cmux_port_speed_vals), 0, |
2828 | 14 | NULL, |
2829 | 14 | HFILL} |
2830 | 14 | }, |
2831 | 14 | { &hf_cmux_subset, |
2832 | 14 | { "Subset", "at.subset", |
2833 | 14 | FT_UINT8, BASE_DEC, VALS(cmux_subset_vals), 0, |
2834 | 14 | NULL, |
2835 | 14 | HFILL} |
2836 | 14 | }, |
2837 | 14 | { &hf_cmux_t1, |
2838 | 14 | { "Acknowledgement Timer", "at.t1", |
2839 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2840 | 14 | "Acknowledgement timer in units of ten milliseconds", |
2841 | 14 | HFILL} |
2842 | 14 | }, |
2843 | 14 | { &hf_cmux_t2, |
2844 | 14 | { "Response Timer", "at.t2", |
2845 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2846 | 14 | "Response timer for the multiplexer control channel in units of ten milliseconds", |
2847 | 14 | HFILL} |
2848 | 14 | }, |
2849 | 14 | { &hf_cmux_t3, |
2850 | 14 | { "Wake Up Response Timer", "at.t3", |
2851 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2852 | 14 | "Wake up response timer in seconds", |
2853 | 14 | HFILL} |
2854 | 14 | }, |
2855 | 14 | { &hf_cmux_transparency, |
2856 | 14 | { "Transparency Mechanism", "at.transparency", |
2857 | 14 | FT_UINT8, BASE_DEC, VALS(cmux_transparency_vals), 0, |
2858 | 14 | NULL, |
2859 | 14 | HFILL} |
2860 | 14 | }, |
2861 | 14 | { &hf_chld_mode, |
2862 | 14 | { "Mode", "at.chld.mode_value", |
2863 | 14 | FT_UINT8, BASE_DEC, VALS(chld_vals), 0, |
2864 | 14 | NULL, HFILL} |
2865 | 14 | }, |
2866 | 14 | { &hf_chld_mode_1x, |
2867 | 14 | { "Mode: Releases specified active call only", "at.chld.mode", |
2868 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2869 | 14 | NULL, HFILL} |
2870 | 14 | }, |
2871 | 14 | { &hf_chld_mode_2x, |
2872 | 14 | { "Mode: Request private consultation mode with specified call - place all calls on hold EXCEPT the call indicated by x", "at.chld.mode", |
2873 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2874 | 14 | NULL, HFILL} |
2875 | 14 | }, |
2876 | 14 | { &hf_chld_supported_modes, |
2877 | 14 | { "Supported Modes", "at.chld.supported_modes", |
2878 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2879 | 14 | NULL, HFILL} |
2880 | 14 | }, |
2881 | 14 | { &hf_cimi_imsi, |
2882 | 14 | { "IMSI", "at.cimi.imsi", |
2883 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2884 | 14 | NULL, HFILL} |
2885 | 14 | }, |
2886 | 14 | { &hf_ciev_indicator_index, |
2887 | 14 | { "Indicator Index", "at.ciev.indicator_index", |
2888 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
2889 | 14 | NULL, HFILL} |
2890 | 14 | }, |
2891 | 14 | { &hf_vts_dtmf, |
2892 | 14 | { "DTMF", "at.vts.dtmf", |
2893 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2894 | 14 | NULL, HFILL} |
2895 | 14 | }, |
2896 | 14 | { &hf_vts_duration, |
2897 | 14 | { "Duration", "at.vts.duration", |
2898 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2899 | 14 | NULL, HFILL} |
2900 | 14 | }, |
2901 | 14 | { &hf_cops_mode, |
2902 | 14 | { "Mode", "at.cops.mode", |
2903 | 14 | FT_UINT8, BASE_DEC, VALS(cops_mode_vals), 0, |
2904 | 14 | NULL, HFILL} |
2905 | 14 | }, |
2906 | 14 | { &hf_cops_format, |
2907 | 14 | { "Format", "at.cops.format", |
2908 | 14 | FT_UINT8, BASE_DEC, VALS(cops_format_vals), 0, |
2909 | 14 | NULL, HFILL} |
2910 | 14 | }, |
2911 | 14 | { &hf_cops_operator, |
2912 | 14 | { "Operator", "at.cops.operator", |
2913 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2914 | 14 | NULL, HFILL} |
2915 | 14 | }, |
2916 | 14 | { &hf_cops_act, |
2917 | 14 | { "AcT", "at.cops.act", |
2918 | 14 | FT_UINT8, BASE_DEC, VALS(cops_act_vals), 0, |
2919 | 14 | NULL, HFILL} |
2920 | 14 | }, |
2921 | 14 | { &hf_cpin_code, |
2922 | 14 | { "Code", "at.cpin.code", |
2923 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2924 | 14 | NULL, HFILL} |
2925 | 14 | }, |
2926 | 14 | { &hf_cpin_pin, |
2927 | 14 | { "PIN", "at.cpin.pin", |
2928 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2929 | 14 | NULL, HFILL} |
2930 | 14 | }, |
2931 | 14 | { &hf_cpin_newpin, |
2932 | 14 | { "New PIN", "at.cpin.newpin", |
2933 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2934 | 14 | NULL, HFILL} |
2935 | 14 | }, |
2936 | 14 | { &hf_cpms_mem1, |
2937 | 14 | { "Read Memory Storage", "at.cpms.mem1", |
2938 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2939 | 14 | "Memory from which SMS messages are read and deleted", |
2940 | 14 | HFILL} |
2941 | 14 | }, |
2942 | 14 | { &hf_cpms_mem2, |
2943 | 14 | { "Write Memory Storage", "at.cpms.mem2", |
2944 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2945 | 14 | "Memory to which writing and sending operations are made", |
2946 | 14 | HFILL} |
2947 | 14 | }, |
2948 | 14 | { &hf_cpms_mem3, |
2949 | 14 | { "Receive Memory Storage", "at.cpms.mem3", |
2950 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2951 | 14 | "Memory to which received SMS is preferred to be stored", |
2952 | 14 | HFILL} |
2953 | 14 | }, |
2954 | 14 | { &hf_cpms_total1, |
2955 | 14 | { "Read Storage Capacity", "at.cpms.total1", |
2956 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2957 | 14 | "Total number of messages that the read/delete memory storage can contain", |
2958 | 14 | HFILL} |
2959 | 14 | }, |
2960 | 14 | { &hf_cpms_total2, |
2961 | 14 | { "Write Storage Capacity", "at.cpms.total2", |
2962 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2963 | 14 | "Total number of messages that the write/send memory storage can contain", |
2964 | 14 | HFILL} |
2965 | 14 | }, |
2966 | 14 | { &hf_cpms_total3, |
2967 | 14 | { "Receive Storage Capacity", "at.cpms.total3", |
2968 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2969 | 14 | "Total number of messages that the receive memory storage can contain", |
2970 | 14 | HFILL} |
2971 | 14 | }, |
2972 | 14 | { &hf_cpms_used1, |
2973 | 14 | { "Read Storage Messages Count", "at.cpms.used1", |
2974 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2975 | 14 | "Amount of messages in the read/delete memory storage", |
2976 | 14 | HFILL} |
2977 | 14 | }, |
2978 | 14 | { &hf_cpms_used2, |
2979 | 14 | { "Write Storage Messages Count", "at.cpms.used2", |
2980 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2981 | 14 | "Amount of messages in the write/send memory storage", |
2982 | 14 | HFILL} |
2983 | 14 | }, |
2984 | 14 | { &hf_cpms_used3, |
2985 | 14 | { "Receive Storage Messages Count", "at.cpms.used3", |
2986 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
2987 | 14 | "Amount of messages in the receive memory storage", |
2988 | 14 | HFILL} |
2989 | 14 | }, |
2990 | 14 | { &hf_cscs_chset, |
2991 | 14 | { "Character Set", "at.cscs.chset", |
2992 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2993 | 14 | NULL, HFILL} |
2994 | 14 | }, |
2995 | 14 | { &hf_csim_command, |
2996 | 14 | { "Command", "at.csim.command", |
2997 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
2998 | 14 | NULL, HFILL} |
2999 | 14 | }, |
3000 | 14 | { &hf_csim_length, |
3001 | 14 | { "Length", "at.csim.length", |
3002 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3003 | 14 | NULL, HFILL} |
3004 | 14 | }, |
3005 | 14 | { &hf_csim_response, |
3006 | 14 | { "Response", "at.csim.response", |
3007 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3008 | 14 | NULL, HFILL} |
3009 | 14 | }, |
3010 | 14 | { &hf_csq_ber, |
3011 | 14 | { "BER", "at.csq.ber", |
3012 | 14 | FT_UINT8, BASE_DEC, VALS(csq_ber_vals), 0, |
3013 | 14 | "Bit Error Rate", |
3014 | 14 | HFILL} |
3015 | 14 | }, |
3016 | 14 | { &hf_csq_rssi, |
3017 | 14 | { "RSSI", "at.csq.rssi", |
3018 | 14 | FT_UINT8, BASE_DEC, VALS(csq_rssi_vals), 0, |
3019 | 14 | "Received Signal Strength Indication", |
3020 | 14 | HFILL} |
3021 | 14 | }, |
3022 | 14 | { &hf_clip_mode, |
3023 | 14 | { "Mode", "at.clip.mode", |
3024 | 14 | FT_UINT8, BASE_DEC, VALS(clip_mode_vals), 0, |
3025 | 14 | NULL, HFILL} |
3026 | 14 | }, |
3027 | 14 | { &hf_clip_status, |
3028 | 14 | { "Status", "at.clip.status", |
3029 | 14 | FT_UINT8, BASE_DEC, VALS(clip_status_vals), 0, |
3030 | 14 | NULL, HFILL} |
3031 | 14 | }, |
3032 | 14 | { &hf_at_number, |
3033 | 14 | { "Number", "at.number", |
3034 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3035 | 14 | NULL, HFILL} |
3036 | 14 | }, |
3037 | 14 | { &hf_at_type, |
3038 | 14 | { "Type", "at.type", |
3039 | 14 | FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(at_type_vals), 0, |
3040 | 14 | NULL, HFILL} |
3041 | 14 | }, |
3042 | 14 | { &hf_at_subaddress, |
3043 | 14 | { "Subaddress", "at.subaddress", |
3044 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3045 | 14 | NULL, HFILL} |
3046 | 14 | }, |
3047 | 14 | { &hf_at_subaddress_type, |
3048 | 14 | { "Subaddress Type", "at.subaddress_type", |
3049 | 14 | FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(at_type_vals), 0, |
3050 | 14 | NULL, HFILL} |
3051 | 14 | }, |
3052 | 14 | { &hf_cnum_speed, |
3053 | 14 | { "Speed", "at.cnum.speed", |
3054 | 14 | FT_UINT8, BASE_DEC | BASE_EXT_STRING, &csd_data_rate_vals_ext, 0, |
3055 | 14 | NULL, HFILL} |
3056 | 14 | }, |
3057 | 14 | { &hf_cnum_service, |
3058 | 14 | { "Service", "at.cnum.service", |
3059 | 14 | FT_UINT8, BASE_DEC, VALS(cnum_service_vals), 0, |
3060 | 14 | NULL, HFILL} |
3061 | 14 | }, |
3062 | 14 | { &hf_cnum_itc, |
3063 | 14 | { "Information Transfer Capability", "at.cnum.itc", |
3064 | 14 | FT_UINT8, BASE_DEC, VALS(cnum_itc_vals), 0, |
3065 | 14 | NULL, HFILL} |
3066 | 14 | }, |
3067 | 14 | { &hf_at_alpha, |
3068 | 14 | { "Alpha", "at.alpha", |
3069 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3070 | 14 | NULL, HFILL} |
3071 | 14 | }, |
3072 | 14 | { &hf_at_cli_validity, |
3073 | 14 | { "CLI Validity", "at.cli_validity", |
3074 | 14 | FT_UINT8, BASE_DEC, VALS(cli_validity_vals), 0, |
3075 | 14 | NULL, HFILL} |
3076 | 14 | }, |
3077 | 14 | { &hf_at_priority, |
3078 | 14 | { "Priority", "at.priority", |
3079 | 14 | FT_UINT8, BASE_DEC, NULL, 0, |
3080 | 14 | NULL, HFILL} |
3081 | 14 | }, |
3082 | 14 | { &hf_clcc_id, |
3083 | 14 | { "ID", "at.clcc.id", |
3084 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3085 | 14 | NULL, HFILL} |
3086 | 14 | }, |
3087 | 14 | { &hf_clcc_dir, |
3088 | 14 | { "Direction", "at.clcc.dir", |
3089 | 14 | FT_UINT32, BASE_DEC, VALS(clcc_dir_vals), 0, |
3090 | 14 | NULL, HFILL} |
3091 | 14 | }, |
3092 | 14 | { &hf_clcc_stat, |
3093 | 14 | { "State", "at.clcc.stat", |
3094 | 14 | FT_UINT32, BASE_DEC, VALS(clcc_stat_vals), 0, |
3095 | 14 | NULL, HFILL} |
3096 | 14 | }, |
3097 | 14 | { &hf_clcc_mode, |
3098 | 14 | { "Mode", "at.clcc.mode", |
3099 | 14 | FT_UINT32, BASE_DEC, VALS(clcc_mode_vals), 0, |
3100 | 14 | NULL, HFILL} |
3101 | 14 | }, |
3102 | 14 | { &hf_clcc_mpty, |
3103 | 14 | { "Mpty", "at.clcc.mpty", |
3104 | 14 | FT_UINT32, BASE_DEC, VALS(clcc_mpty_vals), 0, |
3105 | 14 | NULL, HFILL} |
3106 | 14 | }, |
3107 | 14 | { &hf_ccwa_show_result_code, |
3108 | 14 | { "Show Result Code Presentation Status", "at.ccwa.presentation_status", |
3109 | 14 | FT_UINT32, BASE_DEC, VALS(ccwa_show_result_code_vals), 0, |
3110 | 14 | NULL, HFILL} |
3111 | 14 | }, |
3112 | 14 | { &hf_ccwa_mode, |
3113 | 14 | { "Mode", "at.ccwa.mode", |
3114 | 14 | FT_UINT32, BASE_DEC, VALS(ccwa_mode_vals), 0, |
3115 | 14 | NULL, HFILL} |
3116 | 14 | }, |
3117 | 14 | { &hf_ccwa_class, |
3118 | 14 | { "Class", "at.ccwa.class", |
3119 | 14 | FT_UINT32, BASE_DEC, VALS(ccwa_class_vals), 0, |
3120 | 14 | NULL, HFILL} |
3121 | 14 | }, |
3122 | 14 | { &hf_cfun_fun, |
3123 | 14 | { "Functionality", "at.cfun.fun", |
3124 | 14 | FT_UINT8, BASE_DEC, VALS(cfun_fun_vals), 0, |
3125 | 14 | NULL, HFILL} |
3126 | 14 | }, |
3127 | 14 | { &hf_cfun_rst, |
3128 | 14 | { "Reset", "at.cfun.rst", |
3129 | 14 | FT_UINT8, BASE_DEC, VALS(cfun_rst_vals), 0, |
3130 | 14 | NULL, HFILL} |
3131 | 14 | }, |
3132 | 14 | { &hf_cgdcont_cid, |
3133 | 14 | { "CID", "at.cgdcont.cid", |
3134 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3135 | 14 | NULL, HFILL} |
3136 | 14 | }, |
3137 | 14 | { &hf_cgdcont_pdp_type, |
3138 | 14 | { "PDP type", "at.cgdcont.pdp_type", |
3139 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3140 | 14 | NULL, HFILL} |
3141 | 14 | }, |
3142 | 14 | { &hf_cgdcont_apn, |
3143 | 14 | { "APN", "at.cgdcont.apn", |
3144 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3145 | 14 | "Access Point Name", HFILL} |
3146 | 14 | }, |
3147 | 14 | { &hf_cgdcont_pdp_addr, |
3148 | 14 | { "PDP address", "at.cgdcont.pdp_addr", |
3149 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3150 | 14 | NULL, HFILL} |
3151 | 14 | }, |
3152 | 14 | { &hf_cgdcont_d_comp, |
3153 | 14 | { "Data compression", "at.cgdcont.d_comp", |
3154 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3155 | 14 | NULL, HFILL} |
3156 | 14 | }, |
3157 | 14 | { &hf_cgdcont_h_comp, |
3158 | 14 | { "Header compression", "at.cgdcont.h_comp", |
3159 | 14 | FT_UINT32, BASE_DEC, NULL, 0, |
3160 | 14 | NULL, HFILL} |
3161 | 14 | }, |
3162 | 14 | { &hf_cgmi_manufacturer_id, |
3163 | 14 | { "Manufacturer Identification", "at.cgmi.manufacturer_id", |
3164 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3165 | 14 | NULL, HFILL} |
3166 | 14 | }, |
3167 | 14 | { &hf_cgmm_model_id, |
3168 | 14 | { "Model Identification", "at.cgmm.model_id", |
3169 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3170 | 14 | NULL, HFILL} |
3171 | 14 | }, |
3172 | 14 | { &hf_cgmr_revision_id, |
3173 | 14 | { "Revision Identification", "at.cgmr.revision_id", |
3174 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3175 | 14 | NULL, HFILL} |
3176 | 14 | }, |
3177 | 14 | { &hf_gmi_manufacturer_id, |
3178 | 14 | { "Manufacturer Identification", "at.gmi.manufacturer_id", |
3179 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3180 | 14 | NULL, HFILL} |
3181 | 14 | }, |
3182 | 14 | { &hf_gmm_model_id, |
3183 | 14 | { "Model Identification", "at.gmm.model_id", |
3184 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3185 | 14 | NULL, HFILL} |
3186 | 14 | }, |
3187 | 14 | { &hf_gmr_revision_id, |
3188 | 14 | { "Revision Identification", "at.gmr.revision_id", |
3189 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3190 | 14 | NULL, HFILL} |
3191 | 14 | }, |
3192 | 14 | { &hf_zpas_network, |
3193 | 14 | { "Network type", "at.zpas.network", |
3194 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3195 | 14 | NULL, HFILL} |
3196 | 14 | }, |
3197 | 14 | { &hf_zpas_srv_domain, |
3198 | 14 | { "Service domain", "at.zpas.srv_domain", |
3199 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3200 | 14 | NULL, HFILL} |
3201 | 14 | }, |
3202 | 14 | { &hf_zusim_usim_card, |
3203 | 14 | { "USIM card type", "at.zusim.usim_card", |
3204 | 14 | FT_UINT8, BASE_DEC, VALS(zusim_usim_card_vals), 0, |
3205 | 14 | "The type of the current (U)SIM card", |
3206 | 14 | HFILL} |
3207 | 14 | }, |
3208 | 14 | { &hf_indicator[0], |
3209 | 14 | { "Indicator 1", "at.indicator.1", |
3210 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3211 | 14 | NULL, HFILL} |
3212 | 14 | }, |
3213 | 14 | { &hf_indicator[1], |
3214 | 14 | { "Indicator 2", "at.indicator.2", |
3215 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3216 | 14 | NULL, HFILL} |
3217 | 14 | }, |
3218 | 14 | { &hf_indicator[2], |
3219 | 14 | { "Indicator 3", "at.indicator.3", |
3220 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3221 | 14 | NULL, HFILL} |
3222 | 14 | }, |
3223 | 14 | { &hf_indicator[3], |
3224 | 14 | { "Indicator 4", "at.indicator.4", |
3225 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3226 | 14 | NULL, HFILL} |
3227 | 14 | }, |
3228 | 14 | { &hf_indicator[4], |
3229 | 14 | { "Indicator 5", "at.indicator.5", |
3230 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3231 | 14 | NULL, HFILL} |
3232 | 14 | }, |
3233 | 14 | { &hf_indicator[5], |
3234 | 14 | { "Indicator 6", "at.indicator.6", |
3235 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3236 | 14 | NULL, HFILL} |
3237 | 14 | }, |
3238 | 14 | { &hf_indicator[6], |
3239 | 14 | { "Indicator 7", "at.indicator.7", |
3240 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3241 | 14 | NULL, HFILL} |
3242 | 14 | }, |
3243 | 14 | { &hf_indicator[7], |
3244 | 14 | { "Indicator 8", "at.indicator.8", |
3245 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3246 | 14 | NULL, HFILL} |
3247 | 14 | }, |
3248 | 14 | { &hf_indicator[8], |
3249 | 14 | { "Indicator 9", "at.indicator.9", |
3250 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3251 | 14 | NULL, HFILL} |
3252 | 14 | }, |
3253 | 14 | { &hf_indicator[9], |
3254 | 14 | { "Indicator 10", "at.indicator.10", |
3255 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3256 | 14 | NULL, HFILL} |
3257 | 14 | }, |
3258 | 14 | { &hf_indicator[10], |
3259 | 14 | { "Indicator 11", "at.indicator.11", |
3260 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3261 | 14 | NULL, HFILL} |
3262 | 14 | }, |
3263 | 14 | { &hf_indicator[11], |
3264 | 14 | { "Indicator 12", "at.indicator.12", |
3265 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3266 | 14 | NULL, HFILL} |
3267 | 14 | }, |
3268 | 14 | { &hf_indicator[12], |
3269 | 14 | { "Indicator 13", "at.indicator.13", |
3270 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3271 | 14 | NULL, HFILL} |
3272 | 14 | }, |
3273 | 14 | { &hf_indicator[13], |
3274 | 14 | { "Indicator 14", "at.indicator.14", |
3275 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3276 | 14 | NULL, HFILL} |
3277 | 14 | }, |
3278 | 14 | { &hf_indicator[14], |
3279 | 14 | { "Indicator 15", "at.indicator.15", |
3280 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3281 | 14 | NULL, HFILL} |
3282 | 14 | }, |
3283 | 14 | { &hf_indicator[15], |
3284 | 14 | { "Indicator 16", "at.indicator.16", |
3285 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3286 | 14 | NULL, HFILL} |
3287 | 14 | }, |
3288 | 14 | { &hf_indicator[16], |
3289 | 14 | { "Indicator 17", "at.indicator.17", |
3290 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3291 | 14 | NULL, HFILL} |
3292 | 14 | }, |
3293 | 14 | { &hf_indicator[17], |
3294 | 14 | { "Indicator 18", "at.indicator.18", |
3295 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3296 | 14 | NULL, HFILL} |
3297 | 14 | }, |
3298 | 14 | { &hf_indicator[18], |
3299 | 14 | { "Indicator 19", "at.indicator.19", |
3300 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3301 | 14 | NULL, HFILL} |
3302 | 14 | }, |
3303 | 14 | { &hf_indicator[19], |
3304 | 14 | { "Indicator 20", "at.indicator.20", |
3305 | 14 | FT_STRING, BASE_NONE, NULL, 0, |
3306 | 14 | NULL, HFILL} |
3307 | 14 | }, |
3308 | 14 | }; |
3309 | | |
3310 | 14 | static ei_register_info ei[] = { |
3311 | 14 | { &ei_unknown_command, { "at.expert.unknown_command", PI_PROTOCOL, PI_NOTE, "Unknown or Non-standard AT command", EXPFILL }}, |
3312 | 14 | { &ei_invalid_usage, { "at.expert.invalid_usage", PI_PROTOCOL, PI_WARN, "Non mandatory type or command in this role", EXPFILL }}, |
3313 | 14 | { &ei_unknown_parameter, { "at.expert.unknown_parameter", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }}, |
3314 | 14 | { &ei_cmer_mode, { "at.expert.cmer.mode", PI_PROTOCOL, PI_WARN, "Only 0-3 are valid", EXPFILL }}, |
3315 | 14 | { &ei_cmer_keyp, { "at.expert.cmer.keyp", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }}, |
3316 | 14 | { &ei_cmer_disp, { "at.expert.cmer.disp", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }}, |
3317 | 14 | { &ei_cmer_ind, { "at.expert.cmer.ind", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }}, |
3318 | 14 | { &ei_cmer_bfr, { "at.expert.cmer.bfr", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }}, |
3319 | 14 | { &ei_chld_mode, { "at.expert.chld.mode", PI_PROTOCOL, PI_WARN, "Invalid value", EXPFILL }}, |
3320 | 14 | { &ei_ciev_indicator, { "at.expert.ciev.indicator", PI_PROTOCOL, PI_WARN, "Unknown indicator", EXPFILL }}, |
3321 | 14 | { &ei_cfun_res_fun, { "at.expert.cfun.reserved_fun", PI_PROTOCOL, PI_NOTE, "Manufacturer specific value for an intermediate states between full and minimum functionality", EXPFILL }}, |
3322 | 14 | { &ei_cfun_range_fun, { "at.expert.cfun.invalid_fun", PI_PROTOCOL, PI_WARN, "Only 0-127 are valid", EXPFILL }}, |
3323 | 14 | { &ei_cfun_rst, { "at.expert.cfun.rst", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }}, |
3324 | 14 | { &ei_vts_dtmf, { "at.expert.vts.dtmf", PI_PROTOCOL, PI_WARN, "DTMF should be single character", EXPFILL }}, |
3325 | 14 | { &ei_at_type, { "at.expert.at.type", PI_PROTOCOL, PI_WARN, "Unknown type value", EXPFILL }}, |
3326 | 14 | { &ei_cnum_service, { "at.expert.cnum.service", PI_PROTOCOL, PI_WARN, "Only 0-5 are valid", EXPFILL }}, |
3327 | 14 | { &ei_cnum_itc, { "at.expert.cnum.itc", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }}, |
3328 | 14 | { &ei_empty_hex, { "at.expert.csim.empty_hex", PI_PROTOCOL, PI_WARN, "Hex string is empty", EXPFILL }}, |
3329 | 14 | { &ei_invalid_hex, { "at.expert.csim.invalid_hex", PI_PROTOCOL, PI_WARN, "Non hex character found in hex string", EXPFILL }}, |
3330 | 14 | { &ei_odd_len, { "at.expert.csim.odd_len", PI_PROTOCOL, PI_WARN, "Odd hex string length", EXPFILL }}, |
3331 | 14 | { &ei_csq_ber, { "at.expert.csq.ber", PI_PROTOCOL, PI_WARN, "Only 0-7 and 99 are valid", EXPFILL }}, |
3332 | 14 | { &ei_csq_rssi, { "at.expert.csq.rssi", PI_PROTOCOL, PI_WARN, "Only 0-31 and 99 are valid", EXPFILL }}, |
3333 | 14 | }; |
3334 | | |
3335 | 14 | static int *ett[] = { |
3336 | 14 | &ett_at, |
3337 | 14 | &ett_at_command, |
3338 | 14 | &ett_at_data_part, |
3339 | 14 | &ett_at_parameters, |
3340 | 14 | }; |
3341 | | |
3342 | 14 | proto_at = proto_register_protocol("AT Command", "AT", "at"); |
3343 | 14 | proto_register_field_array(proto_at, hf, array_length(hf)); |
3344 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
3345 | | |
3346 | 14 | expert_at = expert_register_protocol(proto_at); |
3347 | 14 | expert_register_field_array(expert_at, ei, array_length(ei)); |
3348 | | |
3349 | 14 | module = prefs_register_protocol(proto_at, NULL); |
3350 | 14 | prefs_register_enum_preference(module, "role", |
3351 | 14 | "Force treat packets as DTE (PC) or DCE (Modem) role", |
3352 | 14 | "Force treat packets as DTE (PC) or DCE (Modem) role", |
3353 | 14 | &at_role, pref_at_role, true); |
3354 | | |
3355 | 14 | register_dissector("at", dissect_at, proto_at); |
3356 | 14 | } |
3357 | | |
3358 | | /* Handler registration */ |
3359 | | void |
3360 | | proto_reg_handoff_at_command(void) |
3361 | 14 | { |
3362 | 14 | gsm_sim_handle = find_dissector_add_dependency("gsm_sim.part", proto_at); |
3363 | 14 | gsm_sms_handle = find_dissector_add_dependency("gsm_sms", proto_at); |
3364 | | |
3365 | 14 | heur_dissector_add("usb.bulk", heur_dissect_at, "AT Command USB bulk endpoint", "at_usb_bulk", proto_at, HEURISTIC_ENABLE); |
3366 | 14 | heur_dissector_add("usb.control", heur_dissect_at, "AT Command USB control endpoint", "at_usb_control", proto_at, HEURISTIC_ENABLE); |
3367 | 14 | } |
3368 | | |
3369 | | /* |
3370 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
3371 | | * |
3372 | | * Local variables: |
3373 | | * c-basic-offset: 4 |
3374 | | * tab-width: 8 |
3375 | | * indent-tabs-mode: nil |
3376 | | * End: |
3377 | | * |
3378 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
3379 | | * :indentSize=4:tabSize=8:noTabs=true: |
3380 | | */ |