blob: 6ca5d65a3b9c5efd7547c44b3a3f66e579fccaaf [file] [log] [blame]
b.liu87afc4c2024-08-14 17:33:45 +08001#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <errno.h>
5#include <sys/socket.h>
6#include <sys/un.h>
7#include <netinet/in.h>
8#include <pthread.h>
9#include <sys/epoll.h>
10#include <fcntl.h>
11#include <signal.h>
12#include <cutils/properties.h>
13#include <arpa/inet.h>
14
15#include "mbtk_type.h"
16#include "mbtk_ril.h"
17#include "atchannel.h"
18#include "at_tok.h"
19#include "mbtk_utils.h"
20#include "ril_info.h"
21#include "mbtk_str.h"
22
b.liub4772072024-08-15 14:47:03 +080023mbtk_cell_pack_info_t cell_info;
b.liubcf86c92024-08-19 19:48:28 +080024ril_cgact_wait_t cgact_wait;
b.liub4772072024-08-15 14:47:03 +080025
b.liu87afc4c2024-08-14 17:33:45 +080026extern ril_band_info_t band_info;
27void ril_rsp_pack_send(int fd, int ril_id, int msg_index, const void* data, int data_len);
b.liubcf86c92024-08-19 19:48:28 +080028static int req_apn_get(bool get_def_cid, mbtk_apn_info_array_t *apns, int *cme_err);
b.liu87afc4c2024-08-14 17:33:45 +080029static int req_apn_set(mbtk_apn_info_t *apn, int *cme_err);
b.liu10a34102024-08-20 20:36:24 +080030static void apn_prop_get(mbtk_apn_info_array_t *apns);
31
32static int apn_file_save(const char *file, char *data, int data_len)
33{
34 if(!file) {
35 return -1;
36 }
37
38 if(str_empty(data) || data_len <= 0) { // Delete file
39 return unlink(file);
40 } else {
41 int fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0644);
42 if(fd < 0) {
43 LOGE("open(%s) fail:%d", file, errno);
44 return -1;
45 }
46
47 if(write(fd, data, data_len) != data_len) {
48 LOGE("write fail:%d", errno);
49 close(fd);
50 return -1;
51 }
52 close(fd);
53 return 0;
54 }
55}
56
57static int apn_file_read(const char *file, char *data, int data_len)
58{
59 if(!file) {
60 LOGE("file is null");
61 return -1;
62 }
63
64 if(data == NULL || data_len <= 100) {
65 LOGE("apn_file_read() arg error.");
66 return -1;
67 } else {
68 int len = -1;
69 int fd = open(file, O_RDONLY, 0644);
70 if(fd < 0) {
71 LOGE("open(%s) fail:%d", file, errno);
72 return -1;
73 }
74
75 memset(data, 0, data_len);
76 if((len = read(fd, data, data_len)) < 0) {
77 LOGE("read fail:%d", errno);
78 close(fd);
79 return -1;
80 }
81 close(fd);
82 return len;
83 }
84}
85
b.liu87afc4c2024-08-14 17:33:45 +080086
87void apn_auto_conf_from_prop()
88{
b.liu10a34102024-08-20 20:36:24 +080089 mbtk_apn_info_array_t apns;
b.liu87afc4c2024-08-14 17:33:45 +080090 int i = 0;
b.liu10a34102024-08-20 20:36:24 +080091 memset(&apns, 0, sizeof(mbtk_apn_info_array_t));
b.liu87afc4c2024-08-14 17:33:45 +080092 apn_prop_get(&apns);
93 while(i < apns.num) {
94 int cme_err = MBTK_RIL_ERR_CME_NON;
95 if(req_apn_set(&(apns.apns[i]), &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
96 {
97 LOGD("Set APN fail.");
98 }
99 else
100 {
101 LOGD("Set APN - %d success.", apns.apns[i].cid);
102 }
103 i++;
104 }
105}
106
107static bool apn_conf_support(mbtk_ril_cid_enum cid)
108{
109 if(cid == MBTK_RIL_CID_DEF) {
110 /*
111 uci show wan_default.default.enable
112 wan_default.default.enable='1'
113
114 uci get wan_default.default.enable
115 1
116 */
117 char buff[128] = {0};
118 if(mbtk_cmd_line("uci get wan_default.default.enable", buff, sizeof(buff)) && strlen(buff) > 0) {
119 return buff[0] == '1' ? FALSE : TRUE;
120 }
121 }
122 return TRUE;
123}
124
b.liubcf86c92024-08-19 19:48:28 +0800125static int apn_check_and_cid_reset(mbtk_apn_info_t *apn)
b.liu87afc4c2024-08-14 17:33:45 +0800126{
127 // Delete apn
128 if(str_empty(apn->apn)) {
129 if(apn->cid == MBTK_RIL_CID_NUL)
130 return -1;
131
132 if(!apn_conf_support(MBTK_RIL_CID_DEF) && apn->cid == MBTK_RIL_CID_DEF)
133 return -1;
134
b.liubcf86c92024-08-19 19:48:28 +0800135 // The cid no use,so can not delete.
b.liu87afc4c2024-08-14 17:33:45 +0800136 mbtk_apn_info_array_t apns;
137 int cme_err = MBTK_RIL_ERR_CME_NON;
138 memset(&apns, 0, sizeof(mbtk_apn_info_array_t));
b.liubcf86c92024-08-19 19:48:28 +0800139 if(req_apn_get(FALSE, &apns, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
b.liu87afc4c2024-08-14 17:33:45 +0800140 {
141 LOGW("Get APN fail.");
142 return 0;
143 }
144 else
145 {
146 int index = 0;
147 while(index < apns.num) {
148 if(apns.apns[index].cid == apn->cid)
149 return 0;
150 index++;
151 }
152 return -1;
153 }
b.liubcf86c92024-08-19 19:48:28 +0800154 } else { // Add or change APN.
155 int start_cid;
156 bool asr_auto_call_open = !apn_conf_support(MBTK_RIL_CID_DEF);
157 mbtk_apn_info_array_t apns;
158 int cme_err = MBTK_RIL_ERR_CME_NON;
159
160 if(asr_auto_call_open) {
161 start_cid = MBTK_RIL_CID_2;
162 } else {
163 start_cid = MBTK_APN_CID_MIN;
164 }
165 memset(&apns, 0, sizeof(mbtk_apn_info_array_t));
166 if(req_apn_get(TRUE, &apns, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
167 {
168 LOGW("Get APN fail.");
169 if(apn->cid == MBTK_RIL_CID_NUL) {
b.liu87afc4c2024-08-14 17:33:45 +0800170 apn->cid = start_cid;
171 }
b.liubcf86c92024-08-19 19:48:28 +0800172 }
173 else
174 {
175 int index = 0;
176 bool is_change = FALSE; // Is add APN default.
177
178 if(apn->cid == MBTK_RIL_CID_NUL) { // Is add (auto set cid).
b.liu87afc4c2024-08-14 17:33:45 +0800179 for(; start_cid <= MBTK_APN_CID_MAX; start_cid++) {
b.liubcf86c92024-08-19 19:48:28 +0800180 index = 0;
b.liu87afc4c2024-08-14 17:33:45 +0800181 while(index < apns.num) {
182 if(apns.apns[index].cid == start_cid)
183 break;
184 index++;
185 }
186
187 if(index == apns.num) { // Found not used cid : start_cid.
188 LOGD("Change CID : %d -> %d", apn->cid, start_cid);
189 apn->cid = start_cid;
b.liubcf86c92024-08-19 19:48:28 +0800190 // return 0;
191 break;
b.liu87afc4c2024-08-14 17:33:45 +0800192 }
193 }
194
195 if(start_cid > MBTK_APN_CID_MAX) {
196 LOGE("APN full.");
197 return -1;
198 }
b.liubcf86c92024-08-19 19:48:28 +0800199 is_change = FALSE;
200 } else {
201 index = 0;
202 while(index < apns.num) {
203 if(apns.apns[index].cid == apn->cid) {
204 is_change = TRUE;
205 break;
206 }
207 index++;
208 }
209 }
210
211 // Is add,the APN can't same.
212 if(!is_change) {
213 index = 0;
214 while(index < apns.num) {
215 if(strcmp(apns.apns[index].apn,apn->apn) == 0) {
216 LOGW("APN : %s exist.", apn->apn);
217 return -1;
218 }
219 index++;
220 }
b.liu87afc4c2024-08-14 17:33:45 +0800221 }
222 }
223 }
224 return 0;
225}
226
b.liu10a34102024-08-20 20:36:24 +0800227static void apn_prop_get(mbtk_apn_info_array_t *apns)
b.liu87afc4c2024-08-14 17:33:45 +0800228{
b.liu10a34102024-08-20 20:36:24 +0800229 char prop_name[128] = {0};
230 char prop_data[1024] = {0};
b.liu87afc4c2024-08-14 17:33:45 +0800231 int cid;
b.liu10a34102024-08-20 20:36:24 +0800232 memset(apns, 0, sizeof(mbtk_apn_info_array_t));
b.liu87afc4c2024-08-14 17:33:45 +0800233 bool asr_auto_call_open = !apn_conf_support(MBTK_RIL_CID_DEF);
234
235 // If auto data call is open,the default route is CID 1.
236 if(asr_auto_call_open) {
b.liu10a34102024-08-20 20:36:24 +0800237 //apns->cid_for_def_route = MBTK_RIL_CID_DEF;
238 //apns->cid_for_def_dns = MBTK_RIL_CID_DEF;
b.liu87afc4c2024-08-14 17:33:45 +0800239 cid = MBTK_RIL_CID_2;
240 } else {
b.liu87afc4c2024-08-14 17:33:45 +0800241 cid = MBTK_APN_CID_MIN;
242 }
b.liu10a34102024-08-20 20:36:24 +0800243
244 char def_cid[10] = {0};
245 sprintf(def_cid, "%d", MBTK_RIL_CID_DEF);
246 if(property_get(MBTK_DEF_ROUTE_CID, prop_data, def_cid) > 0 && !str_empty(prop_data)) {
247 apns->cid_for_def_route = (mbtk_ril_cid_enum)atoi(prop_data);
248 }
249 memset(prop_data, 0, sizeof(prop_data));
250 if(property_get(MBTK_DEF_DNS_CID, prop_data, def_cid) > 0 && !str_empty(prop_data)) {
251 apns->cid_for_def_dns = (mbtk_ril_cid_enum)atoi(prop_data);
252 }
253
b.liu87afc4c2024-08-14 17:33:45 +0800254 for(; cid <= MBTK_APN_CID_MAX; cid++) {
b.liu10a34102024-08-20 20:36:24 +0800255 memset(prop_name, 0, sizeof(prop_name));
256 memset(prop_data, 0, sizeof(prop_data));
b.liu87afc4c2024-08-14 17:33:45 +0800257
258 sprintf(prop_name, "%s_%d",MBTK_APN_PROP,cid);
259 // ip_type,auth,auto_data_call,apn,user,pass
b.liu10a34102024-08-20 20:36:24 +0800260#if 0
b.liu87afc4c2024-08-14 17:33:45 +0800261 if(property_get(prop_name, prop_data, "") > 0 && !str_empty(prop_data)) {
b.liu10a34102024-08-20 20:36:24 +0800262#else
263 if(apn_file_read(prop_name, prop_data, sizeof(prop_data)) > 0 && !str_empty(prop_data)) {
264#endif
b.liu87afc4c2024-08-14 17:33:45 +0800265 apns->apns[apns->num].cid = (mbtk_ril_cid_enum)cid;
266 char *ptr_1 = prop_data;
267 apns->apns[apns->num].ip_type = (mbtk_ip_type_enum)atoi(ptr_1);
268 ptr_1 = strstr(ptr_1, ",");
269 if(!ptr_1) {
270 continue;
271 }
272 ptr_1++; // Jump ',' to auth
273
274 apns->apns[apns->num].auth = (mbtk_apn_auth_type_enum)atoi(ptr_1);
275 ptr_1 = strstr(ptr_1, ",");
276 if(!ptr_1) {
277 continue;
278 }
279 ptr_1++; // Jump ',' to auto_data_call
280
281 apns->apns[apns->num].auto_boot_call = (uint8)atoi(ptr_1);
282 ptr_1 = strstr(ptr_1, ",");
283 if(!ptr_1) {
284 continue;
285 }
286 ptr_1++; // Jump ',' to apn
287
288 char *ptr_2 = strstr(ptr_1, ",");
289 if(!ptr_2) {
290 continue;
291 }
292 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
293 memcpy(apns->apns[apns->num].apn, ptr_1, ptr_2 - ptr_1); // apn
294 }
295
296 ptr_2++; // Jump ',' to user
297 ptr_1 = strstr(ptr_2, ",");
298 if(!ptr_1) {
299 continue;
300 }
301 if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
302 memcpy(apns->apns[apns->num].user, ptr_2, ptr_1 - ptr_2); // user
303 }
304
305 ptr_1++; // Jump ',' to pass
b.liu10a34102024-08-20 20:36:24 +0800306 ptr_2 = strstr(ptr_1, ",");
307 if(!ptr_2) {
308 continue;
309 }
b.liu87afc4c2024-08-14 17:33:45 +0800310 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
b.liu10a34102024-08-20 20:36:24 +0800311 memcpy(apns->apns[apns->num].pass, ptr_1, ptr_2 - ptr_1); // pass
312 }
313
314 ptr_2++; // Jump ',' to type
315 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
316 memcpy(apns->apns[apns->num].type, ptr_2, strlen(ptr_2)); // type
b.liu87afc4c2024-08-14 17:33:45 +0800317 }
318
319 apns->num++;
320 }
321 }
322}
323
324static int apn_prop_get_by_cid(mbtk_ril_cid_enum cid, mbtk_apn_info_t *apn)
325{
b.liu10a34102024-08-20 20:36:24 +0800326 char prop_name[128] = {0};
327 char prop_data[1024] = {0};
b.liu87afc4c2024-08-14 17:33:45 +0800328 memset(apn, 0, sizeof(mbtk_apn_info_t));
329
330 sprintf(prop_name, "%s_%d",MBTK_APN_PROP,cid);
331 // ip_type,auth,auto_data_call,apn,user,pass
b.liu10a34102024-08-20 20:36:24 +0800332#if 0
b.liu87afc4c2024-08-14 17:33:45 +0800333 if(property_get(prop_name, prop_data, "") > 0 && !str_empty(prop_data)) {
b.liu10a34102024-08-20 20:36:24 +0800334#else
335 if(apn_file_read(prop_name, prop_data, sizeof(prop_data)) > 0 && !str_empty(prop_data)) {
336#endif
b.liu87afc4c2024-08-14 17:33:45 +0800337 apn->cid = cid;
338 apn->auto_save = (uint8)1;
339 char *ptr_1 = prop_data;
340 apn->ip_type = (mbtk_ip_type_enum)atoi(ptr_1);
341 ptr_1 = strstr(ptr_1, ",");
342 if(!ptr_1) {
343 return -1;
344 }
345 ptr_1++; // Jump ',' to auth
346
347 apn->auth = (mbtk_apn_auth_type_enum)atoi(ptr_1);
348 ptr_1 = strstr(ptr_1, ",");
349 if(!ptr_1) {
350 return -1;
351 }
352 ptr_1++; // Jump ',' to auto_data_call
353
354 apn->auto_boot_call = (uint8)atoi(ptr_1);
355 ptr_1 = strstr(ptr_1, ",");
356 if(!ptr_1) {
357 return -1;
358 }
359 ptr_1++; // Jump ',' to apn
360
361 char *ptr_2 = strstr(ptr_1, ",");
362 if(!ptr_2) {
363 return -1;
364 }
365 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
366 memcpy(apn->apn, ptr_1, ptr_2 - ptr_1); // apn
367 }
368
369 ptr_2++; // Jump ',' to user
370 ptr_1 = strstr(ptr_2, ",");
371 if(!ptr_1) {
372 return -1;
373 }
374 if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
375 memcpy(apn->user, ptr_2, ptr_1 - ptr_2); // user
376 }
377
378 ptr_1++; // Jump ',' to pass
b.liu10a34102024-08-20 20:36:24 +0800379 ptr_2 = strstr(ptr_1, ",");
380 if(!ptr_2) {
381 return -1;
382 }
b.liu87afc4c2024-08-14 17:33:45 +0800383 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
b.liu10a34102024-08-20 20:36:24 +0800384 memcpy(apn->user, ptr_1, ptr_2 - ptr_1); // pass
385 }
386
387 ptr_2++; // Jump ',' to type
388 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
389 memcpy(apn->type, ptr_2, strlen(ptr_2)); // pass
b.liu87afc4c2024-08-14 17:33:45 +0800390 }
391 return 0;
392 }
393 return -1;
394}
395
b.liu10a34102024-08-20 20:36:24 +0800396static int apn_prop_get_by_cid_without_cgdcont(mbtk_ril_cid_enum cid, mbtk_apn_info_t *apn)
397{
398 char prop_name[128] = {0};
399 char prop_data[1024] = {0};
400
401 sprintf(prop_name, "%s_%d",MBTK_APN_PROP,cid);
402 // ip_type,auth,auto_data_call,apn,user,pass
403#if 0
404 if(property_get(prop_name, prop_data, "") > 0 && !str_empty(prop_data)) {
405#else
406 if(apn_file_read(prop_name, prop_data, sizeof(prop_data)) > 0 && !str_empty(prop_data)) {
407#endif
408 LOGD("APN : %s", prop_data);
409 char *ptr_1 = prop_data;
410 apn->auto_save = (uint8)1;
411 //apn->ip_type = (mbtk_ip_type_enum)atoi(ptr_1);
412 ptr_1 = strstr(ptr_1, ",");
413 if(!ptr_1) {
414 return -1;
415 }
416 ptr_1++; // Jump ',' to auth
417
418 apn->auth = (mbtk_apn_auth_type_enum)atoi(ptr_1);
419 ptr_1 = strstr(ptr_1, ",");
420 if(!ptr_1) {
421 return -1;
422 }
423 ptr_1++; // Jump ',' to auto_data_call
424
425 apn->auto_boot_call = (uint8)atoi(ptr_1);
426 ptr_1 = strstr(ptr_1, ",");
427 if(!ptr_1) {
428 return -1;
429 }
430 ptr_1++; // Jump ',' to apn
431
432 char *ptr_2 = strstr(ptr_1, ",");
433 if(!ptr_2) {
434 return -1;
435 }
436#if 0
437 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
438 memcpy(apn->apn, ptr_1, ptr_2 - ptr_1); // apn
439 }
440#endif
441
442 ptr_2++; // Jump ',' to user
443 ptr_1 = strstr(ptr_2, ",");
444 if(!ptr_1) {
445 return -1;
446 }
447 if(memcmp(ptr_2, "NULL", 4)) { // Not "NULL"
448 memcpy(apn->user, ptr_2, ptr_1 - ptr_2); // user
449 }
450
451 ptr_1++; // Jump ',' to pass
452 ptr_2 = strstr(ptr_1, ",");
453 if(!ptr_2) {
454 return -1;
455 }
456 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
457 memcpy(apn->user, ptr_1, ptr_2 - ptr_1); // pass
458 }
459
460 ptr_2++; // Jump ',' to type
461 if(memcmp(ptr_1, "NULL", 4)) { // Not "NULL"
462 memcpy(apn->type, ptr_2, strlen(ptr_2)); // pass
463 }
464 return 0;
465 } else {
466 apn->auto_save = (uint8)0;
467 }
468 return -1;
469}
470
b.liu87afc4c2024-08-14 17:33:45 +0800471static int apn_prop_set(mbtk_apn_info_t *apn)
472{
473 char prop_name[20] = {0};
b.liu10a34102024-08-20 20:36:24 +0800474 char prop_data[1024] = {0};
b.liu87afc4c2024-08-14 17:33:45 +0800475 int ret = -1;
476 if(apn->auto_save) {
477 sprintf(prop_name, "%s_%d", MBTK_APN_PROP, apn->cid);
478 // Delete apn
479 if(!str_empty(apn->apn)) {
b.liu10a34102024-08-20 20:36:24 +0800480 snprintf(prop_data, 1024, "%d,%d,%d,%s,%s,%s,%s", apn->ip_type, apn->auth, apn->auto_boot_call,
b.liu87afc4c2024-08-14 17:33:45 +0800481 apn->apn,
482 str_empty(apn->user) ? "NULL" : apn->user,
b.liu10a34102024-08-20 20:36:24 +0800483 str_empty(apn->pass) ? "NULL" : apn->pass,
484 str_empty(apn->pass) ? "NULL" : apn->type);
b.liu87afc4c2024-08-14 17:33:45 +0800485 }
486
b.liu10a34102024-08-20 20:36:24 +0800487#if 0
b.liu87afc4c2024-08-14 17:33:45 +0800488 ret = property_set(prop_name, prop_data);
b.liu10a34102024-08-20 20:36:24 +0800489#else
490 if(str_empty(apn->apn)) { // Delete APN
491 ret = apn_file_save(prop_name, NULL, 0);
492 } else {
493 ret = apn_file_save(prop_name, prop_data, strlen(prop_data));
494 }
495#endif
b.liu87afc4c2024-08-14 17:33:45 +0800496 }
497
b.liu10a34102024-08-20 20:36:24 +0800498 if(!ret && apn->def_route) {
b.liu87afc4c2024-08-14 17:33:45 +0800499 memset(prop_data, 0, sizeof(prop_data));
500 prop_data[0] = '0' + apn->cid;
501 ret = property_set(MBTK_DEF_ROUTE_CID, prop_data);
502 }
b.liu10a34102024-08-20 20:36:24 +0800503 if(!ret && apn->as_dns) {
b.liubcf86c92024-08-19 19:48:28 +0800504 memset(prop_data, 0, sizeof(prop_data));
505 prop_data[0] = '0' + apn->cid;
506 ret = property_set(MBTK_DEF_DNS_CID, prop_data);
507 }
b.liu87afc4c2024-08-14 17:33:45 +0800508 return ret;
509}
510
511static int apn_prop_reset(mbtk_data_call_info_t *data_info)
512{
513 mbtk_apn_info_t apn;
514 if(apn_prop_get_by_cid(data_info->cid, &apn)) {
515 return -1;
516 } else {
517 apn.auto_boot_call = data_info->auto_boot_call;
518 apn.def_route = data_info->def_route;
b.liubcf86c92024-08-19 19:48:28 +0800519 apn.as_dns = data_info->as_dns;
b.liu87afc4c2024-08-14 17:33:45 +0800520 return apn_prop_set(&apn);
521 }
522}
523
b.liubcf86c92024-08-19 19:48:28 +0800524static int wait_cgact_complete(int timeout)
525{
526 int count = timeout * 10; // timeout * 1000 / 100
527 int i = 0;
528
529 while(cgact_wait.waitting && i < count) {
530 i++;
531 usleep(100000); // 100ms
532 }
533
534 memset(&cgact_wait, 0, sizeof(ril_cgact_wait_t));
535 if(i == count) { // Timeout
536 return -1;
537 } else {
538 return 0;
539 }
540}
b.liu87afc4c2024-08-14 17:33:45 +0800541
542/*
543AT+COPS=?
544
545+COPS: (2, "CHN-CT", "CT", "46011", 7),(3, "CHN-UNICOM", "UNICOM", "46001", 7),(3, "CHINA MOBILE", "CMCC", "46000", 0),(3, "CHINA MOBILE", "CMCC", "46000", 7),(3, "China Broadnet", "CBN", "46015", 7),,(0,1,2,3,4),(0,1,2)
546
547OK
548*/
549static int req_available_net_get(mbtk_net_info_array_t* nets, int *cme_err)
550{
551 ATResponse *response = NULL;
552 int err = at_send_command_singleline("AT+COPS=?", "+COPS:", &response);
553
554 if (err < 0 || response->success == 0 || !response->p_intermediates){
555 if(cme_err) {
556 *cme_err = at_get_cme_error(response);
557 }
558 goto exit;
559 }
560 char *line_ptr = response->p_intermediates->line;
561 if(line_ptr == NULL) {
562 LOG("line is NULL");
563 err = -1;
564 goto exit;
565 }
566 //LOG("Line:%s",line_ptr);
567 line_ptr = strstr(line_ptr, "(");
568 while(line_ptr) {
569 line_ptr++;
570 // Only for available/current net.
571 if(*line_ptr == '1' || *line_ptr == '2' || *line_ptr == '3') {
572 nets->net_info[nets->num].net_state = (uint8)atoi(line_ptr); // net_state
573
574 line_ptr = strstr(line_ptr, ",");
575 if(line_ptr == NULL) {
576 err = -1;
577 goto exit;
578 }
579 line_ptr++;
580
581 line_ptr = strstr(line_ptr, ",");
582 if(line_ptr == NULL) {
583 err = -1;
584 goto exit;
585 }
586 line_ptr++;
587
588 line_ptr = strstr(line_ptr, ",");
589 if(line_ptr == NULL) {
590 err = -1;
591 goto exit;
592 }
593
594 while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' ' || *line_ptr == '"'))
595 line_ptr++;
596
597 // set sel_mode to 0
598 nets->net_info[nets->num].net_sel_mode = (uint8)0;
599 // Point to "46000"
600 //LOG("PLMN:%s",line_ptr);
601 //sleep(1);
602 //uint32_2_byte((uint32)atoi(line_ptr), buff_ptr + 3, false); // plmn
603 nets->net_info[nets->num].plmn = (uint32)atoi(line_ptr);
604
605 line_ptr = strstr(line_ptr, ",");
606 if(line_ptr == NULL) {
607 err = -1;
608 goto exit;
609 }
610
611 while(*line_ptr != '\0' && (*line_ptr == ',' || *line_ptr == ' '))
612 line_ptr++;
613
614 // Point to "7"
615 if(*line_ptr == '\0') {
616 err = -1;
617 goto exit;
618 }
619 //LOG("Type:%s",line_ptr);
620 //sleep(1);
621 nets->net_info[nets->num].net_type = (uint8)atoi(line_ptr); // net_type
622
623 nets->num++;
624 }
625
626 line_ptr = strstr(line_ptr, "(");
627 }
628exit:
629 at_response_free(response);
630 return err;
631}
632
633/*
634AT+COPS?
635+COPS: 1
636
637OK
638
639or
640
641AT+COPS?
642+COPS: 0,2,"46001",7
643
644OK
645
646*/
647static int req_net_sel_mode_get(mbtk_net_info_t *net, int *cme_err)
648{
649 //LOG("req_net_sel_mode_get() 0");
650 //sleep(1);
651 ATResponse *response = NULL;
652 int tmp_int;
653 char *tmp_ptr = NULL;
654 int err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
655 //LOG("req_net_sel_mode_get() 00");
656 //sleep(1);
657 if (err < 0 || response->success == 0 || !response->p_intermediates){
658 if(cme_err != NULL)
659 *cme_err = at_get_cme_error(response);
660 err = -1;
661 goto exit;
662 }
663 //LOG("req_net_sel_mode_get() 1");
664 //sleep(1);
665 char *line = response->p_intermediates->line;
666 if(line == NULL) {
667 LOG("line is NULL");
668 goto exit;
669 }
670 //LOG("req_net_sel_mode_get() 2");
671 //sleep(1);
672 err = at_tok_start(&line);
673 if (err < 0)
674 {
675 goto exit;
676 }
677 //LOG("req_net_sel_mode_get() 3");
678 //sleep(1);
679 err = at_tok_nextint(&line, &tmp_int);
680 if (err < 0)
681 {
682 goto exit;
683 }
684 net->net_sel_mode = (uint8)tmp_int;
685 //LOG("req_net_sel_mode_get() 4");
686 //sleep(1);
687 // +COPS: 1
688 if(!at_tok_hasmore(&line)) {
689 goto exit;
690 }
691 //LOG("req_net_sel_mode_get() 5");
692 //sleep(1);
693 err = at_tok_nextint(&line, &tmp_int);
694 if (err < 0)
695 {
696 goto exit;
697 }
698 //LOG("req_net_sel_mode_get() 6");
699 //sleep(1);
700 err = at_tok_nextstr(&line, &tmp_ptr);
701 if (err < 0)
702 {
703 goto exit;
704 }
705 // memcpy(net->plmn, tmp_ptr, strlen(tmp_ptr));
706 net->plmn = (uint32)atoi(tmp_ptr);
707 //LOG("req_net_sel_mode_get() 7");
708 //sleep(1);
709 err = at_tok_nextint(&line, &tmp_int);
710 if (err < 0)
711 {
712 goto exit;
713 }
714 net->net_type = (uint8)tmp_int;
715
716 net->net_state = (uint8)MBTK_NET_AVIL_STATE_CURRENT;
717
718exit:
719 //LOG("req_net_sel_mode_get() 8");
720 //sleep(1);
721 at_response_free(response);
722 return err;
723}
724
725/*
726AT+COPS=0
727or
728AT+COPS=1,2,"46000",7
729
730OK
731
732*/
733static int req_net_sel_mode_set(mbtk_net_info_t* net, int *cme_err)
734{
735 ATResponse *response = NULL;
736 char cmd[50] = {0};
737 char* cmp_ptr = cmd;
738 if(net == NULL) {
739 cmp_ptr += sprintf(cmp_ptr, "AT+COPS=0");
740 } else {
741 if(net->net_sel_mode == 0) {
742 cmp_ptr += sprintf(cmp_ptr, "AT+COPS=0");
743 } else if(net->net_type == 0xFF) {
744 cmp_ptr += sprintf(cmp_ptr, "AT+COPS=1,2,\"%d\"",net->plmn);
745 } else {
746 cmp_ptr += sprintf(cmp_ptr, "AT+COPS=1,2,\"%d\",%d",net->plmn, net->net_type);
747 }
748 }
749
750 int err = at_send_command(cmd, &response);
751
752 if (err < 0 || response->success == 0) {
753 if(cme_err) {
754 *cme_err = at_get_cme_error(response);
755 }
756 goto exit;
757 }
758
759exit:
760 at_response_free(response);
761 return err;
762}
763
764/*
765AT*BAND=15
766OK
767
768*/
769static int req_band_set(mbtk_band_info_t* band, int *cme_err)
770{
771 ATResponse *response = NULL;
772 char cmd[100] = {0};
773 int err = -1;
774
775 if(band->gsm_band == 0 && band->umts_band == 0
776 && band->tdlte_band == 0 && band->fddlte_band == 0) {
777 sprintf(cmd, "AT*BAND=%d", band->net_pref);
778 } else {
779 log_hex("BAND_SUPPORT", &band_info.band_support, sizeof(mbtk_band_info_t));
780 log_hex("BAND", band, sizeof(mbtk_band_info_t));
781
782 if(band->gsm_band == 0) {
783 band->gsm_band = band_info.band_support.gsm_band;
784 }
785 if(band->umts_band == 0) {
786 band->umts_band = band_info.band_support.umts_band;
787 }
788 if(band->tdlte_band == 0) {
789 band->tdlte_band = band_info.band_support.tdlte_band;
790 }
791 if(band->fddlte_band == 0) {
792 band->fddlte_band = band_info.band_support.fddlte_band;
793 }
794
795 if((band->gsm_band & band_info.band_support.gsm_band) != band->gsm_band) {
796 LOG("GSM band error.");
797 goto exit;
798 }
799
800 if((band->umts_band & band_info.band_support.umts_band) != band->umts_band) {
801 LOG("UMTS band error.");
802 goto exit;
803 }
804
805 if((band->tdlte_band & band_info.band_support.tdlte_band) != band->tdlte_band) {
806 LOG("TDLTE band error.");
807 goto exit;
808 }
809
810 if((band->fddlte_band & band_info.band_support.fddlte_band) != band->fddlte_band) {
811 LOG("FDDLTE band error.");
812 goto exit;
813 }
814
815 if((band->lte_ext_band & band_info.band_support.lte_ext_band) != band->lte_ext_band) {
816 LOG("EXT_LTE band error.");
817 goto exit;
818 }
819
820 if(band->net_pref == 0xFF) { // No change net_pref.
821 int tmp_int;
822 err = at_send_command_singleline("AT*BAND?", "*BAND:", &response);
823 if (err < 0 || response->success == 0 || !response->p_intermediates){
824 if(cme_err) {
825 *cme_err = at_get_cme_error(response);
826 }
827 goto exit;
828 }
829
830 char *line = response->p_intermediates->line;
831 err = at_tok_start(&line);
832 if (err < 0)
833 {
834 goto exit;
835 }
836
837 err = at_tok_nextint(&line, &tmp_int);
838 if (err < 0)
839 {
840 goto exit;
841 }
842 band->net_pref = (uint8)tmp_int; // Set to current net_pref.
843
844 at_response_free(response);
845 }
846
847 if(band->lte_ext_band > 0) {
848 sprintf(cmd, "AT*BAND=%d,%d,%d,%d,%d,,,,%d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band, band->lte_ext_band);
849 } else {
850 sprintf(cmd, "AT*BAND=%d,%d,%d,%d,%d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
851 }
852 }
853 err = at_send_command(cmd, &response);
854
855 if (err < 0 || response->success == 0){
856 if(cme_err) {
857 *cme_err = at_get_cme_error(response);
858 }
859 goto exit;
860 }
861
862 err = 0;
863exit:
864 at_response_free(response);
865 return err;
866}
867
868/*
869// ???????
870AT*BAND=?
871*BAND:(0-18),79,147,482,524503
872
873OK
874
875// ???????????
876AT*BAND?
877*BAND: 15, 78, 147, 482, 524503, 0, 2, 2, 0, 0
878
879OK
880
881// ?????????
882AT*BAND=5,79,147,128,1
883OK
884
885net_prefferred??
886 0 : GSM only
887 1 : UMTS only
888 2 : GSM/UMTS(auto)
889 3 : GSM/UMTS(GSM preferred)
890 4 : GSM/UMTS(UMTS preferred)
891 5 : LTE only
892 6 : GSM/LTE(auto)
893 7 : GSM/LTE(GSM preferred)
894 8 : GSM/LTE(LTE preferred)
895 9 : UMTS/LTE(auto)
896 10 : UMTS/LTE(UMTS preferred)
897 11 : UMTS/LTE(LTE preferred)
898 12 : GSM/UMTS/LTE(auto)
899 13 : GSM/UMTS/LTE(GSM preferred)
900 14 : GSM/UMTS/LTE(UMTS preferred)
901 15 : GSM/UMTS/LTE(LTE preferred)
902GSM band??
903 1 ?C PGSM 900 (standard or primary)
904 2 ?C DCS GSM 1800
905 4 ?C PCS GSM 1900
906 8 ?C EGSM 900 (extended)
907 16 ?C GSM 450
908 32 ?C GSM 480
909 64 ?C GSM 850
910 512 - BAND_LOCK_BIT // used for GSM band setting
911UMTS band??
912 1 ?C UMTS_BAND_1
913 2 ?C UMTS_BAND_2
914 4 ?C UMTS_BAND_3
915 8 ?C UMTS_BAND_4
916 16 ?C UMTS_BAND_5
917 32 ?C UMTS_BAND_6
918 64 ?C UMTS_BAND_7
919 128 ?C UMTS_BAND_8
920 256 ?C UMTS_BAND_9
921LTEbandH(TDD-LTE band)
922 32 ?C TDLTE_BAND_38
923 64 ?C TDLTE_BAND_39
924 128 ?C TDLTE_BAND_40
925 256 ?C TDLTE_BAND_41
926LTEbandL(FDD-LTE band)
927 1 ?C FDDLTE_BAND_1
928 4 ?C FDDLTE _BAND_3
929 8 ?C FDDLTE _BAND_4
930 64 ?C FDDLTE _BAND_7
931 65536 ?C FDDLTE _BAND_17
932 524288 ?C FDDLTE _BAND_20
933*/
934static int req_band_get(mbtk_band_info_t *band, int *cme_err)
935{
936 ATResponse *response = NULL;
937 int tmp_int;
938
939 log_hex("BAND_SUPPORT", &band_info.band_support, sizeof(mbtk_band_info_t));
940 int err = at_send_command_singleline("AT*BAND?", "*BAND:", &response);
941 if (err < 0 || response->success == 0 || !response->p_intermediates){
942 if(cme_err) {
943 *cme_err = at_get_cme_error(response);
944 }
945 goto exit;
946 }
947
948 char *line = response->p_intermediates->line;
949 err = at_tok_start(&line);
950 if (err < 0)
951 {
952 goto exit;
953 }
954
955 err = at_tok_nextint(&line, &tmp_int);
956 if (err < 0)
957 {
958 goto exit;
959 }
960 band->net_pref = (uint8)tmp_int;
961
962 err = at_tok_nextint(&line, &tmp_int);
963 if (err < 0)
964 {
965 goto exit;
966 }
967 band->gsm_band = (uint16)tmp_int;
968
969 err = at_tok_nextint(&line, &tmp_int);
970 if (err < 0)
971 {
972 goto exit;
973 }
974 band->umts_band = (uint16)tmp_int;
975
976 err = at_tok_nextint(&line, &tmp_int);
977 if (err < 0)
978 {
979 goto exit;
980 }
981 band->tdlte_band = (uint32)tmp_int;
982
983 err = at_tok_nextint(&line, &tmp_int);
984 if (err < 0)
985 {
986 goto exit;
987 }
988 band->fddlte_band = (uint32)tmp_int;
989
990 // roamingConfig
991 err = at_tok_nextint(&line, &tmp_int);
992 if (err < 0)
993 {
994 goto exit;
995 }
996
997 // srvDomain
998 err = at_tok_nextint(&line, &tmp_int);
999 if (err < 0)
1000 {
1001 goto exit;
1002 }
1003
1004 // bandPriorityFlag
1005 err = at_tok_nextint(&line, &tmp_int);
1006 if (err < 0)
1007 {
1008 goto exit;
1009 }
1010
1011 //
1012 err = at_tok_nextint(&line, &tmp_int);
1013 if (err < 0)
1014 {
1015 goto exit;
1016 }
1017
1018 // ltebandExt
1019 err = at_tok_nextint(&line, &tmp_int);
1020 if (err < 0)
1021 {
1022 goto exit;
1023 }
1024 band->lte_ext_band = (uint32)tmp_int;
1025
1026 log_hex("BAND", band, sizeof(mbtk_band_info_t));
1027
1028exit:
1029 at_response_free(response);
1030 return err;
1031}
1032
1033/*
1034AT+CSQ
1035+CSQ: 31,99
1036
1037OK
1038
1039AT+CESQ
1040+CESQ: 60,99,255,255,20,61
1041
1042OK
1043
1044AT+COPS?
1045+COPS: 0,2,"46001",7
1046
1047OK
1048
1049*/
1050static int req_net_signal_get(mbtk_signal_info_t *signal, int *cme_err)
1051{
1052 ATResponse *response = NULL;
1053 int tmp_int;
1054 char *tmp_ptr = NULL;
1055 // AT+EEMOPT=1 in the first.
1056 int err = at_send_command_singleline("AT+CSQ", "+CSQ:", &response);
1057 if (err < 0 || response->success == 0 || !response->p_intermediates){
1058 if(cme_err != NULL)
1059 *cme_err = at_get_cme_error(response);
1060 err = -1;
1061 goto exit;
1062 }
1063
1064 char *line = response->p_intermediates->line;
1065 err = at_tok_start(&line);
1066 if (err < 0)
1067 {
1068 goto exit;
1069 }
1070 err = at_tok_nextint(&line, &tmp_int);
1071 if (err < 0)
1072 {
1073 goto exit;
1074 }
1075 signal->rssi = (uint8)tmp_int;
1076 at_response_free(response);
1077
1078 err = at_send_command_singleline("AT+CESQ", "+CESQ:", &response);
1079 if (err < 0 || response->success == 0 || !response->p_intermediates){
1080 if(cme_err != NULL)
1081 *cme_err = at_get_cme_error(response);
1082 err = -1;
1083 goto exit;
1084 }
1085
1086 line = response->p_intermediates->line;
1087 err = at_tok_start(&line);
1088 if (err < 0)
1089 {
1090 goto exit;
1091 }
1092 err = at_tok_nextint(&line, &tmp_int);
1093 if (err < 0)
1094 {
1095 goto exit;
1096 }
1097 signal->rxlev = (uint8)tmp_int;
1098
1099 err = at_tok_nextint(&line, &tmp_int);
1100 if (err < 0)
1101 {
1102 goto exit;
1103 }
1104 signal->ber = (uint8)tmp_int;
1105
1106 err = at_tok_nextint(&line, &tmp_int);
1107 if (err < 0)
1108 {
1109 goto exit;
1110 }
1111 signal->rscp = (uint8)tmp_int;
1112
1113 err = at_tok_nextint(&line, &tmp_int);
1114 if (err < 0)
1115 {
1116 goto exit;
1117 }
1118 signal->ecno = (uint8)tmp_int;
1119
1120 err = at_tok_nextint(&line, &tmp_int);
1121 if (err < 0)
1122 {
1123 goto exit;
1124 }
1125 signal->rsrq = (uint8)tmp_int;
1126
1127 err = at_tok_nextint(&line, &tmp_int);
1128 if (err < 0)
1129 {
1130 goto exit;
1131 }
1132 signal->rsrp = (uint8)tmp_int;
1133
1134 at_response_free(response);
1135 err = at_send_command_singleline("AT+COPS?", "+COPS:", &response);
1136 if (err < 0 || response->success == 0 || !response->p_intermediates){
1137 if(cme_err != NULL)
1138 *cme_err = at_get_cme_error(response);
1139 err = -1;
1140 goto exit;
1141 }
1142 line = response->p_intermediates->line;
1143 err = at_tok_start(&line);
1144 if (err < 0)
1145 {
1146 goto exit;
1147 }
1148 err = at_tok_nextint(&line, &tmp_int);
1149 if (err < 0)
1150 {
1151 goto exit;
1152 }
1153 if(!at_tok_hasmore(&line)) {
1154 goto exit;
1155 }
1156 err = at_tok_nextint(&line, &tmp_int);
1157 if (err < 0)
1158 {
1159 goto exit;
1160 }
1161 err = at_tok_nextstr(&line, &tmp_ptr);
1162 if (err < 0)
1163 {
1164 goto exit;
1165 }
1166 err = at_tok_nextint(&line, &tmp_int);
1167 if (err < 0)
1168 {
1169 goto exit;
1170 }
1171 signal->type = (uint8)tmp_int;
1172
1173exit:
1174 at_response_free(response);
1175 return err;
1176}
1177
1178/*
1179AT+CREG=3
1180OK
1181
1182AT+CREG?
1183+CREG: 3,1,"8330","06447340",7
1184
1185OK
1186
1187AT+CREG?
1188+CREG: 3,0
1189
1190OK
1191
1192AT+CEREG?
1193+CEREG: 3,1,"8330","06447340",7
1194
1195OK
1196
1197
1198AT+CIREG?
1199+CIREG: 2,1,15
1200
1201OK
1202
1203AT+CIREG?
1204+CIREG: 0
1205
1206OK
1207
1208
1209*/
1210static int req_net_reg_get(mbtk_net_reg_info_t *reg, int *cme_err)
1211{
1212 ATResponse *response = NULL;
1213 int tmp_int;
1214 char *tmp_str = NULL;
1215 int err = at_send_command("AT+CREG=3", &response);
1216 if (err < 0 || response->success == 0){
1217 if(cme_err) {
1218 *cme_err = at_get_cme_error(response);
1219 }
1220 goto exit;
1221 }
1222 at_response_free(response);
1223
1224 err = at_send_command_multiline("AT+CREG?", "+CREG:", &response);
1225 if (err < 0 || response->success == 0 || !response->p_intermediates){
1226 if(cme_err) {
1227 *cme_err = at_get_cme_error(response);
1228 }
1229 goto exit;
1230 }
1231
1232 char *line = response->p_intermediates->line;
1233 err = at_tok_start(&line);
1234 if (err < 0)
1235 {
1236 goto exit;
1237 }
1238 err = at_tok_nextint(&line, &tmp_int); // n
1239 if (err < 0)
1240 {
1241 goto exit;
1242 }
1243 err = at_tok_nextint(&line, &tmp_int);// stat
1244 if (err < 0)
1245 {
1246 goto exit;
1247 }
1248 reg->call_state = (uint8)tmp_int;
1249
1250 if(at_tok_hasmore(&line)) {
1251 err = at_tok_nextstr(&line, &tmp_str); // lac
1252 if (err < 0)
1253 {
1254 goto exit;
1255 }
1256 reg->lac = strtol(tmp_str, NULL, 16);
1257
1258 err = at_tok_nextstr(&line, &tmp_str); // ci
1259 if (err < 0)
1260 {
1261 goto exit;
1262 }
1263 reg->ci = strtol(tmp_str, NULL, 16);
1264
1265 err = at_tok_nextint(&line, &tmp_int);// AcT
1266 if (err < 0)
1267 {
1268 goto exit;
1269 }
1270 reg->type = (uint8)tmp_int;
1271 }
1272 at_response_free(response);
1273
1274 err = at_send_command_multiline("AT+CEREG?", "+CEREG:", &response);
1275 if (err < 0 || response->success == 0 || !response->p_intermediates){
1276 if(cme_err) {
1277 *cme_err = at_get_cme_error(response);
1278 }
1279 goto exit;
1280 }
1281
1282 line = response->p_intermediates->line;
1283 err = at_tok_start(&line);
1284 if (err < 0)
1285 {
1286 goto exit;
1287 }
1288 err = at_tok_nextint(&line, &tmp_int); // n
1289 if (err < 0)
1290 {
1291 goto exit;
1292 }
1293 err = at_tok_nextint(&line, &tmp_int);// stat
1294 if (err < 0)
1295 {
1296 goto exit;
1297 }
1298 reg->data_state = (uint8)tmp_int;
1299
1300 if(reg->lac == 0 && at_tok_hasmore(&line)) {
1301 err = at_tok_nextstr(&line, &tmp_str); // lac
1302 if (err < 0)
1303 {
1304 goto exit;
1305 }
1306 reg->lac = strtol(tmp_str, NULL, 16);
1307
1308 err = at_tok_nextstr(&line, &tmp_str); // ci
1309 if (err < 0)
1310 {
1311 goto exit;
1312 }
1313 reg->ci = strtol(tmp_str, NULL, 16);
1314
1315 err = at_tok_nextint(&line, &tmp_int);// AcT
1316 if (err < 0)
1317 {
1318 goto exit;
1319 }
1320 reg->type = (uint8)tmp_int;
1321 }
1322 at_response_free(response);
1323
1324 err = at_send_command_multiline("AT+CIREG?", "+CIREG:", &response);
1325 if (err < 0 || response->success == 0 || !response->p_intermediates){
1326 reg->ims_state = (uint8)0;
1327 err = 0;
1328 goto exit;
1329 }
1330 line = response->p_intermediates->line;
1331 err = at_tok_start(&line);
1332 if (err < 0)
1333 {
1334 goto exit;
1335 }
1336 err = at_tok_nextint(&line, &tmp_int); // n/stat
1337 if (err < 0)
1338 {
1339 goto exit;
1340 }
1341 if(at_tok_hasmore(&line)) {
1342 err = at_tok_nextint(&line, &tmp_int);// stat
1343 if (err < 0)
1344 {
1345 goto exit;
1346 }
1347 reg->ims_state = (uint8)tmp_int;
1348 } else {
1349 reg->ims_state = (uint8)tmp_int;
1350 }
1351
1352exit:
1353 at_response_free(response);
1354 return err;
1355}
1356
1357/*
b.liub4772072024-08-15 14:47:03 +08001358AT+EEMOPT=1
1359OK
1360
1361// LTE
1362AT+EEMGINFO?
1363// <mcc>, <length of mnc>, <mnc>, <tac>, <PCI>, <dlEuarfcn>, < ulEuarfcn >, <band>, <dlBandwidth>,
1364// <rsrp>,<rsrq>, <sinr>,
1365// errcModeState,emmState,serviceState,IsSingleEmmRejectCause,EMMRejectCause,mmeGroupId,mmeCode,mTmsi,
1366// cellId,subFrameAssignType,specialSubframePatterns,transMode
1367// mainRsrp,diversityRsrp,mainRsrq,diversityRsrq,rssi,cqi,pathLoss,tb0DlTpt,tb1DlTpt,tb0DlPeakTpt,tb1DlPeakTpt,tb0UlPeakTpt,
1368// tb1UlPeakTpt,dlThroughPut,dlPeakThroughPut,averDlPRB,averCQITb0,averCQITb1,rankIndex,grantTotal,ulThroughPut,ulPeakThroughPut,currPuschTxPower,averUlPRB,
1369// dlBer, ulBer,
1370// diversitySinr, diversityRssi
1371+EEMLTESVC: 1120, 2, 0, 33584, 430, 40936, 40936, 41, 20,
13720, 0, 0,
13731, 10, 0, 1, 0, 1059, 78, 3959566565,
1374105149248, 2, 7, 7,
13750, 0, 0, 0, 0, 0, 0, 1190919, 0, 0, 0, 16779777,
13760, 5112867, 3959566565, 2, 0, 0, 0, 0, 0, 0, 0, 0,
13770, 0,
13787, 44
1379
1380// index,phyCellId,euArfcn,rsrp,rsrq
1381+EEMLTEINTER: 0, 65535, 38950, 0, 0
1382
1383+EEMLTEINTER: 1, 0, 0, 0, 0
1384
1385+EEMLTEINTER: 2, 0, 4294967295, 255, 255
1386
1387+EEMLTEINTER: 3, 65535, 1300, 0, 0
1388
1389+EEMLTEINTER: 4, 0, 0, 0, 0
1390
1391+EEMLTEINTER: 5, 0, 4294967295, 247, 0
1392
1393+EEMLTEINTER: 6, 197, 41332, 24, 9
1394
1395+EEMLTEINTER: 7, 0, 0, 0, 0
1396
1397+EEMLTEINTER: 8, 0, 0, 0, 0
1398
1399+EEMLTEINTRA: 0, 429, 40936, 56, 12
1400
1401+EEMLTEINTERRAT: 0,0
1402
1403+EEMLTEINTERRAT: 1,0
1404
1405+EEMGINFO: 3, 2 // <state>:
1406 // 0: ME in Idle mode
1407 // 1: ME in Dedicated mode
1408 // 2: ME in PS PTM mode
1409 // 3: invalid state
1410 // <nw_type>:
1411 // 0: GSM 1: UMTS 2: LTE
1412
1413OK
1414
1415// WCDMA
1416AT+EEMGINFO?
1417// Mode, sCMeasPresent, sCParamPresent, ueOpStatusPresent,
1418
1419// if sCMeasPresent == 1
1420// cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev, txPower,
1421// endif
1422
1423// if sCParamPresent == 1
1424// rac, nom, mcc, mnc_len, mnc, lac, ci,
1425// uraId, psc, arfcn, t3212, t3312, hcsUsed, attDetAllowed,
1426// csDrxCycleLen, psDrxCycleLen, utranDrxCycleLen, HSDPASupport, HSUPASupport,
1427// endif
1428
1429// if ueOpStatusPresent == 1
1430// rrcState, numLinks, srncId, sRnti,
1431// algPresent, cipherAlg, cipherOn, algPresent, cipherAlg, cipherOn,
1432// HSDPAActive, HSUPAActive, MccLastRegisteredNetwork, MncLastRegisteredNetwork, TMSI, PTMSI, IsSingleMmRejectCause, IsSingleGmmRejectCause,
1433// MMRejectCause, GMMRejectCause, mmState, gmmState, gprsReadyState, readyTimerValueInSecs, NumActivePDPContext, ULThroughput, DLThroughput,
1434// serviceStatus, pmmState, LAU_status, LAU_count, RAU_status, RAU_count
1435// endif
1436//
1437+EEMUMTSSVC: 3, 1, 1, 1,
1438-80, 27, -6, -18, -115, -32768,
14391, 1, 1120, 2, 1, 61697, 168432821,
144015, 24, 10763, 0, 0, 0, 0,
1441128, 128, 65535, 0, 0,
14422, 255, 65535, 4294967295,
14430, 0, 0, 0, 0, 0,
14440, 0, 0, 0, 0, 0, 1, 1,
144528672, 28672, 0, 0, 0, 0, 0, 0, 0,
14460, 0, 0, 0, 0, 0
1447
1448// index, cpichRSCP, utraRssi, cpichEcN0, sQual, sRxLev ,mcc, mnc, lac, ci, arfcn, psc
1449+EEMUMTSINTRA: 0, -32768, -1, -32768, -18, -115, 0, 0, 65534, 1, 10763, 32
1450
1451+EEMUMTSINTRA: 1, -1, -32768, -18, -115, 0, 0, 65534, 2, 10763, 40, 32768
1452
1453+EEMUMTSINTRA: 2, -32768, -18, -115, 0, 0, 65534, 3, 10763, 278, 32768, 65535
1454
1455+EEMUMTSINTRA: 3, -18, -115, 0, 0, -2, 4, 10763, 28, 32768, 65535, 32768
1456
1457+EEMUMTSINTRA: 4, -115, 0, 0, -2, 5, 10763, 270, 32768, 65535, 32768, 65518
1458
1459+EEMUMTSINTRA: 5, 0, 0, -2, 6, 10763, 286, 32768, 65535, 32768, 65518, 65421
1460
1461+EEMUMTSINTRA: 6, 0, -2, 7, 10763, 80, 32768, 65535, 32768, 65518, 65421, 0
1462
1463+EEMUMTSINTRA: 7, -2, 8, 10763, 206, -32768, 65535, 32768, 65518, 65421, 0, 0
1464
1465+EEMUMTSINTRA: 8, 9, 10763, 11, -32768, -1, 32768, 65518, 65421, 0, 0, 65534
1466
1467+EEMUMTSINTRA: 9, 10763, 19, -32768, -1, -32768, 65518, 65421, 0, 0, 65534, 11
1468
1469+EEMUMTSINTRA: 10, 232, -32768, -1, -32768, -18, 65421, 0, 0, 65534, 12, 10763
1470
1471+EEMUMTSINTRA: 11, -32768, -1, -32768, -18, -115, 0, 0, 65534, 13, 10763, 66
1472
1473+EEMUMTSINTRA: 12, -1, -32768, -18, -115, 0, 0, 65534, 14, 10763, 216, 32768
1474
1475+EEMUMTSINTRA: 13, -32768, -18, -115, 0, 0, 65534, 15, 10763, 183, 32768, 65535
1476
1477+EEMUMTSINTRA: 14, -18, -115, 0, 0, -2, 16, 10763, 165, 32768, 65535, 32768
1478
1479+EEMUMTSINTRA: 15, -115, 0, 0, -2, 17, 10763, 151, 32768, 65535, 32768, 65518
1480
1481+EEMUMTSINTRA: 16, 0, 0, -2, 18, 10763, 43, 32768, 65535, 32768, 65518, 65421
1482
1483+EEMUMTSINTRA: 17, 0, -2, 19, 10763, 72, 32768, 65535, 32768, 65518, 65421, 0
1484
1485+EEMUMTSINTRA: 18, -2, 20, 10763, 157, -32768, 65535, 32768, 65518, 65421, 0, 0
1486
1487+EEMUMTSINTRA: 19, 21, 10763, 165, -32768, -1, 32768, 65518, 65421, 0, 0, 65534
1488
1489+EEMUMTSINTRA: 20, 10763, 301, -32768, -1, -32768, 65518, 65421, 0, 0, 65534, 23
1490
1491+EEMUMTSINTRA: 21, 23, -32768, -1, -32768, -18, 65421, 0, 0, 65534, 24, 10763
1492
1493+EEMUMTSINTRA: 22, -32768, -1, -32768, -18, -115, 0, 0, 65534, 25, 10763, 0
1494
1495+EEMUMTSINTRA: 23, -1, -32768, -18, -115, 0, 0, 65534, 26, 10763, 167, 32768
1496
1497+EEMUMTSINTRA: 24, -32768, -18, -115, 0, 0, 65534, 27, 10763, 34, 32768, 65535
1498
1499+EEMUMTSINTRA: 25, -18, -115, 0, 0, -2, 28, 10763, 313, 32768, 65535, 32768
1500
1501+EEMUMTSINTRA: 26, -115, 0, 0, -2, 29, 10763, 152, 32768, 65535, 32768, 65518
1502
1503+EEMUMTSINTRA: 27, 0, 0, -2, 30, 10763, 239, 0, 0, 0, 0, 0
1504
1505+EEMUMTSINTRA: 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1506
1507+EEMUMTSINTRA: 29, 0, 0, 0, 0, -115, 0, 0, 65534, 30, 10763, 239
1508
1509// index,gsmRssi,rxLev,C1,C2,mcc,mnc,lac,ci,arfcn,bsic
1510+EEMUMTSINTERRAT: 0, -32768, -107, -1, -1, 0, 0, 65534, 0, 117, 36
1511
1512+EEMUMTSINTERRAT: 1, -107, -1, -1, 0, 0, 65534, 1, 72, 49, 0
1513
1514+EEMUMTSINTERRAT: 2, -1, -1, 0, 0, 65534, 2, 119, 15, 32768, 149
1515
1516+EEMUMTSINTERRAT: 3, -1, 0, 0, -2, 3, 121, 23, 0, 0, 0
1517
1518+EEMGINFO: 3, 1
1519
1520OK
1521
1522
1523// GSM
1524AT+EEMGINFO?
1525+EEMGINFOBASIC: 2
1526
1527// mcc, mnc_len, mnc, lac, ci, nom, nco,
1528// bsic, C1, C2, TA, TxPwr,
1529// RxSig, RxSigFull, RxSigSub, RxQualFull, RxQualSub,
1530// ARFCB_tch, hopping_chnl, chnl_type, TS, PacketIdle, rac, arfcn,
1531// bs_pa_mfrms, C31, C32, t3212, t3312, pbcch_support, EDGE_support,
1532// ncc_permitted, rl_timeout, ho_count, ho_succ, chnl_access_count, chnl_access_succ_count,
1533// gsmBand,channelMode
1534+EEMGINFOSVC: 1120, 2, 0, 32784, 24741, 2, 0,
153563, 36, 146, 1, 7,
153646, 42, 42, 7, 0,
153753, 0, 8, 0, 1, 6, 53,
15382, 0, 146, 42, 54, 0, 1,
15391, 32, 0, 0, 0, 0,
15400, 0
1541
1542// PS_attached, attach_type, service_type, tx_power, c_value,
1543// ul_ts, dl_ts, ul_cs, dl_cs, ul_modulation, dl_modulation,
1544// gmsk_cv_bep, 8psk_cv_bep, gmsk_mean_bep, 8psk_mean_bep, EDGE_bep_period, single_gmm_rej_cause
1545// pdp_active_num, mac_mode, network_control, network_mode, EDGE_slq_measurement_mode, edge_status
1546+EEMGINFOPS: 1, 255, 0, 0, 0,
15470, 0, 268435501, 1, 0, 0,
15484, 0, 96, 0, 0, 0,
15490, 0, 0, 65535, 0, 13350
1550
1551+EEMGINFO: 0, 0
1552
1553OK
1554
1555*/
1556static int req_cell_info_get(int *cme_err)
1557{
1558 ATResponse *response = NULL;
1559 int tmp_int;
1560 int buff_size = 0;
1561 // AT+EEMOPT=1 in the first.
1562 int err = at_send_command("AT+EEMOPT=1", &response);
1563 if (err < 0 || response->success == 0){
1564 *cme_err = at_get_cme_error(response);
1565 goto exit;
1566 }
1567
1568 // Reset buffer in the first.
1569 memset(&cell_info, 0xFF, sizeof(mbtK_cell_pack_info_t));
1570 cell_info.running = true;
1571 cell_info.cell_list.num = 0;
1572
1573 err = at_send_command_singleline("AT+EEMGINFO?", "+EEMGINFO:", &response);
1574 if (err < 0 || response->success == 0 || !response->p_intermediates){
1575 *cme_err = at_get_cme_error(response);
1576 goto exit;
1577 }
1578
1579 // Now, cell infomation has get from URC message.
1580
1581 char *line = response->p_intermediates->line;
1582 err = at_tok_start(&line);
1583 if (err < 0)
1584 {
1585 goto exit;
1586 }
1587 err = at_tok_nextint(&line, &tmp_int);
1588 if (err < 0)
1589 {
1590 goto exit;
1591 }
1592 err = at_tok_nextint(&line, &tmp_int);
1593 if (err < 0)
1594 {
1595 goto exit;
1596 }
1597
1598 cell_info.cell_list.type = (uint8)tmp_int;
1599 cell_info.running = false;
1600
1601#if 0
1602 while(lines_ptr)
1603 {
1604 // LTE
1605 if(strStartsWith(line, "+EEMLTESVC:")) // LTE Server Cell
1606 {
1607
1608 }
1609 else if(strStartsWith(line, "+EEMLTEINTER:")) // LTE
1610 {
1611
1612 }
1613 else if(strStartsWith(line, "+EEMLTEINTRA:")) // LTE
1614 {
1615
1616 }
1617 else if(strStartsWith(line, "+EEMLTEINTERRAT:")) // LTE
1618 {
1619
1620 }
1621 else if(strStartsWith(line, "+EEMGINFO:")) // <state>: 0: ME in Idle mode 1: ME in Dedicated mode 2: ME in PS PTM mode 3: invalid state
1622 // <nw_type>: 0: GSM 1: UMTS 2: LTE
1623 {
1624
1625 }
1626 // WCDMA
1627 else if(strStartsWith(line, "+EEMUMTSSVC:")) // WCDMA Server Cell
1628 {
1629
1630 }
1631 else if(strStartsWith(line, "+EEMUMTSINTRA:")) // WCDMA
1632 {
1633
1634 }
1635 else if(strStartsWith(line, "+EEMUMTSINTERRAT:")) // WCDMA
1636 {
1637
1638 }
1639 // GSM
1640 else if(strStartsWith(line, "+EEMGINFOBASIC:")) // Basic information in GSM
1641 // 0: ME in Idle mode 1: ME in Dedicated mode 2: ME in PS PTM mode
1642 {
1643
1644 }
1645 else if(strStartsWith(line, "+EEMGINFOSVC:")) // GSM Server Cell
1646 {
1647
1648 }
1649 else if(strStartsWith(line, "+EEMGINFOPS:")) // PS
1650 {
1651
1652 }
1653
1654
1655 lines_ptr = lines_ptr->p_next;
1656 }
1657#endif
1658
1659exit:
1660 at_response_free(response);
1661 return buff_size;
1662}
1663
1664static int req_cell_info_set(const char *cmgl, char *reg, int len, int *cme_err)
1665{
1666 ATResponse *response = NULL;
1667 char cmd[30] = {0};
1668 char data[218] = {0};
1669 int err = 0;
1670
1671 memcpy(data, cmgl, len);
1672
1673 sprintf(cmd, "AT*CELL=%s", data);
1674
1675 if(strlen(cmd) > 0)
1676 {
1677 err = at_send_command_multiline(cmd, "", &response);
1678 if (err < 0 || response->success == 0 || !response->p_intermediates){
1679 *cme_err = at_get_cme_error(response);
1680 goto exit;
1681 }
1682
1683 ATLine* lines_ptr = response->p_intermediates;
1684 char *line = NULL;
1685 int reg_len = 0;
1686 bool flag = false;
1687 while(lines_ptr)
1688 {
1689 line = lines_ptr->line;
1690 if(line ==NULL)
1691 {
1692 LOGD("line is null----------------------");
1693 }
1694 lines_ptr = lines_ptr->p_next;
1695 }
1696 }
1697 err = 0;
1698 memcpy(reg, "req_cell_info_set succss", strlen("req_cell_info_set succss"));
1699exit:
1700 at_response_free(response);
1701 return err;
1702}
1703
1704
1705/*
b.liu87afc4c2024-08-14 17:33:45 +08001706AT+CGDCONT?
1707
1708+CGDCONT: 1,"IPV4V6","ctnet","10.142.64.116 254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1",0,0,0,2,0,0
1709
1710+CGDCONT: 8,"IPV4V6","IMS","254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1",0,0,0,2,1,1
1711
1712OK
1713
1714*/
b.liubcf86c92024-08-19 19:48:28 +08001715static int req_apn_get(bool get_def_cid, mbtk_apn_info_array_t *apns, int *cme_err)
b.liu87afc4c2024-08-14 17:33:45 +08001716{
1717 ATResponse *response = NULL;
1718 int err = at_send_command_multiline("AT+CGDCONT?", "+CGDCONT:", &response);
1719
1720 if (err < 0 || response->success == 0 || !response->p_intermediates){
1721 if(cme_err) {
1722 *cme_err = at_get_cme_error(response);
1723 }
1724 goto exit;
1725 }
1726
1727 ATLine* lines_ptr = response->p_intermediates;
1728 char *line = NULL;
1729 int tmp_int;
1730 char *tmp_str = NULL;
b.liubcf86c92024-08-19 19:48:28 +08001731 int cid_start;
1732 if(apn_conf_support(MBTK_RIL_CID_DEF)) {
1733 cid_start = MBTK_RIL_CID_DEF;
1734 } else {
1735 if(get_def_cid) {
1736 cid_start = MBTK_RIL_CID_DEF;
1737 } else {
1738 cid_start = MBTK_RIL_CID_2;
1739 }
1740 }
b.liu87afc4c2024-08-14 17:33:45 +08001741 /*
1742 <apn_num[1]><cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>...
1743 <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
1744 */
1745 while(lines_ptr)
1746 {
1747 line = lines_ptr->line;
1748 err = at_tok_start(&line);
1749 if (err < 0)
1750 {
1751 goto exit;
1752 }
1753
1754 err = at_tok_nextint(&line, &tmp_int); // cid
1755 if (err < 0)
1756 {
1757 goto exit;
1758 }
1759 // Only get CID 1-7
b.liubcf86c92024-08-19 19:48:28 +08001760 if(tmp_int >= cid_start && tmp_int <= MBTK_APN_CID_MAX) {
b.liu87afc4c2024-08-14 17:33:45 +08001761 apns->apns[apns->num].cid = (mbtk_ril_cid_enum)tmp_int;
1762
1763 err = at_tok_nextstr(&line, &tmp_str);// ip type
1764 if (err < 0)
1765 {
1766 goto exit;
1767 }
1768 if(!strcasecmp(tmp_str, "IP")) {
1769 apns->apns[apns->num].ip_type = MBTK_IP_TYPE_IP;
1770 } else if(!strcasecmp(tmp_str, "IPV6")) {
1771 apns->apns[apns->num].ip_type = MBTK_IP_TYPE_IPV6;
1772 } else if(!strcasecmp(tmp_str, "IPV4V6")) {
1773 apns->apns[apns->num].ip_type = MBTK_IP_TYPE_IPV4V6;
1774 } else {
1775 apns->apns[apns->num].ip_type = MBTK_IP_TYPE_PPP;
1776 }
1777
1778 err = at_tok_nextstr(&line, &tmp_str); // apn
1779 if (err < 0)
1780 {
1781 goto exit;
1782 }
1783 if(!str_empty(tmp_str)) {
1784 memcpy(apns->apns[apns->num].apn, tmp_str, strlen(tmp_str));
1785 }
1786
b.liu10a34102024-08-20 20:36:24 +08001787 // Get other arg from proc or file.
1788 apn_prop_get_by_cid_without_cgdcont(apns->apns[apns->num].cid, &(apns->apns[apns->num]));
1789
b.liu87afc4c2024-08-14 17:33:45 +08001790 apns->num++;
1791 }
1792
1793 lines_ptr = lines_ptr->p_next;
1794 }
1795
b.liu10a34102024-08-20 20:36:24 +08001796 char prop_name[128] = {0};
1797 char prop_data[1024] = {0};
1798 char def_cid[10] = {0};
1799 sprintf(def_cid, "%d", MBTK_RIL_CID_DEF);
1800
1801 if(property_get(MBTK_DEF_ROUTE_CID, prop_data, def_cid) > 0 && !str_empty(prop_data)) {
1802 apns->cid_for_def_route = (mbtk_ril_cid_enum)atoi(prop_data);
1803 }
1804 memset(prop_data, 0, sizeof(prop_data));
1805 if(property_get(MBTK_DEF_DNS_CID, prop_data, def_cid) > 0 && !str_empty(prop_data)) {
1806 apns->cid_for_def_dns = (mbtk_ril_cid_enum)atoi(prop_data);
1807 }
1808
b.liu87afc4c2024-08-14 17:33:45 +08001809 goto exit;
1810exit:
1811 at_response_free(response);
1812 return err;
1813}
1814
1815/*
1816AT+CGDCONT=1,"IPV4V6","cmnet"
1817OK
1818
1819AT*AUTHReq=1,1,marvell,123456
1820OK
1821
1822*/
1823static int req_apn_set(mbtk_apn_info_t *apn, int *cme_err)
1824{
1825 ATResponse *response = NULL;
1826 char cmd[400] = {0};
1827 int index = 0;
1828 int err = 0;
1829
1830 // Delete apn
1831 if(str_empty(apn->apn)) {
1832 sprintf(cmd, "AT+CGDCONT=%d", apn->cid);
1833 err = at_send_command(cmd, &response);
1834 if (err < 0 || response->success == 0){
1835 if(cme_err) {
1836 *cme_err = at_get_cme_error(response);
1837 }
1838 goto exit;
1839 }
1840 } else {
1841 index += sprintf(cmd, "AT+CGDCONT=%d,", apn->cid);
1842 switch(apn->ip_type) {
1843 case MBTK_IP_TYPE_IP: {
1844 index += sprintf(cmd + index,"\"IP\",");
1845 break;
1846 }
1847 case MBTK_IP_TYPE_IPV6: {
1848 index += sprintf(cmd + index,"\"IPV6\",");
1849 break;
1850 }
1851 case MBTK_IP_TYPE_IPV4V6: {
1852 index += sprintf(cmd + index,"\"IPV4V6\",");
1853 break;
1854 }
1855 default: {
1856 index += sprintf(cmd + index,"\"PPP\",");
1857 break;
1858 }
1859 }
1860 if(strlen(apn->apn) > 0) {
1861 index += sprintf(cmd + index,"\"%s\"", apn->apn);
1862 }
1863
1864 err = at_send_command(cmd, &response);
1865 if (err < 0 || response->success == 0){
1866 if(cme_err) {
1867 *cme_err = at_get_cme_error(response);
1868 }
1869 goto exit;
1870 }
1871
1872 if(!str_empty(apn->user) || !str_empty(apn->pass)) {
1873 at_response_free(response);
1874
1875 memset(cmd,0,400);
1876 int cmd_auth=0;
1877 if(apn->auth == MBTK_APN_AUTH_PROTO_NONE)
1878 cmd_auth = 0;
1879 else if(apn->auth == MBTK_APN_AUTH_PROTO_PAP)
1880 cmd_auth = 1;
1881 else if(apn->auth == MBTK_APN_AUTH_PROTO_CHAP)
1882 cmd_auth = 2;
1883 else
1884 goto exit;
1885
1886 sprintf(cmd, "AT*AUTHREQ=%d,%d,%s,%s",apn->cid,cmd_auth,apn->user,apn->pass);
1887 err = at_send_command(cmd, &response);
1888 if (err < 0 || response->success == 0){
1889 if(cme_err) {
1890 *cme_err = at_get_cme_error(response);
1891 }
1892 goto exit;
1893 }
1894 }
1895 }
1896
1897exit:
1898 at_response_free(response);
1899 return err;
1900}
1901
1902/*
1903AT+CGACT?
1904+CGACT: 1,1
1905+CGACT: 8,1
1906OK
1907
1908AT+CGACT=1,<cid>
1909OK
1910
1911*/
b.liubcf86c92024-08-19 19:48:28 +08001912static int req_data_call_start(mbtk_ril_cid_enum cid, bool def_route, bool as_dns,
1913 int retry_interval, int timeout, int *cme_err)
b.liu87afc4c2024-08-14 17:33:45 +08001914{
1915 ATResponse *response = NULL;
1916 char cmd[400] = {0};
1917 int err = 0;
b.liubcf86c92024-08-19 19:48:28 +08001918 memset(&cgact_wait, 0, sizeof(ril_cgact_wait_t));
1919 cgact_wait.waitting = true;
1920 cgact_wait.cid = cid;
1921 cgact_wait.act = true;
b.liu87afc4c2024-08-14 17:33:45 +08001922
1923 sprintf(cmd, "AT+CGACT=1,%d", cid);
1924 err = at_send_command(cmd, &response);
1925 if (err < 0 || response->success == 0){
1926 if(cme_err) {
1927 *cme_err = at_get_cme_error(response);
1928 }
1929 goto exit;
1930 }
1931
1932exit:
1933 at_response_free(response);
1934 return err;
1935}
1936
1937/*
1938AT+CGACT=0,<cid>
1939OK
1940
1941*/
1942static int req_data_call_stop(mbtk_ril_cid_enum cid, int timeout, int *cme_err)
1943{
1944 ATResponse *response = NULL;
1945 char cmd[400] = {0};
1946 int err = 0;
1947
b.liubcf86c92024-08-19 19:48:28 +08001948 memset(&cgact_wait, 0, sizeof(ril_cgact_wait_t));
1949 cgact_wait.waitting = true;
1950 cgact_wait.cid = cid;
1951 cgact_wait.act = false;
1952
b.liu87afc4c2024-08-14 17:33:45 +08001953 sprintf(cmd, "AT+CGACT=0,%d", cid);
1954 err = at_send_command(cmd, &response);
1955 if (err < 0 || response->success == 0){
1956 if(cme_err) {
1957 *cme_err = at_get_cme_error(response);
1958 }
1959 goto exit;
1960 }
1961
1962exit:
1963 at_response_free(response);
1964 return err;
1965}
1966
1967/*
1968AT+CGCONTRDP=1
1969+CGCONTRDP: 1,7,"cmnet-2.MNC000.MCC460.GPRS","10.255.74.26","","223.87.253.100","223.87.253.253","","",0,0
1970+CGCONTRDP: 1,7,"cmnet-2.MNC000.MCC460.GPRS","254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239","","36.9.128.98.32.0.0.2.0.0.0.0.0.0.0.1","36.9.128.98.32.0.0.2.0.0.0.0.0.0.0.2","","",0,0
1971
1972OK
1973
1974*/
1975static int req_data_call_state_get(mbtk_ril_cid_enum cid, mbtk_ip_info_t *ip_info, int *cme_err)
1976{
1977 ATResponse *response = NULL;
1978 char cmd[50] = {0};
1979 int err = 0;
1980
1981 sprintf(cmd, "AT+CGCONTRDP=%d", cid);
1982
1983 err = at_send_command_multiline(cmd, "+CGCONTRDP:", &response);
1984 if (err < 0 || response->success == 0 || !response->p_intermediates){
1985 *cme_err = at_get_cme_error(response);
1986 goto exit;
1987 }
1988 ATLine* lines_ptr = response->p_intermediates;
1989 char *line = NULL;
1990 int tmp_int;
1991 char *tmp_ptr = NULL;
1992 while(lines_ptr)
1993 {
1994 line = lines_ptr->line;
1995 err = at_tok_start(&line);
1996 if (err < 0)
1997 {
1998 goto exit;
1999 }
2000
2001 err = at_tok_nextint(&line, &tmp_int); // cid
2002 if (err < 0)
2003 {
2004 goto exit;
2005 }
2006 err = at_tok_nextint(&line, &tmp_int); // bearer_id
2007 if (err < 0)
2008 {
2009 goto exit;
2010 }
2011 err = at_tok_nextstr(&line, &tmp_ptr); // APN
2012 if (err < 0)
2013 {
2014 goto exit;
2015 }
2016
2017 err = at_tok_nextstr(&line, &tmp_ptr); // IP
2018 if (err < 0 || str_empty(tmp_ptr))
2019 {
2020 goto exit;
2021 }
2022 if(is_ipv4(tmp_ptr)) {
2023 if(inet_pton(AF_INET, tmp_ptr, &(ip_info->ipv4.IPAddr)) < 0) {
2024 LOGE("inet_pton() fail.");
2025 err = -1;
2026 goto exit;
2027 }
2028
2029 ip_info->ipv4.valid = true;
2030 //log_hex("IPv4", &(ipv4->IPAddr), sizeof(struct in_addr));
2031 } else {
2032 if(str_2_ipv6(tmp_ptr, &(ip_info->ipv6.IPV6Addr))) {
2033 LOGE("str_2_ipv6() fail.");
2034 err = -1;
2035 goto exit;
2036 }
2037
2038 ip_info->ipv6.valid = true;
2039 //log_hex("IPv6", &(ipv6->IPV6Addr), 16);
2040 }
2041
2042 err = at_tok_nextstr(&line, &tmp_ptr); // Gateway
2043 if (err < 0)
2044 {
2045 goto exit;
2046 }
2047 if(!str_empty(tmp_ptr)) { // No found gateway
2048 if(is_ipv4(tmp_ptr)) {
2049 if(inet_pton(AF_INET, tmp_ptr, &(ip_info->ipv4.GateWay)) < 0) {
2050 LOGE("inet_pton() fail.");
2051 err = -1;
2052 goto exit;
2053 }
2054
2055 //log_hex("IPv4", &(ipv4->GateWay), sizeof(struct in_addr));
2056 } else {
2057 if(str_2_ipv6(tmp_ptr, &(ip_info->ipv6.GateWay))) {
2058 LOGE("str_2_ipv6() fail.");
2059 err = -1;
2060 goto exit;
2061 }
2062
2063 //log_hex("IPv6", &(ipv6->GateWay), 16);
2064 }
2065 }
2066
2067 err = at_tok_nextstr(&line, &tmp_ptr); // prim_DNS
2068 if (err < 0)
2069 {
2070 goto exit;
2071 }
2072 if(!str_empty(tmp_ptr)) { // No found Primary DNS
2073 if(is_ipv4(tmp_ptr)) {
2074 if(inet_pton(AF_INET, tmp_ptr, &(ip_info->ipv4.PrimaryDNS)) < 0) {
2075 LOGE("inet_pton() fail.");
2076 err = -1;
2077 goto exit;
2078 }
2079
2080 //log_hex("IPv4", &(ipv4->PrimaryDNS), sizeof(struct in_addr));
2081 } else {
2082 if(str_2_ipv6(tmp_ptr, &(ip_info->ipv6.PrimaryDNS))) {
2083 LOGE("str_2_ipv6() fail.");
2084 err = -1;
2085 goto exit;
2086 }
2087
2088 //log_hex("IPv6", &(ipv6->PrimaryDNS), 16);
2089 }
2090 }
2091
2092 err = at_tok_nextstr(&line, &tmp_ptr); // sec_DNS
2093 if (err < 0)
2094 {
2095 goto exit;
2096 }
2097 if(!str_empty(tmp_ptr)) { // No found Secondary DNS
2098 if(is_ipv4(tmp_ptr)) {
2099 if(inet_pton(AF_INET, tmp_ptr, &(ip_info->ipv4.SecondaryDNS)) < 0) {
2100 LOGE("inet_pton() fail.");
2101 err = -1;
2102 goto exit;
2103 }
2104
2105 //log_hex("IPv4", &(ipv4->SecondaryDNS), sizeof(struct in_addr));
2106 } else {
2107 if(str_2_ipv6(tmp_ptr, &(ip_info->ipv6.SecondaryDNS))) {
2108 LOGE("str_2_ipv6() fail.");
2109 err = -1;
2110 goto exit;
2111 }
2112
2113 //log_hex("IPv6", &(ipv6->SecondaryDNS), 16);
2114 }
2115 }
2116
2117 lines_ptr = lines_ptr->p_next;
2118 }
2119
2120exit:
2121 at_response_free(response);
2122 return err;
2123}
2124
2125
2126//void net_list_free(void *data);
2127// Return MBTK_INFO_ERR_SUCCESS,will call pack_error_send() to send RSP.
2128// Otherwise, do not call pack_error_send().
2129mbtk_ril_err_enum net_pack_req_process(sock_cli_info_t* cli_info, ril_msg_pack_info_t* pack)
2130{
2131 mbtk_ril_err_enum err = MBTK_RIL_ERR_SUCCESS;
2132 int cme_err = MBTK_RIL_ERR_CME_NON;
2133 switch(pack->msg_id)
2134 {
2135 case RIL_MSG_ID_NET_AVAILABLE:
2136 {
2137 if(pack->data_len == 0 || pack->data == NULL)
2138 {
2139 mbtk_net_info_array_t net_array;
2140 memset(&net_array, 0, sizeof(mbtk_net_info_array_t));
2141 if(req_available_net_get(&net_array, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2142 {
2143 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2144 err = MBTK_RIL_ERR_CME + cme_err;
2145 } else {
2146 err = MBTK_RIL_ERR_UNKNOWN;
2147 }
2148 LOGD("Get Available Net fail.");
2149 }
2150 else
2151 {
2152 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &net_array, sizeof(mbtk_net_info_array_t));
2153 }
2154 }
2155 else // Set
2156 {
2157 err = MBTK_RIL_ERR_UNSUPPORTED;
2158 LOGW("Unsupport set available net.");
2159 }
2160 break;
2161 }
2162 case RIL_MSG_ID_NET_SEL_MODE:
2163 {
2164 if(pack->data_len == 0 || pack->data == NULL)
2165 {
2166 mbtk_net_info_t info;
2167 memset(&info, 0, sizeof(mbtk_net_info_t));
2168 if(req_net_sel_mode_get(&info, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2169 {
2170 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2171 err = MBTK_RIL_ERR_CME + cme_err;
2172 } else {
2173 err = MBTK_RIL_ERR_UNKNOWN;
2174 }
2175 LOGD("Get Net sel mode fail.");
2176 }
2177 else
2178 {
2179 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &info, sizeof(mbtk_net_info_t));
2180 }
2181 }
2182 else // Set
2183 {
2184 mbtk_net_info_t *info = (mbtk_net_info_t*)pack->data;
2185 if(req_net_sel_mode_set(info, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2186 {
2187 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2188 err = MBTK_RIL_ERR_CME + cme_err;
2189 } else {
2190 err = MBTK_RIL_ERR_UNKNOWN;
2191 }
2192 LOGD("Set Net sel mode fail.");
2193 }
2194 else
2195 {
2196 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, NULL, 0);
2197 }
2198 }
2199 break;
2200 }
2201 case RIL_MSG_ID_NET_BAND:
2202 {
2203 if(pack->data_len == 0 || pack->data == NULL)
2204 {
2205 err = MBTK_RIL_ERR_REQ_PARAMETER;
2206 LOG("No data found.");
2207 }
2208 else // Set
2209 {
2210 if(pack->data_len == sizeof(uint8)) {
2211 if(*(pack->data)) { // Get current bands.
2212 mbtk_band_info_t band;
2213 memset(&band, 0x0, sizeof(mbtk_band_info_t));
2214 if(req_band_get(&band, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2215 {
2216 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2217 err = MBTK_RIL_ERR_CME + cme_err;
2218 } else {
2219 err = MBTK_RIL_ERR_UNKNOWN;
2220 }
2221 LOG("Get net band fail.");
2222 }
2223 else
2224 {
2225 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &band, sizeof(mbtk_band_info_t));
2226 }
2227 } else { // Get support bands.
2228 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &band_info.band_support , sizeof(mbtk_band_info_t));
2229 }
2230 } else { // Set current bands.
2231 mbtk_band_info_t* band = (mbtk_band_info_t*)pack->data;
2232 if(pack->data_len != sizeof(mbtk_band_info_t))
2233 {
2234 err = MBTK_RIL_ERR_REQ_PARAMETER;
2235 LOG("Set net band error.");
2236 break;
2237 }
2238
2239 if(req_band_set(band, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2240 {
2241 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2242 err = MBTK_RIL_ERR_CME + cme_err;
2243 } else {
2244 err = MBTK_RIL_ERR_UNKNOWN;
2245 }
2246 LOG("Set net band fail.");
2247 }
2248 else
2249 {
2250 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, NULL, 0);
2251 }
2252 }
2253 }
2254 break;
2255 }
2256 case RIL_MSG_ID_NET_SIGNAL:
2257 {
2258 if(pack->data_len == 0 || pack->data == NULL)
2259 {
2260 mbtk_signal_info_t signal;
2261 memset(&signal, 0, sizeof(mbtk_signal_info_t));
2262 if(req_net_signal_get(&signal, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2263 {
2264 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2265 err = MBTK_RIL_ERR_CME + cme_err;
2266 } else {
2267 err = MBTK_RIL_ERR_UNKNOWN;
2268 }
2269 LOGD("Get net signal fail.");
2270 }
2271 else
2272 {
2273 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &signal, sizeof(mbtk_signal_info_t));
2274 }
2275 }
2276 else // Set
2277 {
2278 err = MBTK_RIL_ERR_UNSUPPORTED;
2279 LOGW("Unsupport set net signal.");
2280 }
2281 break;
2282 }
2283 case RIL_MSG_ID_NET_REG:
2284 {
2285 if(pack->data_len == 0 || pack->data == NULL)
2286 {
2287 mbtk_net_reg_info_t net_reg;
2288 memset(&net_reg, 0, sizeof(mbtk_net_reg_info_t));
2289 if(req_net_reg_get(&net_reg, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2290 {
2291 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2292 err = MBTK_RIL_ERR_CME + cme_err;
2293 } else {
2294 err = MBTK_RIL_ERR_UNKNOWN;
2295 }
2296 LOGD("Get Net reg info fail.");
2297 }
2298 else
2299 {
2300 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &net_reg, sizeof(mbtk_net_reg_info_t));
2301 }
2302 }
2303 else // Set
2304 {
2305 err = MBTK_RIL_ERR_UNSUPPORTED;
2306 LOGW("Unsupport set net reg info.");
2307 }
2308 break;
2309 }
2310 case RIL_MSG_ID_NET_CELL:
2311 {
b.liub4772072024-08-15 14:47:03 +08002312 if(pack->data_len == 0 || pack->data == NULL) // Get net cell.
b.liu87afc4c2024-08-14 17:33:45 +08002313 {
b.liub4772072024-08-15 14:47:03 +08002314 if(req_cell_info_get(&cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
b.liu87afc4c2024-08-14 17:33:45 +08002315 {
2316 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2317 err = MBTK_RIL_ERR_CME + cme_err;
2318 } else {
2319 err = MBTK_RIL_ERR_UNKNOWN;
2320 }
b.liub4772072024-08-15 14:47:03 +08002321 LOG("Get net cell fail.");
b.liu87afc4c2024-08-14 17:33:45 +08002322 }
2323 else
2324 {
b.liub4772072024-08-15 14:47:03 +08002325 LOG("req_cell_info_get() success,cell number: %d", cell_info.cell_list.num);
2326 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &cell_info.cell_list, sizeof(mbtk_cell_info_array_t));
b.liu87afc4c2024-08-14 17:33:45 +08002327 }
2328 }
b.liub4772072024-08-15 14:47:03 +08002329 else // Lock cell
b.liu87afc4c2024-08-14 17:33:45 +08002330 {
b.liub4772072024-08-15 14:47:03 +08002331 char *mem = (char*)(pack->data);
2332 int len = pack->data_len;
2333 char reg[100] = {0};
2334 if(req_cell_info_set(mem, reg, len, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2335 {
2336 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2337 err = MBTK_RIL_ERR_CME + cme_err;
2338 } else {
2339 err = MBTK_RIL_ERR_UNKNOWN;
2340 }
2341 }
2342 else
2343 {
2344 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, reg, strlen(reg));
2345 }
b.liu87afc4c2024-08-14 17:33:45 +08002346 }
2347 break;
2348 }
2349 case RIL_MSG_ID_NET_APN:
2350 {
2351 if(pack->data_len == 0 || pack->data == NULL)
2352 {
2353 mbtk_apn_info_array_t apns;
2354 memset(&apns, 0, sizeof(mbtk_apn_info_array_t));
b.liubcf86c92024-08-19 19:48:28 +08002355 if(req_apn_get(FALSE, &apns, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
b.liu87afc4c2024-08-14 17:33:45 +08002356 {
2357 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2358 err = MBTK_RIL_ERR_CME + cme_err;
2359 } else {
2360 err = MBTK_RIL_ERR_UNKNOWN;
2361 }
2362 LOGD("Get APN fail.");
2363 }
2364 else
2365 {
2366 LOGD("size - %d", sizeof(mbtk_apn_info_array_t));
2367 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &apns, sizeof(mbtk_apn_info_array_t));
2368 }
2369 }
2370 else // Set
2371 {
2372 mbtk_apn_info_t *apn = (mbtk_apn_info_t*)pack->data;
b.liubcf86c92024-08-19 19:48:28 +08002373 if(apn_check_and_cid_reset(apn)) {
b.liu87afc4c2024-08-14 17:33:45 +08002374 err = MBTK_RIL_ERR_CID;
2375 } else {
2376 if(apn_conf_support(apn->cid)) {
2377 if(req_apn_set(apn, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2378 {
2379 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2380 err = MBTK_RIL_ERR_CME + cme_err;
2381 } else {
2382 err = MBTK_RIL_ERR_UNKNOWN;
2383 }
2384 LOGD("Set APN fail.");
2385 }
2386 else
2387 {
2388 if(apn_prop_set(apn)) {
2389 LOGE("Save APN fail.");
2390 }
2391 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, NULL, 0);
2392 }
2393 } else {
2394 err = MBTK_RIL_ERR_UNSUPPORTED;
2395 LOGD("Can not set APN for CID : %d", apn->cid);
2396 }
2397 }
2398 }
2399 break;
2400 }
2401 case RIL_MSG_ID_NET_DATA_CALL:
2402 {
2403 if(pack->data_len == 0 || pack->data == NULL)
2404 {
2405 err = MBTK_RIL_ERR_UNSUPPORTED;
2406 }
2407 else // Set
2408 {
2409 mbtk_data_call_info_t *call_info = (mbtk_data_call_info_t*)pack->data;
b.liubcf86c92024-08-19 19:48:28 +08002410 if(!apn_conf_support(call_info->cid)) {
2411 err = MBTK_RIL_ERR_UNSUPPORTED;
2412 LOGD("Can not data call for CID : %d", call_info->cid);
2413 } else {
2414 if(call_info->type == MBTK_DATA_CALL_START) {
2415 mbtk_ip_info_t ip_info;
2416 memset(&ip_info, 0, sizeof(ip_info));
2417#if 0
2418 if(apn_prop_reset(call_info)) {
2419 err = MBTK_RIL_ERR_REQ_UNKNOWN;
2420 LOG("apn_prop_reset() fail.");
2421 } else
2422#else
2423 if(apn_prop_reset(call_info)) {
2424 LOG("apn_prop_reset() fail.");
2425 }
2426#endif
2427 {
2428 if(req_data_call_start(call_info->cid, call_info->def_route, call_info->as_dns,
2429 call_info->retry_interval, call_info->timeout, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2430 {
2431 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2432 err = MBTK_RIL_ERR_CME + cme_err;
2433 } else {
2434 err = MBTK_RIL_ERR_UNKNOWN;
2435 }
2436 LOGD("Start data call fail.");
2437 }
2438 else
2439 {
2440 // Wait for "CONNECT" or "+CGEV:"
2441 if(wait_cgact_complete(call_info->timeout)) { // Timeout
2442 err = MBTK_RIL_ERR_TIMEOUT;
2443 break;
2444 }
2445
2446 // Get Ip informations.
2447 cme_err = MBTK_RIL_ERR_CME_NON;
2448 if(req_data_call_state_get(call_info->cid ,&ip_info, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2449 {
2450 LOGD("Get net informations fail.");
2451 err = MBTK_RIL_ERR_NET_CONF;
2452 }
2453 else
2454 {
2455 // Config network informations.
2456 if(net_ifc_reconfig(call_info->cid, call_info->def_route, call_info->as_dns, &ip_info)) {
2457 err = MBTK_RIL_ERR_NET_CONF;
2458 break;
2459 }
2460
2461 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &ip_info, sizeof(mbtk_ip_info_t));
2462 }
2463 }
2464 }
2465 } else if(call_info->type == MBTK_DATA_CALL_STOP) {
2466 if(req_data_call_stop(call_info->cid, call_info->timeout, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
b.liu87afc4c2024-08-14 17:33:45 +08002467 {
2468 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2469 err = MBTK_RIL_ERR_CME + cme_err;
2470 } else {
2471 err = MBTK_RIL_ERR_UNKNOWN;
2472 }
b.liubcf86c92024-08-19 19:48:28 +08002473 LOGD("Stop data call fail.");
2474 }
2475 else
2476 {
2477 // Wait for "CONNECT" or "+CGEV:"
2478 if(wait_cgact_complete(call_info->timeout)) { // Timeout
2479 err = MBTK_RIL_ERR_TIMEOUT;
2480 break;
2481 }
2482
2483 // Clean network config.
2484 if(net_ifc_config(call_info->cid, FALSE, FALSE, NULL)) {
2485 err = MBTK_RIL_ERR_NET_CONF;
2486 break;
2487 }
2488
2489 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, NULL, 0);
2490 }
2491 } else {
2492 mbtk_ip_info_t ip_info;
2493 memset(&ip_info, 0, sizeof(ip_info));
2494 if(req_data_call_state_get(call_info->cid ,&ip_info, &cme_err) || cme_err != MBTK_RIL_ERR_CME_NON)
2495 {
2496 if(cme_err != MBTK_RIL_ERR_CME_NON) {
2497 err = MBTK_RIL_ERR_CME + cme_err;
2498 } else {
2499 err = MBTK_RIL_ERR_UNKNOWN;
2500 }
2501 LOGD("Get data call state fail.");
b.liu87afc4c2024-08-14 17:33:45 +08002502 }
2503 else
2504 {
2505 ril_rsp_pack_send(cli_info->fd, pack->msg_id, pack->msg_index, &ip_info, sizeof(mbtk_ip_info_t));
2506 }
2507 }
b.liu87afc4c2024-08-14 17:33:45 +08002508 }
2509 }
2510 break;
2511 }
2512 default:
2513 {
2514 err = MBTK_RIL_ERR_REQ_UNKNOWN;
2515 LOG("Unknown request : %s", id2str(pack->msg_id));
2516 break;
2517 }
2518 }
2519
2520 return err;
2521}
2522