Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-at.c
blob780e35522325c1dbabdf0fae52ea3abb8699642c
1 /* packet-at.c
2 * Dissector for AT Commands
4 * Copyright 2011, Tyson Key <tyson.key@gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "config.h"
16 #include <stdio.h> /* for sscanf() */
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>
24 #include "packet-e212.h"
26 void proto_register_at_command(void);
27 void proto_reg_handoff_at_command(void);
29 static int proto_at;
31 static dissector_handle_t gsm_sim_handle;
32 static dissector_handle_t gsm_sms_handle;
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];
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;
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;
173 #define ROLE_UNKNOWN 0
174 #define ROLE_DCE 1
175 #define ROLE_DTE 2
177 #define TYPE_UNKNOWN 0x0000
178 #define TYPE_RESPONSE_ACK 0x0d0a
179 #define TYPE_RESPONSE 0x003a
180 #define TYPE_ACTION 0x003d
181 #define TYPE_ACTION_SIMPLY 0x000d
182 #define TYPE_READ 0x003f
183 #define TYPE_TEST 0x3d3f
185 #define STORE_COMMAND_MAX_LEN 20
187 static int at_role = ROLE_UNKNOWN;
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 }
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 }
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 }
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 }
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 }
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 }
272 static const value_string cmee_vals[] = {
273 { 0, "Disabled" },
274 { 1, "Enabled" },
275 { 2, "Verbose" },
276 { 0, NULL }
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 }
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 }
296 static const value_string cmux_transparency_vals[] = {
297 { 0, "Basic option" },
298 { 1, "Advanced option" },
299 { 0, NULL }
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 }
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 }
320 static const value_string cops_format_vals[] = {
321 { 0, "Long Format Alphanumeric" },
322 { 1, "Short Format Alphanumeric" },
323 { 2, "Numeric" },
324 { 0, NULL }
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 }
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 }
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 }
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 }
370 static const value_string cnum_itc_vals[] = {
371 { 0, "3.1 kHz" },
372 { 1, "UDI" },
373 { 0, NULL }
376 static const value_string clip_mode_vals[] = {
377 { 0, "Disabled" },
378 { 1, "Enabled" },
379 { 0, NULL }
382 static const value_string clip_status_vals[] = {
383 { 0, "CLIP not Provisioned" },
384 { 1, "CLIP Provisioned" },
385 { 2, "Unknown" },
386 { 0, NULL }
389 static const value_string clcc_dir_vals[] = {
390 { 0, "Mobile Originated" },
391 { 1, "Mobile Terminated" },
392 { 0, NULL }
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 }
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 }
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 }
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 }
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 }
440 static const value_string ccwa_show_result_code_vals[] = {
441 { 0, "Disabled" },
442 { 1, "Enabled" },
443 { 0, NULL }
446 static const value_string ccwa_mode_vals[] = {
447 { 0, "Disabled" },
448 { 1, "Enabled" },
449 { 2, "Query Status" },
450 { 0, NULL }
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 }
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 }
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 }
515 static const value_string zusim_usim_card_vals[] = {
516 { 0, "SIM" },
517 { 1, "USIM" },
518 { 0, NULL }
521 extern value_string_ext csd_data_rate_vals_ext;
523 struct _at_packet_info_t;
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;
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;
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;
554 typedef struct _at_cmd_t {
555 const char *name;
556 const char *long_name;
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;
565 static at_conv_info_t *
566 get_at_conv_info(conversation_t *conversation)
568 if (!conversation)
569 return NULL;
570 at_conv_info_t *at_conv_info;
571 /* do we have conversation specific data ? */
572 at_conv_info = (at_conv_info_t *)conversation_get_proto_data(conversation, proto_at);
573 if (!at_conv_info) {
574 /* no not yet so create some */
575 at_conv_info = wmem_new0(wmem_file_scope(), at_conv_info_t);
576 conversation_add_proto_data(conversation, proto_at, at_conv_info);
578 return at_conv_info;
581 static at_packet_info_t *
582 get_at_packet_info(packet_info *pinfo, at_conv_info_t *at_conv)
584 at_packet_info_t *at_info;
585 at_info = (at_packet_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_at, 0);
586 if (!at_info) {
587 at_info = wmem_new0(wmem_file_scope(), at_packet_info_t);
588 p_add_proto_data(wmem_file_scope(), pinfo, proto_at, 0, at_info);
589 if(at_conv) {
590 at_info->initial_dce_command = at_conv->dce_command;
591 at_info->initial_dte_command = at_conv->dte_command;
594 at_info->current_dce_command = at_info->initial_dce_command;
595 at_info->current_dte_command = at_info->initial_dte_command;
596 return at_info;
599 static void
600 set_at_packet_info(packet_info *pinfo, at_conv_info_t *at_conv, at_packet_info_t *at_info)
602 if(at_conv && !PINFO_FD_VISITED(pinfo))
604 at_conv->dce_command = at_info->current_dce_command;
605 at_conv->dte_command = at_info->current_dte_command;
609 static at_processed_cmd_t *get_current_role_last_command(at_packet_info_t *at_info, uint32_t role)
611 if(!at_info) return NULL;
612 return role == ROLE_DCE ? &at_info->current_dce_command : &at_info->current_dte_command;
615 static uint32_t get_uint_parameter(wmem_allocator_t *pool, uint8_t *parameter_stream, int parameter_length)
617 uint32_t value;
618 char *val;
620 val = (char*) wmem_alloc(pool, parameter_length + 1);
621 memcpy(val, parameter_stream, parameter_length);
622 val[parameter_length] = '\0';
623 value = (uint32_t) g_ascii_strtoull(val, NULL, 10);
625 return value;
628 static bool check_only_dce_role(int role, uint16_t type) {
629 if (role == ROLE_DCE && type == TYPE_RESPONSE_ACK) return true;
631 return false;
634 static bool check_only_dte_role(int role, uint16_t type) {
635 if (role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) return true;
637 return false;
640 static bool check_ccwa(int role, uint16_t type) {
641 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
642 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
644 return false;
647 static bool check_cfun(int role, uint16_t type) {
648 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
649 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
651 return false;
654 static bool check_cgdcont(int role, uint16_t type) {
655 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_ACTION_SIMPLY ||
656 type == TYPE_READ || type == TYPE_TEST)) return true;
657 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
659 return false;
662 static bool check_cgmi(int role, uint16_t type) {
663 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
664 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
666 return false;
669 static bool check_cgmm(int role, uint16_t type) {
670 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
671 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
673 return false;
676 static bool check_cgmr(int role, uint16_t type) {
677 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
678 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
680 return false;
683 static bool check_cgsn(int role, uint16_t type) {
684 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
686 return false;
689 static bool check_chld(int role, uint16_t type) {
690 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
691 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
693 return false;
696 static bool check_chup(int role, uint16_t type) {
697 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
699 return false;
702 static bool check_ciev(int role, uint16_t type) {
703 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
705 return false;
708 static bool check_cimi(int role, uint16_t type) {
709 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
710 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
712 return false;
715 static bool check_cind(int role, uint16_t type) {
716 if (role == ROLE_DTE && (type == TYPE_READ || type == TYPE_TEST)) return true;
717 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
719 return false;
722 static bool check_clac(int role, uint16_t type) {
723 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
725 return false;
728 static bool check_clcc(int role, uint16_t type) {
729 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
730 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
732 return false;
735 static bool check_clip(int role, uint16_t type) {
736 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
737 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
739 return false;
742 static bool check_cme(int role, uint16_t type) {
743 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
745 return false;
748 static bool check_cmee(int role, uint16_t type) {
749 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_ACTION_SIMPLY ||
750 type == TYPE_TEST || type == TYPE_READ)) return true;
751 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
753 return false;
756 static bool check_cmer(int role, uint16_t type) {
757 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
758 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
760 return false;
763 static bool check_cmgl(int role, uint16_t type) {
764 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
765 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
767 return false;
770 static bool check_cmgr(int role, uint16_t type) {
771 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
772 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
774 return false;
777 static bool check_cmux(int role, uint16_t type) {
778 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
779 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
781 return false;
784 static bool check_cnum(int role, uint16_t type) {
785 if (role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) return true;
786 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
788 return false;
791 static bool check_cops(int role, uint16_t type) {
792 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ)) return true;
793 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
795 return false;
798 static bool check_cpin(int role, uint16_t type) {
799 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
800 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
802 return false;
805 static bool check_cpms(int role, uint16_t type) {
806 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
807 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
809 return false;
812 static bool check_cscs(int role, uint16_t type) {
813 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
814 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
816 return false;
819 static bool check_csim(int role, uint16_t type) {
820 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
821 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
823 return false;
826 static bool check_csq(int role, uint16_t type) {
827 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
828 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
830 return false;
833 static bool check_csupi(int role, uint16_t type) {
834 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
836 return false;
839 static bool check_gmi(int role, uint16_t type) {
840 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
841 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
843 return false;
846 static bool check_gmm(int role, uint16_t type) {
847 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
848 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
850 return false;
853 static bool check_gmr(int role, uint16_t type) {
854 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
855 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
857 return false;
860 static bool check_gsn(int role, uint16_t type) {
861 if (role == ROLE_DTE && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
863 return false;
866 static bool check_vts(int role, uint16_t type) {
867 if (role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
868 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
870 return false;
873 static bool check_zpas(int role, uint16_t type) {
874 if (role == ROLE_DTE && type == TYPE_READ) return true;
875 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
877 return false;
880 static bool check_zusim(int role, uint16_t type) {
881 if (role == ROLE_DTE && type == TYPE_TEST) return true;
882 if (role == ROLE_DCE && type == TYPE_RESPONSE) return true;
884 return false;
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_)
892 proto_item *pitem;
893 uint32_t value;
895 if (!check_ccwa(role, type)) return false;
897 if (role == ROLE_DTE && parameter_number > 2) return false;
898 if (role == ROLE_DCE && parameter_number > 7) return false;
900 if (role == ROLE_DTE) switch (parameter_number) {
901 case 0:
902 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
903 proto_tree_add_uint(tree, hf_ccwa_show_result_code, tvb, offset, parameter_length, value);
904 break;
905 case 1:
906 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
907 proto_tree_add_uint(tree, hf_ccwa_mode, tvb, offset, parameter_length, value);
908 break;
909 case 2:
910 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
911 proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
912 break;
915 /* If AT+CCWA = 1 */
916 if (role == ROLE_DCE) switch (parameter_number) {
917 case 0:
918 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
919 break;
920 case 1:
921 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
922 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
923 if (value < 128 || value > 175)
924 expert_add_info(pinfo, pitem, &ei_at_type);
925 break;
926 case 2:
927 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
928 proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
929 break;
930 case 3:
931 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
932 break;
933 case 4:
934 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
935 proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
936 break;
937 case 5:
938 proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
939 break;
940 case 6:
941 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
942 proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
943 break;
944 case 7:
945 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
946 proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
947 break;
950 return true;
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_)
958 proto_item *pitem;
959 uint32_t value;
961 if (!check_cfun(role, type)) return false;
963 if (parameter_number > 1) return false;
965 if (role == ROLE_DTE) switch (parameter_number) {
966 case 0:
967 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
968 pitem = proto_tree_add_uint(tree, hf_cfun_fun, tvb, offset, parameter_length, value);
969 if (value > 4 && value < 128)
970 expert_add_info(pinfo, pitem, &ei_cfun_res_fun);
971 else if (value >= 128)
972 expert_add_info(pinfo, pitem, &ei_cfun_range_fun);
973 break;
974 case 1:
975 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
976 pitem = proto_tree_add_uint(tree, hf_cfun_rst, tvb, offset, parameter_length, value);
977 if (value > 1)
978 expert_add_info(pinfo, pitem, &ei_cfun_rst);
979 break;
982 /* TODO: Currently assuming response is for READ command, add support for
983 * TEST commands response */
984 if (role == ROLE_DCE) switch (parameter_number) {
985 case 0:
986 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
987 pitem = proto_tree_add_uint(tree, hf_cfun_fun, tvb, offset, parameter_length, value);
988 if (value > 4 && value < 128)
989 expert_add_info(pinfo, pitem, &ei_cfun_res_fun);
990 else if (value >= 128)
991 expert_add_info(pinfo, pitem, &ei_cfun_range_fun);
992 break;
993 case 1:
994 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
995 pitem = proto_tree_add_uint(tree, hf_cfun_rst, tvb, offset, parameter_length, value);
996 if (value > 1)
997 expert_add_info(pinfo, pitem, &ei_cfun_rst);
998 break;
1001 return true;
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_)
1010 uint32_t value;
1012 if (!check_cgdcont(role, type)) return false;
1014 switch (parameter_number) {
1015 case 0:
1016 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1017 proto_tree_add_uint(tree, hf_cgdcont_cid, tvb, offset, parameter_length, value);
1018 break;
1019 case 1:
1020 proto_tree_add_item(tree, hf_cgdcont_pdp_type, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1021 break;
1022 case 2:
1023 proto_tree_add_item(tree, hf_cgdcont_apn, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1024 break;
1025 case 3:
1026 proto_tree_add_item(tree, hf_cgdcont_pdp_addr, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1027 break;
1028 case 4:
1029 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1030 proto_tree_add_uint(tree, hf_cgdcont_d_comp, tvb, offset, parameter_length, value);
1031 break;
1032 case 5:
1033 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1034 proto_tree_add_uint(tree, hf_cgdcont_h_comp, tvb, offset, parameter_length, value);
1035 break;
1036 default:
1037 proto_tree_add_item(tree, hf_parameter, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1038 break;
1041 return true;
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_)
1049 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1050 return false;
1053 if (parameter_number > 1) return false;
1055 proto_tree_add_item(tree, hf_cgmi_manufacturer_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1057 return true;
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_)
1065 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1066 return false;
1069 if (parameter_number > 1) return false;
1071 proto_tree_add_item(tree, hf_cgmm_model_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1073 return true;
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_)
1081 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1082 return false;
1085 if (parameter_number > 1) return false;
1087 proto_tree_add_item(tree, hf_cgmr_revision_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1089 return true;
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_)
1097 uint32_t value;
1099 if (!check_chld(role, type)) return false;
1101 if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number == 0) {
1102 value = get_uint_parameter(pinfo->pool, parameter_stream, 1);
1104 if (parameter_length >= 2) {
1105 if (tvb_get_uint8(tvb, offset + 1) == 'x') {
1106 if (value == 1)
1107 proto_tree_add_item(tree, hf_chld_mode_1x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1108 else if (value == 2)
1109 proto_tree_add_item(tree, hf_chld_mode_2x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1112 if (tvb_get_uint8(tvb, offset + 1) != 'x' || value > 4) {
1113 proto_tree_add_expert(tree, pinfo, &ei_chld_mode, tvb, offset, parameter_length);
1117 proto_tree_add_uint(tree, hf_chld_mode, tvb, offset, parameter_length, value);
1118 return true;
1121 /* Type == Test */
1122 proto_tree_add_item(tree, hf_chld_supported_modes, tvb, offset,
1123 parameter_length, ENC_NA | ENC_ASCII);
1125 return true;
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)
1133 uint32_t value;
1134 unsigned indicator_index;
1136 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return true;
1137 if (parameter_number > 1) return false;
1139 switch (parameter_number) {
1140 case 0:
1141 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1142 proto_tree_add_uint(tree, hf_ciev_indicator_index, tvb, offset, parameter_length, value);
1143 *data = wmem_alloc(pinfo->pool, sizeof(unsigned));
1144 *((unsigned *) *data) = value;
1145 break;
1146 case 1:
1147 indicator_index = *((unsigned *) *data) - 1;
1148 if (indicator_index > 19) {
1149 proto_tree_add_expert(tree, pinfo, &ei_ciev_indicator, tvb, offset, parameter_length);
1150 } else {
1151 proto_tree_add_item(tree, hf_indicator[indicator_index], tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1153 break;
1156 return true;
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_)
1164 proto_item *pitem;
1166 if (!check_cimi(role, type)) return false;
1168 if (role == ROLE_DTE) return false;
1169 if (parameter_number > 0) return false;
1171 /* Only parameter is found in the response from DCE - the IMSI */
1172 pitem = proto_tree_add_item(tree, hf_cimi_imsi, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1173 /* Hiding the AT IMSI item because we are showing the detailed E.212 item */
1174 proto_item_set_hidden(pitem);
1175 dissect_e212_utf8_imsi(tvb, pinfo, tree, offset, parameter_length);
1177 return true;
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_)
1185 if (!check_cind(role, type)) return false;
1186 if (parameter_number > 19) return false;
1188 proto_tree_add_item(tree, hf_indicator[parameter_number], tvb, offset,
1189 parameter_length, ENC_NA | ENC_ASCII);
1191 return true;
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_)
1199 proto_item *pitem;
1200 uint32_t value;
1202 if (!((role == ROLE_DTE && type == TYPE_ACTION_SIMPLY) ||
1203 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1204 return false;
1207 if (parameter_number > 8) return false;
1209 switch (parameter_number) {
1210 case 0:
1211 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1212 proto_tree_add_uint(tree, hf_clcc_id, tvb, offset, parameter_length, value);
1213 break;
1214 case 1:
1215 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1216 proto_tree_add_uint(tree, hf_clcc_dir, tvb, offset, parameter_length, value);
1217 break;
1218 case 2:
1219 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1220 proto_tree_add_uint(tree, hf_clcc_stat, tvb, offset, parameter_length, value);
1221 break;
1222 case 3:
1223 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1224 proto_tree_add_uint(tree, hf_clcc_mode, tvb, offset, parameter_length, value);
1225 break;
1226 case 4:
1227 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1228 proto_tree_add_uint(tree, hf_clcc_mpty, tvb, offset, parameter_length, value);
1229 break;
1230 case 5:
1231 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1232 break;
1233 case 6:
1234 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1235 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1236 if (value < 128 || value > 175)
1237 expert_add_info(pinfo, pitem, &ei_at_type);
1238 break;
1239 case 7:
1240 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1241 break;
1242 case 8:
1243 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1244 proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
1245 break;
1248 return true;
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_)
1256 proto_item *pitem;
1257 uint32_t value;
1259 if (!check_clip(role, type))
1260 return false;
1262 if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number > 1)
1263 return false;
1264 else if (role == ROLE_DCE && parameter_number > 5)
1265 return false;
1267 if (role == ROLE_DTE && type == TYPE_ACTION) switch (parameter_number) {
1268 case 0:
1269 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1270 proto_tree_add_uint(tree, hf_clip_mode, tvb, offset, parameter_length, value);
1271 break;
1272 case 1:
1273 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1274 proto_tree_add_uint(tree, hf_clip_status, tvb, offset, parameter_length, value);
1275 break;
1276 } else {
1277 switch (parameter_number) {
1278 case 0:
1279 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1280 break;
1281 case 1:
1282 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1283 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1284 if (value < 128 || value > 175)
1285 expert_add_info(pinfo, pitem, &ei_at_type);
1286 break;
1287 case 2:
1288 proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1289 break;
1290 case 3:
1291 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1292 proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
1293 break;
1294 case 4:
1295 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1296 break;
1297 case 5:
1298 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1299 proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
1300 break;
1304 return true;
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_)
1312 uint32_t value;
1313 int i;
1314 char curr_char;
1316 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1317 return false;
1320 if (parameter_number > 0) return false;
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 for (i = 0; i < parameter_length; i++) {
1325 curr_char = parameter_stream[i];
1326 if (!g_ascii_isdigit(curr_char) && curr_char != ' ') {
1327 proto_tree_add_item(tree, hf_cme_error_verbose, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1328 return true;
1331 /* Assume numeric error code*/
1332 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1333 proto_tree_add_uint(tree, hf_cme_error, tvb, offset, parameter_length, value);
1335 return true;
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_)
1343 uint32_t value;
1345 if (!(role == ROLE_DTE && type == TYPE_ACTION) &&
1346 !(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1347 return false;
1350 if (parameter_number > 0) return false;
1352 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1353 proto_tree_add_uint(tree, hf_cmee, tvb, offset, parameter_length, value);
1355 return true;
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_)
1363 proto_item *pitem;
1364 uint32_t value;
1366 if (!((role == ROLE_DTE && type == TYPE_ACTION))) {
1367 return false;
1370 if (parameter_number > 4) return false;
1372 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1374 switch (parameter_number) {
1375 case 0:
1376 pitem = proto_tree_add_uint(tree, hf_cmer_mode, tvb, offset, parameter_length, value);
1377 if (value > 3)
1378 expert_add_info(pinfo, pitem, &ei_cmer_mode);
1379 break;
1380 case 1:
1381 pitem = proto_tree_add_uint(tree, hf_cmer_keyp, tvb, offset, parameter_length, value);
1382 if (value > 2)
1383 expert_add_info(pinfo, pitem, &ei_cmer_keyp);
1384 break;
1385 case 2:
1386 pitem = proto_tree_add_uint(tree, hf_cmer_disp, tvb, offset, parameter_length, value);
1387 if (value > 2)
1388 expert_add_info(pinfo, pitem, &ei_cmer_disp);
1389 break;
1390 case 3:
1391 pitem = proto_tree_add_uint(tree, hf_cmer_ind, tvb, offset, parameter_length, value);
1392 if (value > 2)
1393 expert_add_info(pinfo, pitem, &ei_cmer_ind);
1394 break;
1395 case 4:
1396 pitem = proto_tree_add_uint(tree, hf_cmer_bfr, tvb, offset, parameter_length, value);
1397 if (value > 1)
1398 expert_add_info(pinfo, pitem, &ei_cmer_bfr);
1399 break;
1402 return true;
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_)
1411 proto_item *pitem;
1412 int hex_length;
1413 int bytes_count;
1414 int i;
1415 uint8_t *final_arr;
1416 tvbuff_t *final_tvb = NULL;
1418 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1419 return false;
1421 pitem = proto_tree_add_item(tree, hf_cmgl_msg_pdu, tvb, offset, data_part_length, ENC_NA | ENC_ASCII);
1423 hex_length = data_part_length;
1424 if (hex_length % 2 == 1) {
1425 expert_add_info(pinfo, pitem, &ei_odd_len);
1426 return true;
1428 if (hex_length < 1) {
1429 expert_add_info(pinfo, pitem, &ei_empty_hex);
1430 return true;
1432 bytes_count = hex_length / 2;
1433 final_arr = wmem_alloc0_array(pinfo->pool, uint8_t, bytes_count + 1);
1434 /* Try to parse the hex string into a byte array */
1435 uint8_t *pos = data_part_stream;
1436 pos += 16;
1437 for (i = 8; i < bytes_count; i++) {
1438 if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) {
1439 /* Either current or next char isn't a hex character */
1440 expert_add_info(pinfo, pitem, &ei_invalid_hex);
1441 return true;
1443 sscanf((char *)pos, "%2hhx", &(final_arr[i-8]));
1444 pos += 2;
1446 final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count);
1447 add_new_data_source(pinfo, final_tvb, "GSM SMS payload");
1449 /* Adjusting P2P direction as it is read by the SMS dissector */
1450 int at_dir = pinfo->p2p_dir;
1451 pinfo->p2p_dir = P2P_DIR_SENT;
1453 /* Call GSM SMS dissector*/
1454 call_dissector_only(gsm_sms_handle, final_tvb, pinfo, tree, NULL);
1456 /* Restoring P2P direction */
1457 pinfo->p2p_dir = at_dir;
1458 return true;
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_)
1466 uint32_t value = 0;
1467 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1468 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1469 return false;
1472 if (role == ROLE_DTE && type == TYPE_ACTION && parameter_number > 0)
1473 return false;
1474 else if (role == ROLE_DCE && parameter_number > 3)
1475 return false;
1477 if (role == ROLE_DTE && type == TYPE_ACTION) {
1478 proto_tree_add_item(tree, hf_cmgl_req_status, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1479 } else {
1480 switch (parameter_number) {
1481 case 0:
1482 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1483 proto_tree_add_uint(tree, hf_cmgl_msg_index, tvb, offset, parameter_length, value);
1484 break;
1485 case 1:
1486 proto_tree_add_item(tree, hf_cmgl_msg_status, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1487 break;
1488 case 2:
1489 proto_tree_add_item(tree, hf_cmgl_msg_originator_name, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1490 break;
1491 case 3:
1492 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1493 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 at_processed_cmd_t * at_cmd = get_current_role_last_command(at_info, role);
1497 if (!at_cmd)
1498 break;
1499 at_cmd->type = type;
1500 at_cmd->expected_data_parts = 1;
1501 at_cmd->consumed_data_parts = 0;
1502 at_cmd->dissect_data = dissect_cmgl_data_part;
1503 break;
1507 return true;
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_)
1516 proto_item *pitem;
1517 int hex_length;
1518 int bytes_count;
1519 int i;
1520 uint8_t *final_arr;
1521 tvbuff_t *final_tvb = NULL;
1523 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1524 return false;
1526 pitem = proto_tree_add_item(tree, hf_cmgr_msg_pdu, tvb, offset, data_part_length, ENC_NA | ENC_ASCII);
1528 hex_length = data_part_length;
1529 if (hex_length % 2 == 1) {
1530 expert_add_info(pinfo, pitem, &ei_odd_len);
1531 return true;
1533 if (hex_length < 1) {
1534 expert_add_info(pinfo, pitem, &ei_empty_hex);
1535 return true;
1537 bytes_count = hex_length / 2;
1538 final_arr = wmem_alloc0_array(pinfo->pool, uint8_t, bytes_count + 1);
1539 /* Try to parse the hex string into a byte array */
1540 uint8_t *pos = data_part_stream;
1541 pos += 16;
1542 for (i = 8; i < bytes_count; i++) {
1543 if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) {
1544 /* Either current or next char isn't a hex character */
1545 expert_add_info(pinfo, pitem, &ei_invalid_hex);
1546 return true;
1548 sscanf((char *)pos, "%2hhx", &(final_arr[i-8]));
1549 pos += 2;
1551 final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count);
1552 add_new_data_source(pinfo, final_tvb, "GSM SMS payload");
1554 /* Adjusting P2P direction as it is read by the SMS dissector */
1555 int at_dir = pinfo->p2p_dir;
1556 pinfo->p2p_dir = P2P_DIR_SENT;
1558 /* Call GSM SMS dissector*/
1559 call_dissector_only(gsm_sms_handle, final_tvb, pinfo, tree, NULL);
1561 /* Restoring P2P direction */
1562 pinfo->p2p_dir = at_dir;
1563 return true;
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_)
1571 uint32_t value = 0;
1572 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1573 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1574 return false;
1577 if (role == ROLE_DTE && parameter_number > 1)
1578 return false;
1579 else if (role == ROLE_DCE && parameter_number > 3)
1580 return false;
1582 if (role == ROLE_DTE) {
1583 switch (parameter_number) {
1584 case 0:
1585 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1586 proto_tree_add_uint(tree, hf_cmgr_msg_index, tvb, offset, parameter_length, value);
1587 break;
1588 case 1:
1589 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1590 proto_tree_add_uint(tree, hf_cmgr_mode, tvb, offset, parameter_length, value);
1591 break;
1593 } else {
1594 switch (parameter_number) {
1595 case 0:
1596 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1597 proto_tree_add_uint(tree, hf_cmgr_stat, tvb, offset, parameter_length, value);
1598 break;
1599 case 1:
1600 proto_tree_add_item(tree, hf_cmgr_address, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1601 break;
1602 case 2:
1603 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1604 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 at_processed_cmd_t * at_cmd = get_current_role_last_command(at_info, role);
1608 if (!at_cmd)
1609 break;
1610 at_cmd->type = type;
1611 at_cmd->expected_data_parts = 1;
1612 at_cmd->consumed_data_parts = 0;
1613 at_cmd->dissect_data = dissect_cmgr_data_part;
1614 break;
1618 return true;
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_)
1626 uint32_t value = 0;
1627 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1628 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1629 return false;
1632 if (parameter_number > 8) return false;
1634 /* Parameters are the same for both ACTION and RESPONSE */
1635 if (parameter_length != 0) {
1636 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1638 switch (parameter_number) {
1639 case 0:
1640 proto_tree_add_uint(tree, hf_cmux_transparency, tvb, offset, parameter_length, value);
1641 break;
1642 case 1:
1643 /* In the RESPONSE, the subset parameter might be missing */
1644 if (type == TYPE_ACTION || parameter_length != 0) {
1645 proto_tree_add_uint(tree, hf_cmux_subset, tvb, offset, parameter_length, value);
1647 break;
1648 case 2:
1649 proto_tree_add_item(tree, hf_cmux_port_speed, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1650 break;
1651 case 3:
1652 proto_tree_add_uint(tree, hf_cmux_n1, tvb, offset, parameter_length, value);
1653 break;
1654 case 4:
1655 proto_tree_add_uint(tree, hf_cmux_t1, tvb, offset, parameter_length, value);
1656 break;
1657 case 5:
1658 proto_tree_add_uint(tree, hf_cmux_n2, tvb, offset, parameter_length, value);
1659 break;
1660 case 6:
1661 proto_tree_add_uint(tree, hf_cmux_t2, tvb, offset, parameter_length, value);
1662 break;
1663 case 7:
1664 proto_tree_add_uint(tree, hf_cmux_t3, tvb, offset, parameter_length, value);
1665 break;
1666 case 8:
1667 proto_tree_add_uint(tree, hf_cmux_k, tvb, offset, parameter_length, value);
1668 break;
1671 return true;
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_)
1679 proto_item *pitem;
1680 uint32_t value;
1682 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return false;
1683 if (parameter_number > 5) return false;
1685 switch (parameter_number) {
1686 case 0:
1687 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1688 break;
1689 case 1:
1690 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1691 break;
1692 case 2:
1693 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1694 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1695 if (value < 128 || value > 175)
1696 expert_add_info(pinfo, pitem, &ei_at_type);
1697 break;
1698 case 3:
1699 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1700 proto_tree_add_uint(tree, hf_cnum_speed, tvb, offset, parameter_length, value);
1701 break;
1702 case 4:
1703 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1704 pitem = proto_tree_add_uint(tree, hf_cnum_service, tvb, offset, parameter_length, value);
1705 if (value > 5)
1706 expert_add_info(pinfo, pitem, &ei_cnum_service);
1707 break;
1708 case 5:
1709 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1710 pitem = proto_tree_add_uint(tree, hf_cnum_itc, tvb, offset, parameter_length, value);
1711 if (value > 1)
1712 expert_add_info(pinfo, pitem, &ei_cnum_itc);
1713 break;
1716 return true;
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_)
1724 uint32_t value;
1726 if (!((role == ROLE_DTE && (type == TYPE_ACTION || type == TYPE_READ)) ||
1727 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1728 return false;
1731 if (parameter_number > 3) return false;
1733 switch (parameter_number) {
1734 case 0:
1735 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1736 proto_tree_add_uint(tree, hf_cops_mode, tvb, offset, parameter_length, value);
1737 break;
1738 case 1:
1739 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1740 proto_tree_add_uint(tree, hf_cops_format, tvb, offset, parameter_length, value);
1741 break;
1742 case 2:
1743 proto_tree_add_item(tree, hf_cops_operator, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1744 break;
1745 case 3:
1746 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1747 proto_tree_add_uint(tree, hf_cops_act, tvb, offset, parameter_length, value);
1748 break;
1751 return true;
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_)
1759 proto_item *pitem;
1760 bool is_ready;
1761 char *pin_type;
1762 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1763 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1764 return false;
1767 if (type == TYPE_ACTION) {
1768 switch (parameter_number) {
1769 case 0:
1770 proto_tree_add_item(tree, hf_cpin_pin, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1771 break;
1772 case 1:
1773 proto_tree_add_item(tree, hf_cpin_newpin, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1774 break;
1775 default:
1776 return false;
1778 return true;
1781 /* type is TYPE_RESPONSE */
1782 if (parameter_number == 0) {
1783 pitem = proto_tree_add_item(tree, hf_cpin_code, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1784 is_ready = g_ascii_strncasecmp("READY", (char*)parameter_stream, parameter_length) == 0;
1785 if (is_ready) {
1786 proto_item_append_text(pitem, " (MT is not pending for any password)");
1788 else {
1789 pin_type = wmem_strndup(pinfo->pool, parameter_stream, parameter_length);
1790 proto_item_append_text(pitem, " (MT is waiting %s to be given)", pin_type);
1792 return true;
1794 return false;
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_)
1802 uint32_t value;
1803 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1804 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1805 return false;
1808 if (type == TYPE_ACTION) {
1809 switch (parameter_number) {
1810 case 0:
1811 proto_tree_add_item(tree, hf_cpms_mem1, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1812 break;
1813 case 1:
1814 proto_tree_add_item(tree, hf_cpms_mem2, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1815 break;
1816 case 2:
1817 proto_tree_add_item(tree, hf_cpms_mem3, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1818 break;
1819 default:
1820 return false;
1822 return true;
1824 else {
1825 // TODO: Assuming response is for ACTION command, need to support
1826 // responses for READ and QUERY
1827 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1828 switch (parameter_number) {
1829 case 0:
1830 proto_tree_add_uint(tree, hf_cpms_used1, tvb, offset, parameter_length, value);
1831 break;
1832 case 1:
1833 proto_tree_add_uint(tree, hf_cpms_total1, tvb, offset, parameter_length, value);
1834 break;
1835 case 2:
1836 proto_tree_add_uint(tree, hf_cpms_used2, tvb, offset, parameter_length, value);
1837 break;
1838 case 3:
1839 proto_tree_add_uint(tree, hf_cpms_total2, tvb, offset, parameter_length, value);
1840 break;
1841 case 4:
1842 proto_tree_add_uint(tree, hf_cpms_used3, tvb, offset, parameter_length, value);
1843 break;
1844 case 5:
1845 proto_tree_add_uint(tree, hf_cpms_total3, tvb, offset, parameter_length, value);
1846 break;
1847 default:
1848 return false;
1850 return true;
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_)
1859 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1860 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1861 return false;
1864 if (parameter_number > 0) {
1865 return false;
1868 /* For both ACTION and RESPONSE the first
1869 * and only parameter is the character set */
1870 proto_tree_add_item(tree, hf_cscs_chset, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1871 return true;
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)
1879 proto_item *pitem;
1880 uint32_t value;
1881 int hex_length;
1882 int bytes_count;
1883 int i;
1884 uint8_t *final_arr;
1885 tvbuff_t *final_tvb=NULL;
1887 if (!((role == ROLE_DTE && type == TYPE_ACTION) ||
1888 (role == ROLE_DCE && type == TYPE_RESPONSE))) {
1889 return false;
1892 if (parameter_number > 1) return true;
1894 switch (parameter_number) {
1895 case 0:
1896 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1897 proto_tree_add_uint(tree, hf_csim_length, tvb, offset, parameter_length, value);
1898 break;
1899 case 1:
1900 if(role == ROLE_DTE) {
1901 pitem = proto_tree_add_item(tree, hf_csim_command, tvb, offset,
1902 parameter_length, ENC_NA | ENC_ASCII);
1904 else {
1905 pitem = proto_tree_add_item(tree, hf_csim_response, tvb, offset,
1906 parameter_length, ENC_NA | ENC_ASCII);
1908 hex_length = (parameter_length - 2); /* ignoring leading and trailing quotes */
1909 if (hex_length % 2 == 1) {
1910 expert_add_info(pinfo, pitem, &ei_odd_len);
1911 return true;
1913 if(hex_length < 1) {
1914 expert_add_info(pinfo, pitem, &ei_empty_hex);
1915 return true;
1917 bytes_count = hex_length / 2;
1918 final_arr = wmem_alloc0_array(pinfo->pool,uint8_t,bytes_count);
1919 /* Try to parse the hex string into a byte array */
1920 uint8_t *pos = parameter_stream;
1921 pos++; /* skipping first quotes */
1922 for (i = 0; i < bytes_count; i++) {
1923 if (!g_ascii_isxdigit(*pos) || !g_ascii_isxdigit(*(pos + 1))) {
1924 /* Either current or next char isn't a hex character */
1925 expert_add_info(pinfo, pitem, &ei_invalid_hex);
1926 return true;
1928 sscanf((char *)pos, "%2hhx", &(final_arr[i]));
1929 pos += 2;
1931 final_tvb = tvb_new_child_real_data(tvb, final_arr, bytes_count, bytes_count);
1932 add_new_data_source(pinfo, final_tvb, "GSM SIM payload");
1933 /* Call GSM SIM dissector*/
1934 call_dissector_with_data(gsm_sim_handle, final_tvb, pinfo, tree, data);
1935 break;
1938 return true;
1941 static bool
1942 dissect_csq_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1943 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1944 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
1946 proto_item *pitem;
1947 uint32_t value;
1949 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) return false;
1951 if (parameter_number > 1) return false;
1953 switch (parameter_number) {
1954 case 0:
1955 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1956 pitem = proto_tree_add_uint(tree, hf_csq_rssi, tvb, offset, parameter_length, value);
1957 if (value > 31 && value != 99)
1958 expert_add_info(pinfo, pitem, &ei_csq_rssi);
1959 break;
1960 case 1:
1961 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
1962 pitem = proto_tree_add_uint(tree, hf_csq_ber, tvb, offset, parameter_length, value);
1963 if (value > 7 && value != 99)
1964 expert_add_info(pinfo, pitem, &ei_csq_ber);
1965 break;
1968 return true;
1971 static bool
1972 dissect_gmi_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1973 int offset, int role, uint16_t type, uint8_t *parameter_stream _U_,
1974 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
1976 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1977 return false;
1980 if (parameter_number > 1) return false;
1982 proto_tree_add_item(tree, hf_gmi_manufacturer_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1984 return true;
1987 static bool
1988 dissect_gmm_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1989 int offset, int role, uint16_t type, uint8_t *parameter_stream _U_,
1990 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
1992 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
1993 return false;
1996 if (parameter_number > 1) return false;
1998 proto_tree_add_item(tree, hf_gmm_model_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
2000 return true;
2003 static bool
2004 dissect_gmr_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
2005 int offset, int role, uint16_t type, uint8_t *parameter_stream _U_,
2006 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
2008 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
2009 return false;
2012 if (parameter_number > 1) return false;
2014 proto_tree_add_item(tree, hf_gmr_revision_id, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
2016 return true;
2019 static bool
2020 dissect_vts_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2021 int offset, int role, uint16_t type, uint8_t *parameter_stream,
2022 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
2024 proto_item *pitem;
2025 uint32_t value;
2027 if (!(role == ROLE_DTE && type == TYPE_ACTION)) return false;
2028 if (parameter_number > 1) return false;
2030 switch (parameter_number) {
2031 case 0:
2032 pitem = proto_tree_add_item(tree, hf_vts_dtmf, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
2033 if (parameter_length != 1)
2034 expert_add_info(pinfo, pitem, &ei_vts_dtmf);
2035 break;
2036 case 1:
2037 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
2038 proto_tree_add_uint(tree, hf_vts_duration, tvb, offset, parameter_length, value);
2039 break;
2042 return true;
2045 static bool
2046 dissect_zpas_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
2047 int offset, int role, uint16_t type, uint8_t *parameter_stream _U_,
2048 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
2050 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
2051 return false;
2054 if (parameter_number > 1) return false;
2056 switch(parameter_number)
2058 case 0:
2059 proto_tree_add_item(tree, hf_zpas_network, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
2060 break;
2061 case 1:
2062 proto_tree_add_item(tree, hf_zpas_srv_domain, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
2063 break;
2066 return true;
2069 static bool
2070 dissect_zusim_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
2071 int offset, int role, uint16_t type, uint8_t *parameter_stream,
2072 unsigned parameter_number, int parameter_length, at_packet_info_t *at_info _U_, void **data _U_)
2074 uint32_t value;
2076 if (!(role == ROLE_DCE && type == TYPE_RESPONSE)) {
2077 return false;
2080 if (parameter_number > 0) return false;
2082 value = get_uint_parameter(pinfo->pool, parameter_stream, parameter_length);
2083 proto_tree_add_uint(tree, hf_zusim_usim_card, tvb, offset, parameter_length, value);
2085 return true;
2088 static bool
2089 dissect_no_parameter(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_,
2090 int offset _U_, int role _U_, uint16_t type _U_, uint8_t *parameter_stream _U_,
2091 unsigned parameter_number _U_, int parameter_length _U_, at_packet_info_t *at_info _U_, void **data _U_)
2093 return false;
2096 /* TODO: Some commands need to save request command type (request with TYPE_READ vs TYPE_TEST, etc.)
2097 to properly dissect response parameters.
2098 Some commands can use TYPE_TEST respose to properly dissect parameters,
2099 for example: AT+CIND=?, AT+CIND? */
2100 static const at_cmd_t at_cmds[] = {
2101 { "+CCWA", "Call Waiting Notification", check_ccwa, dissect_ccwa_parameter },
2102 { "+CFUN", "Set Phone Functionality", check_cfun, dissect_cfun_parameter },
2103 { "+CGDCONT", "PDP context define", check_cgdcont, dissect_cgdcont_parameter },
2104 { "+CGMI", "Request manufacturer identification", check_cgmi, dissect_cgmi_parameter },
2105 { "+CGMM", "Request model identification", check_cgmm, dissect_cgmm_parameter },
2106 { "+CGMR", "Request revision identification", check_cgmr, dissect_cgmr_parameter },
2107 { "+CGSN", "Request Product Serial Number Identification (ESN/IMEI)", check_cgsn, dissect_no_parameter },
2108 { "+CHLD", "Call Hold and Multiparty Handling", check_chld, dissect_chld_parameter },
2109 { "+CHUP", "Call Hang-up", check_chup, dissect_no_parameter },
2110 { "+CIEV", "Indicator Events Reporting", check_ciev, dissect_ciev_parameter },
2111 { "+CIMI", "Request International Mobile Subscriber Identity (IMSI)", check_cimi, dissect_cimi_parameter },
2112 { "^CIMI", "Request International Mobile Subscriber Identity (IMSI)", check_cimi, dissect_cimi_parameter },
2113 { "+CIND", "Phone Indicators", check_cind, dissect_cind_parameter },
2114 { "+CLAC", "List All Available AT Commands", check_clac, dissect_no_parameter },
2115 { "+CLCC", "Current Calls", check_clcc, dissect_clcc_parameter },
2116 { "+CLIP", "Calling Line Identification Notification", check_clip, dissect_clip_parameter },
2117 { "+CME ERROR", "Mobile Termination Error Result Code", check_cme, dissect_cme_error_parameter },
2118 { "+CMEE", "Mobile Equipment Error", check_cmee, dissect_cmee_parameter },
2119 { "+CMER", "Event Reporting Activation/Deactivation", check_cmer, dissect_cmer_parameter },
2120 { "+CMGL", "List SMS messages", check_cmgl, dissect_cmgl_parameter },
2121 { "+CMGR", "Read SMS message", check_cmgr, dissect_cmgr_parameter },
2122 { "+CMUX", "Multiplexing mode", check_cmux, dissect_cmux_parameter },
2123 { "+CNUM", "Subscriber Number Information", check_cnum, dissect_cnum_parameter },
2124 { "+COPS", "Reading Network Operator", check_cops, dissect_cops_parameter },
2125 { "+CPIN", "Enter SIM PIN", check_cpin, dissect_cpin_parameter },
2126 { "+CPMS", "Preferred Message Storage", check_cpms, dissect_cpms_parameter },
2127 { "+CSCS", "Select TE Character Set", check_cscs, dissect_cscs_parameter },
2128 { "+CSIM", "Generic SIM access", check_csim, dissect_csim_parameter },
2129 { "+CSQ", "Signal Quality", check_csq, dissect_csq_parameter },
2130 { "+CSUPI", "Request 5G subscription permanent identifier", check_csupi, dissect_no_parameter },
2131 { "+GMI", "Request manufacturer identification", check_gmi, dissect_gmi_parameter },
2132 { "+GMM", "Request model identification", check_gmm, dissect_gmm_parameter },
2133 { "+GMR", "Request revision identification", check_gmr, dissect_gmr_parameter },
2134 { "+GSN", "Request Product Serial Number Identification (ESN/IMEI)", check_gsn, dissect_no_parameter },
2135 { "+VTS", "DTMF and tone generation", check_vts, dissect_vts_parameter },
2136 { "+ZPAS", "Check Card Status", check_zpas, dissect_zpas_parameter },
2137 { "+ZUSIM", "Check USIM Card Type", check_zusim, dissect_zusim_parameter },
2138 { "ERROR", "ERROR", check_only_dce_role, dissect_no_parameter },
2139 { "RING", "Incoming Call Indication", check_only_dce_role, dissect_no_parameter },
2140 { "OK", "OK", check_only_dce_role, dissect_no_parameter },
2141 { "D", "Dial", check_only_dte_role, NULL },
2142 { "A", "Call Answer", check_only_dte_role, dissect_no_parameter },
2143 { "E0", "Disable Echo", check_only_dte_role, dissect_no_parameter },
2144 { "E1", "Enable Echo", check_only_dte_role, dissect_no_parameter },
2145 { "I", "Product Identification Information", check_only_dte_role, dissect_no_parameter },
2146 { NULL, NULL, NULL, NULL }
2149 static int
2150 dissect_at_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2151 int offset, uint32_t role, int command_number, at_packet_info_t *at_info)
2153 proto_item *pitem;
2154 proto_tree *command_item = NULL;
2155 proto_item *command_tree = NULL;
2156 proto_tree *parameters_item = NULL;
2157 proto_item *parameters_tree = NULL;
2158 char *at_stream;
2159 char *at_command = NULL;
2160 char *name;
2161 int i_char = 0;
2162 unsigned i_char_fix = 0;
2163 int length;
2164 int leftover_length;
2165 const at_cmd_t *i_at_cmd;
2166 int parameter_length;
2167 unsigned parameter_number = 0;
2168 int first_parameter_offset = offset;
2169 int last_parameter_offset = offset;
2170 uint16_t type = TYPE_UNKNOWN;
2171 uint32_t brackets;
2172 bool quotation;
2173 bool next;
2174 void *data;
2175 at_processed_cmd_t *last_command;
2177 length = tvb_reported_length_remaining(tvb, offset);
2178 if (length <= 0)
2179 return tvb_reported_length(tvb);
2181 if (!command_number) {
2182 proto_tree_add_item(tree, hf_data, tvb, offset, length, ENC_NA | ENC_ASCII);
2185 at_stream = (uint8_t *) wmem_alloc(pinfo->pool, length + 1);
2186 tvb_memcpy(tvb, at_stream, offset, length);
2187 at_stream[length] = '\0';
2189 while (at_stream[i_char]) {
2190 at_stream[i_char] = g_ascii_toupper(at_stream[i_char]);
2191 i_char += 1;
2194 if (role == ROLE_DTE) {
2195 if (command_number) {
2196 at_command = at_stream;
2197 i_char = 0;
2198 } else {
2199 at_command = g_strstr_len(at_stream, length, "AT");
2200 if (at_command) {
2201 command_item = proto_tree_add_none_format(tree, hf_command, tvb,
2202 offset, 0, "Command %u", command_number);
2203 command_tree = proto_item_add_subtree(command_item, ett_at_command);
2205 i_char = (unsigned) (at_command - at_stream);
2206 if (i_char) {
2207 proto_tree_add_item(command_tree, hf_at_ignored, tvb, offset,
2208 i_char, ENC_NA | ENC_ASCII);
2209 offset += i_char;
2212 proto_tree_add_item(command_tree, hf_at_command_line_prefix,
2213 tvb, offset, 2, ENC_NA | ENC_ASCII);
2214 offset += 2;
2215 i_char += 2;
2216 at_command = at_stream;
2217 at_command += i_char;
2218 length -= i_char;
2219 i_char_fix += i_char;
2220 i_char = 0;
2223 } else {
2224 command_item = proto_tree_add_none_format(tree, hf_command, tvb,
2225 offset, 0, "Command %u", command_number);
2226 command_tree = proto_item_add_subtree(command_item, ett_at_command);
2228 at_command = at_stream;
2229 i_char = 0;
2230 while (i_char <= length &&
2231 (at_command[i_char] == '\r' || at_command[i_char] == '\n' ||
2232 at_command[i_char] == ' ' || at_command[i_char] == '\t')) {
2233 /* ignore white characters */
2234 i_char += 1;
2237 offset += i_char;
2238 at_command += i_char;
2239 length -= i_char;
2240 i_char_fix += i_char;
2241 i_char = 0;
2244 if (at_command) {
2246 while (i_char < length &&
2247 (at_command[i_char] != '\r' && at_command[i_char] != '=' &&
2248 at_command[i_char] != ';' && at_command[i_char] != '?' &&
2249 at_command[i_char] != ':')) {
2250 i_char += 1;
2253 i_at_cmd = at_cmds;
2254 if (at_command[0] == '\r') {
2255 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset - 2,
2256 2, ENC_NA | ENC_ASCII);
2257 i_at_cmd = NULL;
2258 } else {
2259 pitem = NULL;
2260 while (i_at_cmd->name) {
2261 if (g_str_has_prefix(&at_command[0], i_at_cmd->name)) {
2262 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
2263 (int) strlen(i_at_cmd->name), ENC_NA | ENC_ASCII);
2264 proto_item_append_text(pitem, " (%s)", i_at_cmd->long_name);
2265 break;
2267 i_at_cmd += 1;
2270 if (!pitem) {
2271 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
2272 i_char, ENC_NA | ENC_ASCII);
2276 name = format_text(pinfo->pool, at_command, i_char + 1);
2278 if (i_at_cmd && i_at_cmd->name == NULL) {
2279 proto_item_append_text(command_item, ": %s (Unknown)", name);
2280 proto_item_append_text(pitem, " (Unknown)");
2281 expert_add_info(pinfo, pitem, &ei_unknown_command);
2282 } else if (i_at_cmd == NULL) {
2283 proto_item_append_text(command_item, ": AT");
2284 } else {
2285 proto_item_append_text(command_item, ": %s", i_at_cmd->name);
2288 offset += i_char;
2290 leftover_length = length - i_char;
2291 if (i_at_cmd && g_strcmp0(i_at_cmd->name, "D")) {
2292 if (leftover_length >= 2 && at_command[i_char] == '=' && at_command[i_char + 1] == '?') {
2293 type = at_command[i_char] << 8 | at_command[i_char + 1];
2294 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
2295 offset += 2;
2296 i_char += 2;
2297 } else if (role == ROLE_DCE && leftover_length >= 2 && at_command[i_char] == '\r' && at_command[i_char + 1] == '\n') {
2298 type = at_command[i_char] << 8 | at_command[i_char + 1];
2299 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
2300 offset += 2;
2301 i_char += 2;
2302 } else if (leftover_length >= 1 && (at_command[i_char] == '=' ||
2303 at_command[i_char] == '\r' ||
2304 at_command[i_char] == ':' ||
2305 at_command[i_char] == '?')) {
2306 type = at_command[i_char];
2307 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 1, type);
2308 offset += 1;
2309 i_char += 1;
2311 else if (leftover_length == 0) {
2312 /* No suffix, assume line break (which translates to 'ACTION_SIMPLY') */
2313 type = TYPE_ACTION_SIMPLY;
2314 pitem = proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 0, type);
2315 proto_item_set_generated(pitem);
2319 /* Setting new command's info in the Last Command field */
2320 last_command = get_current_role_last_command(at_info, role);
2321 if (last_command) {
2322 g_strlcpy(last_command->name, name, STORE_COMMAND_MAX_LEN);
2323 last_command->type = type;
2324 last_command->expected_data_parts = 0;
2325 last_command->consumed_data_parts = 0;
2328 if (i_at_cmd && i_at_cmd->check_command && !i_at_cmd->check_command(role, type)) {
2329 expert_add_info(pinfo, command_item, &ei_invalid_usage);
2332 parameters_item = proto_tree_add_none_format(command_tree, hf_parameters, tvb,
2333 offset, 0, "Parameters");
2334 parameters_tree = proto_item_add_subtree(parameters_item, ett_at_parameters);
2335 first_parameter_offset = offset;
2337 data = NULL;
2339 while (i_char < length) {
2341 while (at_command[i_char] == ' ' || at_command[i_char] == '\t') {
2342 offset += 1;
2343 i_char += 1;
2346 parameter_length = 0;
2347 brackets = 0;
2348 quotation = false;
2349 next = false;
2351 if (at_command[i_char + parameter_length] != '\r') {
2352 while (i_char + parameter_length < length &&
2353 at_command[i_char + parameter_length] != '\r') {
2355 if (at_command[i_char + parameter_length] == ';') {
2356 next = true;
2357 break;
2360 if (at_command[i_char + parameter_length] == '"') {
2361 quotation = quotation ? false : true;
2364 if (quotation == true) {
2365 parameter_length += 1;
2366 continue;
2369 if (at_command[i_char + parameter_length] == '(') {
2370 brackets += 1;
2372 if (at_command[i_char + parameter_length] == ')') {
2373 brackets -= 1;
2376 if (brackets == 0 && at_command[i_char + parameter_length] == ',') {
2377 break;
2380 parameter_length += 1;
2383 if (type == TYPE_ACTION || type == TYPE_RESPONSE) {
2384 if (i_at_cmd && (i_at_cmd->dissect_parameter != NULL &&
2385 !i_at_cmd->dissect_parameter(tvb, pinfo, parameters_tree, offset, role,
2386 type, &at_command[i_char], parameter_number, parameter_length, at_info, &data) )) {
2387 pitem = proto_tree_add_item(parameters_tree,
2388 hf_unknown_parameter, tvb, offset,
2389 parameter_length, ENC_NA | ENC_ASCII);
2390 expert_add_info(pinfo, pitem, &ei_unknown_parameter);
2391 } else if (i_at_cmd && i_at_cmd->dissect_parameter == NULL) {
2392 proto_tree_add_item(parameters_tree, hf_parameter, tvb, offset,
2393 parameter_length, ENC_NA | ENC_ASCII);
2398 if (type != TYPE_ACTION_SIMPLY && type != TYPE_RESPONSE_ACK && type != TYPE_TEST && type != TYPE_READ)
2399 parameter_number += 1;
2400 i_char += parameter_length;
2401 offset += parameter_length;
2402 last_parameter_offset = offset;
2404 if (role == ROLE_DCE &&
2405 i_char + 1 <= length &&
2406 at_command[i_char] == '\r' &&
2407 at_command[i_char + 1] == '\n') {
2408 offset += 2;
2409 i_char += 2;
2410 break;
2411 } else if (at_command[i_char] == ',' ||
2412 at_command[i_char] == '\r' ||
2413 at_command[i_char] == ';') {
2414 i_char += 1;
2415 offset += 1;
2418 if (next) break;
2421 i_char += i_char_fix;
2422 proto_item_set_len(command_item, i_char);
2423 } else {
2424 length = tvb_reported_length_remaining(tvb, offset);
2425 if (length < 0)
2426 length = 0;
2427 offset += length;
2430 if (parameter_number > 0 && last_parameter_offset - first_parameter_offset > 0)
2431 proto_item_set_len(parameters_item, last_parameter_offset - first_parameter_offset);
2432 else
2433 proto_item_append_text(parameters_item, ": No");
2435 return offset;
2438 static int
2439 dissect_at_command_continuation(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2440 int offset, uint32_t role, int command_number, at_packet_info_t *at_info)
2442 at_processed_cmd_t *cmd;
2443 proto_item *data_part_item;
2444 proto_item *data_part_tree;
2445 proto_item *pitem;
2446 char *data_stream;
2447 int data_part_index;
2448 int length;
2449 int data_part_length = 0;
2451 cmd = get_current_role_last_command(at_info, role);
2452 if (!cmd)
2453 return offset;
2454 data_part_index = cmd->consumed_data_parts;
2456 length = tvb_reported_length_remaining(tvb, offset);
2457 if (length <= 0)
2458 return tvb_reported_length(tvb);
2460 data_stream = (uint8_t *) wmem_alloc(pinfo->pool, length + 1);
2461 tvb_memcpy(tvb, data_stream, offset, length);
2462 data_stream[length] = '\0';
2464 while (data_part_length < length && data_stream[data_part_length] != '\r') {
2465 data_part_length += 1;
2468 data_part_item = proto_tree_add_none_format(tree, hf_data_part, tvb,
2469 offset, data_part_length, "Command %u's Data Part %u", command_number, data_part_index);
2470 data_part_tree = proto_item_add_subtree(data_part_item, ett_at_data_part);
2472 if (cmd && (cmd->dissect_data != NULL &&
2473 !cmd->dissect_data(tvb, pinfo, data_part_tree, offset, role, cmd->type,
2474 data_stream, data_part_index, data_part_length,
2475 at_info) )) {
2476 pitem = proto_tree_add_item(data_part_tree, hf_unknown_parameter, tvb, offset,
2477 data_part_length, ENC_NA | ENC_ASCII);
2478 expert_add_info(pinfo, pitem, &ei_unknown_parameter);
2480 offset += data_part_length;
2481 return offset;
2484 /* The dissector itself */
2485 static int dissect_at(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2487 proto_item *item;
2488 proto_tree *at_tree;
2489 char *string;
2490 uint32_t role = ROLE_UNKNOWN;
2491 int offset;
2492 int len;
2493 uint32_t cmd_indx;
2494 conversation_t *conversation;
2495 at_conv_info_t *at_conv;
2496 at_packet_info_t *at_info;
2497 at_processed_cmd_t *last_command;
2499 string = tvb_format_text_wsp(pinfo->pool, tvb, 0, tvb_captured_length(tvb));
2500 col_append_sep_str(pinfo->cinfo, COL_PROTOCOL, "/", "AT");
2501 switch (pinfo->p2p_dir) {
2502 case P2P_DIR_SENT:
2503 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Sent ");
2504 break;
2505 case P2P_DIR_RECV:
2506 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Rcvd ");
2507 break;
2508 default:
2509 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "UnknownDirection ");
2510 break;
2512 col_append_fstr(pinfo->cinfo, COL_INFO, "AT Command: %s", string);
2514 /* Check if user forces roles using preferences */
2515 if ((at_role == ROLE_DCE && pinfo->p2p_dir == P2P_DIR_SENT) ||
2516 (at_role == ROLE_DTE && pinfo->p2p_dir == P2P_DIR_RECV)) {
2517 role = ROLE_DCE;
2518 } else if (at_role != ROLE_UNKNOWN) {
2519 role = ROLE_DTE;
2522 /* If no roles are forced, assume SENT from PC and RECV from device */
2523 if (role == ROLE_UNKNOWN) {
2524 if (pinfo->p2p_dir == P2P_DIR_SENT) {
2525 role = ROLE_DTE;
2526 } else {
2527 role = ROLE_DCE;
2531 /* Start with a top-level item to add everything else to */
2532 item = proto_tree_add_item(tree, proto_at, tvb, 0, -1, ENC_NA);
2533 proto_item_append_text(item, ": %s", string);
2534 at_tree = proto_item_add_subtree(item, ett_at);
2536 /* Show role in tree */
2537 item = proto_tree_add_uint(at_tree, hf_role, tvb, 0, 0, role);
2538 proto_item_set_generated(item);
2541 /* Dissect command(s) */
2542 len = tvb_captured_length(tvb);
2543 offset = 0;
2544 cmd_indx = 0;
2546 conversation = find_conversation(pinfo->num,
2547 &pinfo->src, &pinfo->dst,
2548 conversation_pt_to_conversation_type(pinfo->ptype),
2549 pinfo->srcport, pinfo->destport, 0);
2550 at_conv = get_at_conv_info(conversation);
2551 at_info = get_at_packet_info(pinfo, at_conv);
2553 while(offset < len) {
2554 last_command = get_current_role_last_command(at_info, role);
2555 if (last_command && last_command->expected_data_parts > last_command->consumed_data_parts) {
2556 // Continuing a previous command
2557 offset = dissect_at_command_continuation(tvb, pinfo, at_tree, offset, role, last_command->cmd_indx, at_info);
2558 last_command->consumed_data_parts++;
2560 else {
2561 // New Command
2562 offset = dissect_at_command(tvb, pinfo, at_tree, offset, role, cmd_indx, at_info);
2563 /* Only if the command is expecting data parts save its index */
2564 last_command = get_current_role_last_command(at_info, role);
2565 if (last_command && last_command->expected_data_parts > last_command->consumed_data_parts) {
2566 last_command->cmd_indx = cmd_indx;
2568 cmd_indx++;
2571 set_at_packet_info(pinfo, at_conv, at_info);
2572 return tvb_captured_length(tvb);
2575 static int allowed_chars_len(tvbuff_t *tvb, int captured_len)
2577 int offset;
2578 uint8_t val;
2580 /* Get the amount of characters within the TVB which are ASCII,
2581 * cartridge return or new line */
2582 for (offset = 0; offset < captured_len; offset++) {
2583 val = tvb_get_uint8(tvb, offset);
2584 if (!(g_ascii_isprint(val) || (val == 0x0a) || (val == 0x0d)))
2585 return offset;
2587 return captured_len;
2589 static bool is_padded(tvbuff_t *tvb, int captured_len, int first_pad_offset)
2591 int offset;
2592 uint8_t val;
2594 /* Check if the rest of the packet is 0x00 padding
2595 * and no other values*/
2596 for (offset = first_pad_offset; offset < captured_len; offset++) {
2597 val = tvb_get_uint8(tvb, offset);
2598 if (val != 0x00)
2599 return false;
2601 return true;
2604 #define MIN_PADDED_ALLOWED_CHARS 4
2605 /* Experimental approach based upon the one used for PPP */
2606 static bool heur_dissect_at(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2608 static const uint8_t at_magic1[2] = {0x0d, 0x0a};
2609 static const uint8_t at_magic2[3] = {0x0d, 0x0d, 0x0a};
2610 static const uint8_t at_magic3[2] = {0x41, 0x54}; /* 'A' 'T' */
2611 int len, allwd_chars_len;
2612 tvbuff_t *tvb_no_padding;
2614 if ((tvb_memeql(tvb, 0, at_magic1, sizeof(at_magic1)) == 0) ||
2615 (tvb_memeql(tvb, 0, at_magic2, sizeof(at_magic2)) == 0) ||
2616 (tvb_memeql(tvb, 0, at_magic3, sizeof(at_magic3)) == 0)){
2617 len = tvb_captured_length(tvb);
2618 allwd_chars_len = allowed_chars_len(tvb,len);
2619 if(allwd_chars_len < len && allwd_chars_len > MIN_PADDED_ALLOWED_CHARS) {
2620 /* Found some valid characters, check if rest is padding */
2621 if(is_padded(tvb,len,allwd_chars_len)) {
2622 /* This is a padded AT Command */
2623 tvb_no_padding = tvb_new_subset_length(tvb, 0, allwd_chars_len);
2624 dissect_at(tvb_no_padding, pinfo, tree, data);
2625 return true;
2628 else if(allwd_chars_len == len) {
2629 /* This is an (unpadded) AT Command */
2630 dissect_at(tvb, pinfo, tree, data);
2631 return true;
2634 return false;
2637 void
2638 proto_register_at_command(void)
2640 module_t *module;
2641 expert_module_t *expert_at;
2643 static hf_register_info hf[] = {
2644 { &hf_command,
2645 { "Command", "at.command",
2646 FT_NONE, BASE_NONE, NULL, 0,
2647 NULL, HFILL}
2649 { &hf_data_part,
2650 { "Data Part", "at.data_part",
2651 FT_NONE, BASE_NONE, NULL, 0,
2652 NULL, HFILL}
2654 { &hf_parameters,
2655 { "Parameters", "at.parameters",
2656 FT_NONE, BASE_NONE, NULL, 0,
2657 NULL, HFILL}
2659 { &hf_data,
2660 { "AT Stream", "at.data",
2661 FT_STRING, BASE_NONE, NULL, 0,
2662 NULL, HFILL}
2664 { &hf_at_ignored,
2665 { "Ignored", "at.ignored",
2666 FT_BYTES, BASE_NONE, NULL, 0,
2667 NULL, HFILL}
2669 { &hf_at_cmd,
2670 { "Command", "at.cmd",
2671 FT_STRING, BASE_NONE, NULL, 0,
2672 NULL, HFILL}
2674 { &hf_at_cmd_type,
2675 { "Type", "at.cmd.type",
2676 FT_UINT16, BASE_HEX, VALS(at_cmd_type_vals), 0,
2677 NULL, HFILL}
2679 { &hf_at_command_line_prefix,
2680 { "Command Line Prefix", "at.command_line_prefix",
2681 FT_STRING, BASE_NONE, NULL, 0,
2682 NULL, HFILL}
2684 { &hf_parameter,
2685 { "Parameter", "at.parameter",
2686 FT_STRING, BASE_NONE, NULL, 0,
2687 NULL, HFILL}
2689 { &hf_unknown_parameter,
2690 { "Unknown Parameter", "at.unknown_parameter",
2691 FT_STRING, BASE_NONE, NULL, 0,
2692 NULL, HFILL}
2694 { &hf_role,
2695 { "Role", "at.role",
2696 FT_UINT8, BASE_DEC, VALS(role_vals), 0,
2697 NULL, HFILL}
2699 { &hf_cmer_mode,
2700 { "Mode", "at.cmer.mode",
2701 FT_UINT8, BASE_DEC, NULL, 0,
2702 NULL, HFILL}
2704 { &hf_cmer_keyp,
2705 { "Keypad", "at.cmer.keyp",
2706 FT_UINT8, BASE_DEC, NULL, 0,
2707 NULL, HFILL}
2709 { &hf_cmer_disp,
2710 { "Display", "at.cmer.disp",
2711 FT_UINT8, BASE_DEC, NULL, 0,
2712 NULL, HFILL}
2714 { &hf_cmer_ind,
2715 { "Indicator", "at.cmer.ind",
2716 FT_UINT8, BASE_DEC, NULL, 0,
2717 NULL, HFILL}
2719 { &hf_cmer_bfr,
2720 { "Buffer", "at.cmer.bfr",
2721 FT_UINT8, BASE_DEC, NULL, 0,
2722 NULL, HFILL}
2724 { &hf_cme_error,
2725 { "CME Error (Numeric)", "at.cme_error",
2726 FT_UINT8, BASE_DEC, VALS(cme_error_vals), 0,
2727 NULL, HFILL}
2729 { &hf_cme_error_verbose,
2730 { "CME Error (Verbose)", "at.cme_error_verbose",
2731 FT_STRING, BASE_NONE, NULL, 0,
2732 NULL, HFILL}
2734 { &hf_cmee,
2735 { "Mode", "at.cmee",
2736 FT_UINT8, BASE_DEC, VALS(cmee_vals), 0,
2737 NULL, HFILL}
2739 { &hf_cmgl_req_status,
2740 { "Requested Status", "at.cmgl.req_status",
2741 FT_STRING, BASE_NONE, NULL, 0,
2742 "Status of the requested messages to list",
2743 HFILL}
2745 { &hf_cmgl_msg_index,
2746 { "Index", "at.cmgl.msg_index",
2747 FT_UINT16, BASE_DEC, NULL, 0,
2748 "Index of the message",
2749 HFILL}
2751 { &hf_cmgl_msg_status,
2752 { "Status", "at.cmgl.msg_status",
2753 FT_STRING, BASE_NONE, NULL, 0,
2754 "Status of the message",
2755 HFILL}
2757 { &hf_cmgl_msg_originator_name,
2758 { "Originator Name", "at.cmgl.originator_name",
2759 FT_STRING, BASE_NONE, NULL, 0,
2760 "Originator name as saved in the phonebook",
2761 HFILL}
2763 { &hf_cmgl_msg_length,
2764 { "Length", "at.cmgl.pdu_length",
2765 FT_UINT16, BASE_DEC, NULL, 0,
2766 "PDU Length",
2767 HFILL}
2769 { &hf_cmgl_msg_pdu,
2770 { "SMS PDU", "at.cmgl.pdu",
2771 FT_STRING, BASE_NONE, NULL, 0,
2772 NULL, HFILL}
2774 { &hf_cmgr_address,
2775 { "Address", "at.cmgr.address",
2776 FT_STRING, BASE_NONE, NULL, 0,
2777 NULL, HFILL}
2779 { &hf_cmgr_mode,
2780 { "Mode", "at.cmgr.mode",
2781 FT_UINT16, BASE_DEC, VALS(cmgr_mode_vals), 0,
2782 "Reading mode",
2783 HFILL}
2785 { &hf_cmgr_msg_index,
2786 { "Index", "at.cmgr.msg_index",
2787 FT_UINT16, BASE_DEC, NULL, 0,
2788 "Index of the message",
2789 HFILL}
2791 { &hf_cmgr_msg_length,
2792 { "Length", "at.cmgr.pdu_length",
2793 FT_UINT16, BASE_DEC, NULL, 0,
2794 "PDU Length",
2795 HFILL}
2797 { &hf_cmgr_msg_pdu,
2798 { "SMS PDU", "at.cmgr.pdu",
2799 FT_STRING, BASE_NONE, NULL, 0,
2800 NULL, HFILL}
2802 { &hf_cmgr_stat,
2803 { "Status", "at.cmgr.status",
2804 FT_UINT32, BASE_DEC, VALS(cmgr_stat_vals), 0,
2805 "Status of the returned message",
2806 HFILL}
2808 { &hf_cmux_k,
2809 { "Window Size", "at.k",
2810 FT_UINT8, BASE_DEC, NULL, 0,
2811 "Window Size for Advanced option with Error-Recovery Mode",
2812 HFILL}
2814 { &hf_cmux_n1,
2815 { "Maximum Frame Size", "at.n1",
2816 FT_UINT16, BASE_DEC, NULL, 0,
2817 NULL, HFILL}
2819 { &hf_cmux_n2,
2820 { "Maximum Number of Re-transmissions", "at.n2",
2821 FT_UINT8, BASE_DEC, NULL, 0,
2822 NULL, HFILL}
2824 { &hf_cmux_port_speed,
2825 { "Transmission Rate", "at.port_speed",
2826 FT_UINT8, BASE_DEC, VALS(cmux_port_speed_vals), 0,
2827 NULL,
2828 HFILL}
2830 { &hf_cmux_subset,
2831 { "Subset", "at.subset",
2832 FT_UINT8, BASE_DEC, VALS(cmux_subset_vals), 0,
2833 NULL,
2834 HFILL}
2836 { &hf_cmux_t1,
2837 { "Acknowledgement Timer", "at.t1",
2838 FT_UINT8, BASE_DEC, NULL, 0,
2839 "Acknowledgement timer in units of ten milliseconds",
2840 HFILL}
2842 { &hf_cmux_t2,
2843 { "Response Timer", "at.t2",
2844 FT_UINT8, BASE_DEC, NULL, 0,
2845 "Response timer for the multiplexer control channel in units of ten milliseconds",
2846 HFILL}
2848 { &hf_cmux_t3,
2849 { "Wake Up Response Timer", "at.t3",
2850 FT_UINT8, BASE_DEC, NULL, 0,
2851 "Wake up response timer in seconds",
2852 HFILL}
2854 { &hf_cmux_transparency,
2855 { "Transparency Mechanism", "at.transparency",
2856 FT_UINT8, BASE_DEC, VALS(cmux_transparency_vals), 0,
2857 NULL,
2858 HFILL}
2860 { &hf_chld_mode,
2861 { "Mode", "at.chld.mode_value",
2862 FT_UINT8, BASE_DEC, VALS(chld_vals), 0,
2863 NULL, HFILL}
2865 { &hf_chld_mode_1x,
2866 { "Mode: Releases specified active call only", "at.chld.mode",
2867 FT_STRING, BASE_NONE, NULL, 0,
2868 NULL, HFILL}
2870 { &hf_chld_mode_2x,
2871 { "Mode: Request private consultation mode with specified call - place all calls on hold EXCEPT the call indicated by x", "at.chld.mode",
2872 FT_STRING, BASE_NONE, NULL, 0,
2873 NULL, HFILL}
2875 { &hf_chld_supported_modes,
2876 { "Supported Modes", "at.chld.supported_modes",
2877 FT_STRING, BASE_NONE, NULL, 0,
2878 NULL, HFILL}
2880 { &hf_cimi_imsi,
2881 { "IMSI", "at.cimi.imsi",
2882 FT_STRING, BASE_NONE, NULL, 0,
2883 NULL, HFILL}
2885 { &hf_ciev_indicator_index,
2886 { "Indicator Index", "at.ciev.indicator_index",
2887 FT_UINT8, BASE_DEC, NULL, 0,
2888 NULL, HFILL}
2890 { &hf_vts_dtmf,
2891 { "DTMF", "at.vts.dtmf",
2892 FT_STRING, BASE_NONE, NULL, 0,
2893 NULL, HFILL}
2895 { &hf_vts_duration,
2896 { "Duration", "at.vts.duration",
2897 FT_UINT32, BASE_DEC, NULL, 0,
2898 NULL, HFILL}
2900 { &hf_cops_mode,
2901 { "Mode", "at.cops.mode",
2902 FT_UINT8, BASE_DEC, VALS(cops_mode_vals), 0,
2903 NULL, HFILL}
2905 { &hf_cops_format,
2906 { "Format", "at.cops.format",
2907 FT_UINT8, BASE_DEC, VALS(cops_format_vals), 0,
2908 NULL, HFILL}
2910 { &hf_cops_operator,
2911 { "Operator", "at.cops.operator",
2912 FT_STRING, BASE_NONE, NULL, 0,
2913 NULL, HFILL}
2915 { &hf_cops_act,
2916 { "AcT", "at.cops.act",
2917 FT_UINT8, BASE_DEC, VALS(cops_act_vals), 0,
2918 NULL, HFILL}
2920 { &hf_cpin_code,
2921 { "Code", "at.cpin.code",
2922 FT_STRING, BASE_NONE, NULL, 0,
2923 NULL, HFILL}
2925 { &hf_cpin_pin,
2926 { "PIN", "at.cpin.pin",
2927 FT_STRING, BASE_NONE, NULL, 0,
2928 NULL, HFILL}
2930 { &hf_cpin_newpin,
2931 { "New PIN", "at.cpin.newpin",
2932 FT_STRING, BASE_NONE, NULL, 0,
2933 NULL, HFILL}
2935 { &hf_cpms_mem1,
2936 { "Read Memory Storage", "at.cpms.mem1",
2937 FT_STRING, BASE_NONE, NULL, 0,
2938 "Memory from which SMS messages are read and deleted",
2939 HFILL}
2941 { &hf_cpms_mem2,
2942 { "Write Memory Storage", "at.cpms.mem2",
2943 FT_STRING, BASE_NONE, NULL, 0,
2944 "Memory to which writing and sending operations are made",
2945 HFILL}
2947 { &hf_cpms_mem3,
2948 { "Receive Memory Storage", "at.cpms.mem3",
2949 FT_STRING, BASE_NONE, NULL, 0,
2950 "Memory to which received SMS is preferred to be stored",
2951 HFILL}
2953 { &hf_cpms_total1,
2954 { "Read Storage Capacity", "at.cpms.total1",
2955 FT_UINT32, BASE_DEC, NULL, 0,
2956 "Total number of messages that the read/delete memory storage can contain",
2957 HFILL}
2959 { &hf_cpms_total2,
2960 { "Write Storage Capacity", "at.cpms.total2",
2961 FT_UINT32, BASE_DEC, NULL, 0,
2962 "Total number of messages that the write/send memory storage can contain",
2963 HFILL}
2965 { &hf_cpms_total3,
2966 { "Receive Storage Capacity", "at.cpms.total3",
2967 FT_UINT32, BASE_DEC, NULL, 0,
2968 "Total number of messages that the receive memory storage can contain",
2969 HFILL}
2971 { &hf_cpms_used1,
2972 { "Read Storage Messages Count", "at.cpms.used1",
2973 FT_UINT32, BASE_DEC, NULL, 0,
2974 "Amount of messages in the read/delete memory storage",
2975 HFILL}
2977 { &hf_cpms_used2,
2978 { "Write Storage Messages Count", "at.cpms.used2",
2979 FT_UINT32, BASE_DEC, NULL, 0,
2980 "Amount of messages in the write/send memory storage",
2981 HFILL}
2983 { &hf_cpms_used3,
2984 { "Receive Storage Messages Count", "at.cpms.used3",
2985 FT_UINT32, BASE_DEC, NULL, 0,
2986 "Amount of messages in the receive memory storage",
2987 HFILL}
2989 { &hf_cscs_chset,
2990 { "Character Set", "at.cscs.chset",
2991 FT_STRING, BASE_NONE, NULL, 0,
2992 NULL, HFILL}
2994 { &hf_csim_command,
2995 { "Command", "at.csim.command",
2996 FT_STRING, BASE_NONE, NULL, 0,
2997 NULL, HFILL}
2999 { &hf_csim_length,
3000 { "Length", "at.csim.length",
3001 FT_UINT32, BASE_DEC, NULL, 0,
3002 NULL, HFILL}
3004 { &hf_csim_response,
3005 { "Response", "at.csim.response",
3006 FT_STRING, BASE_NONE, NULL, 0,
3007 NULL, HFILL}
3009 { &hf_csq_ber,
3010 { "BER", "at.csq.ber",
3011 FT_UINT8, BASE_DEC, VALS(csq_ber_vals), 0,
3012 "Bit Error Rate",
3013 HFILL}
3015 { &hf_csq_rssi,
3016 { "RSSI", "at.csq.rssi",
3017 FT_UINT8, BASE_DEC, VALS(csq_rssi_vals), 0,
3018 "Received Signal Strength Indication",
3019 HFILL}
3021 { &hf_clip_mode,
3022 { "Mode", "at.clip.mode",
3023 FT_UINT8, BASE_DEC, VALS(clip_mode_vals), 0,
3024 NULL, HFILL}
3026 { &hf_clip_status,
3027 { "Status", "at.clip.status",
3028 FT_UINT8, BASE_DEC, VALS(clip_status_vals), 0,
3029 NULL, HFILL}
3031 { &hf_at_number,
3032 { "Number", "at.number",
3033 FT_STRING, BASE_NONE, NULL, 0,
3034 NULL, HFILL}
3036 { &hf_at_type,
3037 { "Type", "at.type",
3038 FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(at_type_vals), 0,
3039 NULL, HFILL}
3041 { &hf_at_subaddress,
3042 { "Subaddress", "at.subaddress",
3043 FT_STRING, BASE_NONE, NULL, 0,
3044 NULL, HFILL}
3046 { &hf_at_subaddress_type,
3047 { "Subaddress Type", "at.subaddress_type",
3048 FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(at_type_vals), 0,
3049 NULL, HFILL}
3051 { &hf_cnum_speed,
3052 { "Speed", "at.cnum.speed",
3053 FT_UINT8, BASE_DEC | BASE_EXT_STRING, &csd_data_rate_vals_ext, 0,
3054 NULL, HFILL}
3056 { &hf_cnum_service,
3057 { "Service", "at.cnum.service",
3058 FT_UINT8, BASE_DEC, VALS(cnum_service_vals), 0,
3059 NULL, HFILL}
3061 { &hf_cnum_itc,
3062 { "Information Transfer Capability", "at.cnum.itc",
3063 FT_UINT8, BASE_DEC, VALS(cnum_itc_vals), 0,
3064 NULL, HFILL}
3066 { &hf_at_alpha,
3067 { "Alpha", "at.alpha",
3068 FT_STRING, BASE_NONE, NULL, 0,
3069 NULL, HFILL}
3071 { &hf_at_cli_validity,
3072 { "CLI Validity", "at.cli_validity",
3073 FT_UINT8, BASE_DEC, VALS(cli_validity_vals), 0,
3074 NULL, HFILL}
3076 { &hf_at_priority,
3077 { "Priority", "at.priority",
3078 FT_UINT8, BASE_DEC, NULL, 0,
3079 NULL, HFILL}
3081 { &hf_clcc_id,
3082 { "ID", "at.clcc.id",
3083 FT_UINT32, BASE_DEC, NULL, 0,
3084 NULL, HFILL}
3086 { &hf_clcc_dir,
3087 { "Direction", "at.clcc.dir",
3088 FT_UINT32, BASE_DEC, VALS(clcc_dir_vals), 0,
3089 NULL, HFILL}
3091 { &hf_clcc_stat,
3092 { "State", "at.clcc.stat",
3093 FT_UINT32, BASE_DEC, VALS(clcc_stat_vals), 0,
3094 NULL, HFILL}
3096 { &hf_clcc_mode,
3097 { "Mode", "at.clcc.mode",
3098 FT_UINT32, BASE_DEC, VALS(clcc_mode_vals), 0,
3099 NULL, HFILL}
3101 { &hf_clcc_mpty,
3102 { "Mpty", "at.clcc.mpty",
3103 FT_UINT32, BASE_DEC, VALS(clcc_mpty_vals), 0,
3104 NULL, HFILL}
3106 { &hf_ccwa_show_result_code,
3107 { "Show Result Code Presentation Status", "at.ccwa.presentation_status",
3108 FT_UINT32, BASE_DEC, VALS(ccwa_show_result_code_vals), 0,
3109 NULL, HFILL}
3111 { &hf_ccwa_mode,
3112 { "Mode", "at.ccwa.mode",
3113 FT_UINT32, BASE_DEC, VALS(ccwa_mode_vals), 0,
3114 NULL, HFILL}
3116 { &hf_ccwa_class,
3117 { "Class", "at.ccwa.class",
3118 FT_UINT32, BASE_DEC, VALS(ccwa_class_vals), 0,
3119 NULL, HFILL}
3121 { &hf_cfun_fun,
3122 { "Functionality", "at.cfun.fun",
3123 FT_UINT8, BASE_DEC, VALS(cfun_fun_vals), 0,
3124 NULL, HFILL}
3126 { &hf_cfun_rst,
3127 { "Reset", "at.cfun.rst",
3128 FT_UINT8, BASE_DEC, VALS(cfun_rst_vals), 0,
3129 NULL, HFILL}
3131 { &hf_cgdcont_cid,
3132 { "CID", "at.cgdcont.cid",
3133 FT_UINT32, BASE_DEC, NULL, 0,
3134 NULL, HFILL}
3136 { &hf_cgdcont_pdp_type,
3137 { "PDP type", "at.cgdcont.pdp_type",
3138 FT_STRING, BASE_NONE, NULL, 0,
3139 NULL, HFILL}
3141 { &hf_cgdcont_apn,
3142 { "APN", "at.cgdcont.apn",
3143 FT_STRING, BASE_NONE, NULL, 0,
3144 "Access Point Name", HFILL}
3146 { &hf_cgdcont_pdp_addr,
3147 { "PDP address", "at.cgdcont.pdp_addr",
3148 FT_STRING, BASE_NONE, NULL, 0,
3149 NULL, HFILL}
3151 { &hf_cgdcont_d_comp,
3152 { "Data compression", "at.cgdcont.d_comp",
3153 FT_UINT32, BASE_DEC, NULL, 0,
3154 NULL, HFILL}
3156 { &hf_cgdcont_h_comp,
3157 { "Header compression", "at.cgdcont.h_comp",
3158 FT_UINT32, BASE_DEC, NULL, 0,
3159 NULL, HFILL}
3161 { &hf_cgmi_manufacturer_id,
3162 { "Manufacturer Identification", "at.cgmi.manufacturer_id",
3163 FT_STRING, BASE_NONE, NULL, 0,
3164 NULL, HFILL}
3166 { &hf_cgmm_model_id,
3167 { "Model Identification", "at.cgmm.model_id",
3168 FT_STRING, BASE_NONE, NULL, 0,
3169 NULL, HFILL}
3171 { &hf_cgmr_revision_id,
3172 { "Revision Identification", "at.cgmr.revision_id",
3173 FT_STRING, BASE_NONE, NULL, 0,
3174 NULL, HFILL}
3176 { &hf_gmi_manufacturer_id,
3177 { "Manufacturer Identification", "at.gmi.manufacturer_id",
3178 FT_STRING, BASE_NONE, NULL, 0,
3179 NULL, HFILL}
3181 { &hf_gmm_model_id,
3182 { "Model Identification", "at.gmm.model_id",
3183 FT_STRING, BASE_NONE, NULL, 0,
3184 NULL, HFILL}
3186 { &hf_gmr_revision_id,
3187 { "Revision Identification", "at.gmr.revision_id",
3188 FT_STRING, BASE_NONE, NULL, 0,
3189 NULL, HFILL}
3191 { &hf_zpas_network,
3192 { "Network type", "at.zpas.network",
3193 FT_STRING, BASE_NONE, NULL, 0,
3194 NULL, HFILL}
3196 { &hf_zpas_srv_domain,
3197 { "Service domain", "at.zpas.srv_domain",
3198 FT_STRING, BASE_NONE, NULL, 0,
3199 NULL, HFILL}
3201 { &hf_zusim_usim_card,
3202 { "USIM card type", "at.zusim.usim_card",
3203 FT_UINT8, BASE_DEC, VALS(zusim_usim_card_vals), 0,
3204 "The type of the current (U)SIM card",
3205 HFILL}
3207 { &hf_indicator[0],
3208 { "Indicator 1", "at.indicator.1",
3209 FT_STRING, BASE_NONE, NULL, 0,
3210 NULL, HFILL}
3212 { &hf_indicator[1],
3213 { "Indicator 2", "at.indicator.2",
3214 FT_STRING, BASE_NONE, NULL, 0,
3215 NULL, HFILL}
3217 { &hf_indicator[2],
3218 { "Indicator 3", "at.indicator.3",
3219 FT_STRING, BASE_NONE, NULL, 0,
3220 NULL, HFILL}
3222 { &hf_indicator[3],
3223 { "Indicator 4", "at.indicator.4",
3224 FT_STRING, BASE_NONE, NULL, 0,
3225 NULL, HFILL}
3227 { &hf_indicator[4],
3228 { "Indicator 5", "at.indicator.5",
3229 FT_STRING, BASE_NONE, NULL, 0,
3230 NULL, HFILL}
3232 { &hf_indicator[5],
3233 { "Indicator 6", "at.indicator.6",
3234 FT_STRING, BASE_NONE, NULL, 0,
3235 NULL, HFILL}
3237 { &hf_indicator[6],
3238 { "Indicator 7", "at.indicator.7",
3239 FT_STRING, BASE_NONE, NULL, 0,
3240 NULL, HFILL}
3242 { &hf_indicator[7],
3243 { "Indicator 8", "at.indicator.8",
3244 FT_STRING, BASE_NONE, NULL, 0,
3245 NULL, HFILL}
3247 { &hf_indicator[8],
3248 { "Indicator 9", "at.indicator.9",
3249 FT_STRING, BASE_NONE, NULL, 0,
3250 NULL, HFILL}
3252 { &hf_indicator[9],
3253 { "Indicator 10", "at.indicator.10",
3254 FT_STRING, BASE_NONE, NULL, 0,
3255 NULL, HFILL}
3257 { &hf_indicator[10],
3258 { "Indicator 11", "at.indicator.11",
3259 FT_STRING, BASE_NONE, NULL, 0,
3260 NULL, HFILL}
3262 { &hf_indicator[11],
3263 { "Indicator 12", "at.indicator.12",
3264 FT_STRING, BASE_NONE, NULL, 0,
3265 NULL, HFILL}
3267 { &hf_indicator[12],
3268 { "Indicator 13", "at.indicator.13",
3269 FT_STRING, BASE_NONE, NULL, 0,
3270 NULL, HFILL}
3272 { &hf_indicator[13],
3273 { "Indicator 14", "at.indicator.14",
3274 FT_STRING, BASE_NONE, NULL, 0,
3275 NULL, HFILL}
3277 { &hf_indicator[14],
3278 { "Indicator 15", "at.indicator.15",
3279 FT_STRING, BASE_NONE, NULL, 0,
3280 NULL, HFILL}
3282 { &hf_indicator[15],
3283 { "Indicator 16", "at.indicator.16",
3284 FT_STRING, BASE_NONE, NULL, 0,
3285 NULL, HFILL}
3287 { &hf_indicator[16],
3288 { "Indicator 17", "at.indicator.17",
3289 FT_STRING, BASE_NONE, NULL, 0,
3290 NULL, HFILL}
3292 { &hf_indicator[17],
3293 { "Indicator 18", "at.indicator.18",
3294 FT_STRING, BASE_NONE, NULL, 0,
3295 NULL, HFILL}
3297 { &hf_indicator[18],
3298 { "Indicator 19", "at.indicator.19",
3299 FT_STRING, BASE_NONE, NULL, 0,
3300 NULL, HFILL}
3302 { &hf_indicator[19],
3303 { "Indicator 20", "at.indicator.20",
3304 FT_STRING, BASE_NONE, NULL, 0,
3305 NULL, HFILL}
3309 static ei_register_info ei[] = {
3310 { &ei_unknown_command, { "at.expert.unknown_command", PI_PROTOCOL, PI_NOTE, "Unknown or Non-standard AT command", EXPFILL }},
3311 { &ei_invalid_usage, { "at.expert.invalid_usage", PI_PROTOCOL, PI_WARN, "Non mandatory type or command in this role", EXPFILL }},
3312 { &ei_unknown_parameter, { "at.expert.unknown_parameter", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }},
3313 { &ei_cmer_mode, { "at.expert.cmer.mode", PI_PROTOCOL, PI_WARN, "Only 0-3 are valid", EXPFILL }},
3314 { &ei_cmer_keyp, { "at.expert.cmer.keyp", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }},
3315 { &ei_cmer_disp, { "at.expert.cmer.disp", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }},
3316 { &ei_cmer_ind, { "at.expert.cmer.ind", PI_PROTOCOL, PI_WARN, "Only 0-2 are valid", EXPFILL }},
3317 { &ei_cmer_bfr, { "at.expert.cmer.bfr", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }},
3318 { &ei_chld_mode, { "at.expert.chld.mode", PI_PROTOCOL, PI_WARN, "Invalid value", EXPFILL }},
3319 { &ei_ciev_indicator, { "at.expert.ciev.indicator", PI_PROTOCOL, PI_WARN, "Unknown indicator", EXPFILL }},
3320 { &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 }},
3321 { &ei_cfun_range_fun, { "at.expert.cfun.invalid_fun", PI_PROTOCOL, PI_WARN, "Only 0-127 are valid", EXPFILL }},
3322 { &ei_cfun_rst, { "at.expert.cfun.rst", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }},
3323 { &ei_vts_dtmf, { "at.expert.vts.dtmf", PI_PROTOCOL, PI_WARN, "DTMF should be single character", EXPFILL }},
3324 { &ei_at_type, { "at.expert.at.type", PI_PROTOCOL, PI_WARN, "Unknown type value", EXPFILL }},
3325 { &ei_cnum_service, { "at.expert.cnum.service", PI_PROTOCOL, PI_WARN, "Only 0-5 are valid", EXPFILL }},
3326 { &ei_cnum_itc, { "at.expert.cnum.itc", PI_PROTOCOL, PI_WARN, "Only 0-1 are valid", EXPFILL }},
3327 { &ei_empty_hex, { "at.expert.csim.empty_hex", PI_PROTOCOL, PI_WARN, "Hex string is empty", EXPFILL }},
3328 { &ei_invalid_hex, { "at.expert.csim.invalid_hex", PI_PROTOCOL, PI_WARN, "Non hex character found in hex string", EXPFILL }},
3329 { &ei_odd_len, { "at.expert.csim.odd_len", PI_PROTOCOL, PI_WARN, "Odd hex string length", EXPFILL }},
3330 { &ei_csq_ber, { "at.expert.csq.ber", PI_PROTOCOL, PI_WARN, "Only 0-7 and 99 are valid", EXPFILL }},
3331 { &ei_csq_rssi, { "at.expert.csq.rssi", PI_PROTOCOL, PI_WARN, "Only 0-31 and 99 are valid", EXPFILL }},
3334 static int *ett[] = {
3335 &ett_at,
3336 &ett_at_command,
3337 &ett_at_data_part,
3338 &ett_at_parameters,
3341 proto_at = proto_register_protocol("AT Command", "AT", "at");
3342 proto_register_field_array(proto_at, hf, array_length(hf));
3343 proto_register_subtree_array(ett, array_length(ett));
3345 expert_at = expert_register_protocol(proto_at);
3346 expert_register_field_array(expert_at, ei, array_length(ei));
3348 module = prefs_register_protocol(proto_at, NULL);
3349 prefs_register_enum_preference(module, "role",
3350 "Force treat packets as DTE (PC) or DCE (Modem) role",
3351 "Force treat packets as DTE (PC) or DCE (Modem) role",
3352 &at_role, pref_at_role, true);
3354 register_dissector("at", dissect_at, proto_at);
3357 /* Handler registration */
3358 void
3359 proto_reg_handoff_at_command(void)
3361 gsm_sim_handle = find_dissector_add_dependency("gsm_sim.part", proto_at);
3362 gsm_sms_handle = find_dissector_add_dependency("gsm_sms", proto_at);
3364 heur_dissector_add("usb.bulk", heur_dissect_at, "AT Command USB bulk endpoint", "at_usb_bulk", proto_at, HEURISTIC_ENABLE);
3365 heur_dissector_add("usb.control", heur_dissect_at, "AT Command USB control endpoint", "at_usb_control", proto_at, HEURISTIC_ENABLE);
3369 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3371 * Local variables:
3372 * c-basic-offset: 4
3373 * tab-width: 8
3374 * indent-tabs-mode: nil
3375 * End:
3377 * vi: set shiftwidth=4 tabstop=8 expandtab:
3378 * :indentSize=4:tabSize=8:noTabs=true: