1 /******************************************************************************
2  *
3  *  Copyright 2004-2012 Broadcom Corporation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 /******************************************************************************
20  *
21  *  BTA AG AT command interpreter.
22  *
23  ******************************************************************************/
24 #define LOG_TAG "bta_ag_at"
25 
26 #include "bta/ag/bta_ag_at.h"
27 
28 #include <bluetooth/log.h>
29 #include <com_android_bluetooth_flags.h>
30 
31 #include <cstdint>
32 #include <cstdlib>
33 
34 #include "bta/ag/bta_ag_int.h"
35 #include "bta/include/utl.h"
36 #include "internal_include/bt_target.h"
37 #include "os/log.h"
38 #include "osi/include/allocator.h"
39 
40 using namespace bluetooth;
41 
42 /*****************************************************************************
43  *  Constants
44  ****************************************************************************/
45 
46 /******************************************************************************
47  *
48  * Function         bta_ag_at_init
49  *
50  * Description      Initialize the AT command parser control block.
51  *
52  *
53  * Returns          void
54  *
55  *****************************************************************************/
bta_ag_at_init(tBTA_AG_AT_CB * p_cb)56 void bta_ag_at_init(tBTA_AG_AT_CB* p_cb) {
57   p_cb->p_cmd_buf = nullptr;
58   p_cb->cmd_pos = 0;
59 }
60 
61 /******************************************************************************
62  *
63  * Function         bta_ag_at_reinit
64  *
65  * Description      Re-initialize the AT command parser control block.  This
66  *                  function resets the AT command parser state and frees
67  *                  any GKI buffer.
68  *
69  *
70  * Returns          void
71  *
72  *****************************************************************************/
bta_ag_at_reinit(tBTA_AG_AT_CB * p_cb)73 void bta_ag_at_reinit(tBTA_AG_AT_CB* p_cb) {
74   osi_free_and_reset((void**)&p_cb->p_cmd_buf);
75   p_cb->cmd_pos = 0;
76 }
77 
78 /******************************************************************************
79  *
80  * Function         bta_ag_process_at
81  *
82  * Description      Parse AT commands.  This function will take the input
83  *                  character string and parse it for AT commands according to
84  *                  the AT command table passed in the control block.
85  *
86  *
87  * Returns          void
88  *
89  *****************************************************************************/
bta_ag_process_at(tBTA_AG_AT_CB * p_cb,char * p_end)90 void bta_ag_process_at(tBTA_AG_AT_CB* p_cb, char* p_end) {
91   uint16_t idx;
92   uint8_t arg_type;
93   char* p_arg;
94   int16_t int_arg = 0;
95   /* loop through at command table looking for match */
96   for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) {
97     if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) {
98       break;
99     }
100   }
101 
102   /* if there is a match; verify argument type */
103   if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) {
104     /* start of argument is p + strlen matching command */
105     p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
106     if (p_arg > p_end) {
107       (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
108       return;
109     }
110 
111     /* if no argument */
112     if (p_arg[0] == 0) {
113       arg_type = BTA_AG_AT_NONE;
114     }
115     /* else if arg is '?' and it is last character */
116     else if (p_arg[0] == '?' && p_arg[1] == 0) {
117       /* we have a read */
118       arg_type = BTA_AG_AT_READ;
119     }
120     /* else if arg is '=' */
121     else if (p_arg[0] == '=' && p_arg[1] != 0) {
122       if (p_arg[1] == '?' && p_arg[2] == 0) {
123         /* we have a test */
124         arg_type = BTA_AG_AT_TEST;
125       } else {
126         /* we have a set */
127         arg_type = BTA_AG_AT_SET;
128 
129         /* skip past '=' */
130         p_arg++;
131       }
132     } else
133     /* else it is freeform argument */
134     {
135       arg_type = BTA_AG_AT_FREE;
136     }
137 
138     /* if arguments match command capabilities */
139     if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) {
140       /* if it's a set integer check max, min range */
141       if (arg_type == BTA_AG_AT_SET &&
142           p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) {
143         if (com::android::bluetooth::flags::bta_ag_cmd_brsf_allow_uint32()) {
144           if (p_cb->p_at_tbl[idx].command_id == BTA_AG_LOCAL_EVT_BRSF) {
145             // Per HFP v1.9 BRSF could be 32-bit integer and we should ignore
146             // all reserved bits rather than responding ERROR.
147             long long int_arg_ll = std::atoll(p_arg);
148             if (int_arg_ll >= (1ll << 32) || int_arg_ll < 0) int_arg_ll = -1;
149 
150             // Ignore reserved bits. 0xfff because there are 12 defined bits.
151             if (int_arg_ll > 0 && (int_arg_ll & (~0xfffll))) {
152               log::warn("BRSF: reserved bit is set: 0x{:x}", int_arg_ll);
153               int_arg_ll &= 0xfffll;
154             }
155 
156             int_arg = static_cast<int16_t>(int_arg_ll);
157           } else {
158             int_arg = utl_str2int(p_arg);
159           }
160         } else {
161           int_arg = utl_str2int(p_arg);
162         }
163         if (int_arg < (int16_t)p_cb->p_at_tbl[idx].min ||
164             int_arg > (int16_t)p_cb->p_at_tbl[idx].max) {
165           /* arg out of range; error */
166           log::warn("arg out of range");
167           (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
168         } else {
169           (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
170                                p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
171                                p_end, int_arg);
172         }
173       } else {
174         (*p_cb->p_cmd_cback)((tBTA_AG_SCB*)p_cb->p_user,
175                              p_cb->p_at_tbl[idx].command_id, arg_type, p_arg,
176                              p_end, int_arg);
177       }
178     } else {
179       /* else error */
180       log::warn("Incoming arg type 0x{:x} does not match cmd arg type 0x{:x}",
181                 arg_type, p_cb->p_at_tbl[idx].arg_type);
182       (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, false, nullptr);
183     }
184   } else {
185     /* else no match call error callback */
186     log::warn("Unmatched command index {}", idx);
187     (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
188   }
189 }
190 
191 /******************************************************************************
192  *
193  * Function         bta_ag_at_parse
194  *
195  * Description      Parse AT commands.  This function will take the input
196  *                  character string and parse it for AT commands according to
197  *                  the AT command table passed in the control block.
198  *
199  *
200  * Returns          void
201  *
202  *****************************************************************************/
bta_ag_at_parse(tBTA_AG_AT_CB * p_cb,char * p_buf,uint16_t len)203 void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len) {
204   int i = 0;
205   char* p_save;
206 
207   if (p_cb->p_cmd_buf == nullptr) {
208     p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len);
209     p_cb->cmd_pos = 0;
210   }
211 
212   for (i = 0; i < len;) {
213     while (p_cb->cmd_pos < p_cb->cmd_max_len - 1 && i < len) {
214       /* Skip null characters between AT commands. */
215       if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
216         i++;
217         continue;
218       }
219 
220       p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
221       if (p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' ||
222           p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
223         p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
224         if ((p_cb->cmd_pos > 2) &&
225             (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
226             (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
227           p_save = p_cb->p_cmd_buf;
228           char* p_end = p_cb->p_cmd_buf + p_cb->cmd_pos;
229           p_cb->p_cmd_buf += 2;
230           bta_ag_process_at(p_cb, p_end);
231           p_cb->p_cmd_buf = p_save;
232         }
233 
234         p_cb->cmd_pos = 0;
235 
236       } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A ||
237                  p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
238         p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
239         (*p_cb->p_err_cback)((tBTA_AG_SCB*)p_cb->p_user, true, p_cb->p_cmd_buf);
240         p_cb->cmd_pos = 0;
241       } else {
242         ++p_cb->cmd_pos;
243       }
244     }
245 
246     if (i < len) p_cb->cmd_pos = 0;
247   }
248 }
249