Coverage Report

Created: 2026-01-02 06:13

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