1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun @file atc.c
3*4882a593Smuzhiyun @brief at command.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun DESCRIPTION
6*4882a593Smuzhiyun Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun INITIALIZATION AND SEQUENCING REQUIREMENTS
9*4882a593Smuzhiyun None.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun ---------------------------------------------------------------------------
12*4882a593Smuzhiyun Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
13*4882a593Smuzhiyun Quectel Wireless Solution Proprietary and Confidential.
14*4882a593Smuzhiyun ---------------------------------------------------------------------------
15*4882a593Smuzhiyun ******************************************************************************/
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <stdlib.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <ctype.h>
21*4882a593Smuzhiyun #include <fcntl.h>
22*4882a593Smuzhiyun #include <stddef.h>
23*4882a593Smuzhiyun #include <pthread.h>
24*4882a593Smuzhiyun #include <errno.h>
25*4882a593Smuzhiyun #include <time.h>
26*4882a593Smuzhiyun #include <signal.h>
27*4882a593Smuzhiyun #include <getopt.h>
28*4882a593Smuzhiyun #include <poll.h>
29*4882a593Smuzhiyun #include <sys/time.h>
30*4882a593Smuzhiyun #include <endian.h>
31*4882a593Smuzhiyun #include <time.h>
32*4882a593Smuzhiyun #include <sys/types.h>
33*4882a593Smuzhiyun #include <limits.h>
34*4882a593Smuzhiyun #include <inttypes.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun extern int asprintf(char **s, const char *fmt, ...);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #include "QMIThread.h"
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #include "atchannel.h"
41*4882a593Smuzhiyun #include "at_tok.h"
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun static int asr_style_atc = 0;
44*4882a593Smuzhiyun #define safe_free(__x) do { if (__x) { free((void *)__x); __x = NULL;}} while(0)
45*4882a593Smuzhiyun #define safe_at_response_free(__x) { if (__x) { at_response_free(__x); __x = NULL;}}
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define at_response_error(err, p_response) \
48*4882a593Smuzhiyun (err \
49*4882a593Smuzhiyun || p_response == NULL \
50*4882a593Smuzhiyun || p_response->finalResponse == NULL \
51*4882a593Smuzhiyun || p_response->success == 0)
52*4882a593Smuzhiyun
atc_init(PROFILE_T * profile)53*4882a593Smuzhiyun static int atc_init(PROFILE_T *profile) {
54*4882a593Smuzhiyun int err;
55*4882a593Smuzhiyun ATResponse *p_response = NULL;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun (void)profile;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun err = at_handshake();
60*4882a593Smuzhiyun if (err) {
61*4882a593Smuzhiyun dbg_time("handshake fail, TODO ... ");
62*4882a593Smuzhiyun goto exit;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun at_send_command("AT+QCFG=\"NAT\",1", NULL);
66*4882a593Smuzhiyun at_send_command_singleline("AT+QCFG=\"usbnet\"", "+QCFG:", NULL);
67*4882a593Smuzhiyun at_send_command_multiline("AT+QNETDEVCTL=?", "+QNETDEVCTL:", NULL);
68*4882a593Smuzhiyun at_send_command("AT+CGREG=2", NULL);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun err = at_send_command_singleline("AT+QNETDEVSTATUS=?", "+QNETDEVSTATUS:", &p_response);
71*4882a593Smuzhiyun if (at_response_error(err, p_response))
72*4882a593Smuzhiyun asr_style_atc = 1; //EC200T/EC100Y do not support this AT, but RG801/RG500U support
73*4882a593Smuzhiyun safe_at_response_free(p_response);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun exit:
76*4882a593Smuzhiyun return err;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
atc_deinit(void)79*4882a593Smuzhiyun static int atc_deinit(void) {
80*4882a593Smuzhiyun return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /**
84*4882a593Smuzhiyun * Called by atchannel when an unsolicited line appears
85*4882a593Smuzhiyun * This is called on atchannel's reader thread. AT commands may
86*4882a593Smuzhiyun * not be issued here
87*4882a593Smuzhiyun */
onUnsolicited(const char * s,const char * sms_pdu)88*4882a593Smuzhiyun static void onUnsolicited (const char *s, const char *sms_pdu)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun (void)sms_pdu;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (strStartsWith(s, "+QNETDEVSTATUS:")) {
93*4882a593Smuzhiyun qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun else if (strStartsWith(s, "+CGREG:") || strStartsWith(s, "+C5GREG:")) {
96*4882a593Smuzhiyun qmidevice_send_event_to_main(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
atc_read_thread(void * param)100*4882a593Smuzhiyun static void * atc_read_thread(void *param) {
101*4882a593Smuzhiyun PROFILE_T *profile = (PROFILE_T *)param;
102*4882a593Smuzhiyun const char *cdc_wdm = (const char *)profile->qmichannel;
103*4882a593Smuzhiyun int wait_for_request_quit = 0;
104*4882a593Smuzhiyun int atc_fd;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun atc_fd = cm_open_dev(cdc_wdm);
107*4882a593Smuzhiyun if (atc_fd <= 0) {
108*4882a593Smuzhiyun dbg_time("fail to open (%s), errno: %d (%s)", cdc_wdm, errno, strerror(errno));
109*4882a593Smuzhiyun goto __quit;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun dbg_time("atc_fd = %d", atc_fd);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (at_open(atc_fd, onUnsolicited))
115*4882a593Smuzhiyun goto __quit;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun while (atc_fd > 0) {
120*4882a593Smuzhiyun struct pollfd pollfds[] = {{atc_fd, POLLIN, 0}, {qmidevice_control_fd[1], POLLIN, 0}};
121*4882a593Smuzhiyun int ne, ret, nevents = 2;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun ret = poll(pollfds, nevents, wait_for_request_quit ? 1000 : -1);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (ret == 0 && wait_for_request_quit) {
126*4882a593Smuzhiyun break;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun if (ret < 0) {
130*4882a593Smuzhiyun dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun for (ne = 0; ne < nevents; ne++) {
135*4882a593Smuzhiyun int fd = pollfds[ne].fd;
136*4882a593Smuzhiyun short revents = pollfds[ne].revents;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
139*4882a593Smuzhiyun dbg_time("%s poll err/hup/inval", __func__);
140*4882a593Smuzhiyun dbg_time("epoll fd = %d, events = 0x%04x", fd, revents);
141*4882a593Smuzhiyun if (revents & (POLLERR | POLLHUP | POLLNVAL))
142*4882a593Smuzhiyun goto __quit;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if ((revents & POLLIN) == 0)
146*4882a593Smuzhiyun continue;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (atc_fd == fd) {
149*4882a593Smuzhiyun usleep(10*1000); //let atchannel.c read at response.
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun else if (fd == qmidevice_control_fd[1]) {
152*4882a593Smuzhiyun int triger_event;
153*4882a593Smuzhiyun if (read(fd, &triger_event, sizeof(triger_event)) == sizeof(triger_event)) {
154*4882a593Smuzhiyun //dbg_time("triger_event = 0x%x", triger_event);
155*4882a593Smuzhiyun switch (triger_event) {
156*4882a593Smuzhiyun case RIL_REQUEST_QUIT:
157*4882a593Smuzhiyun goto __quit;
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun case SIG_EVENT_STOP:
160*4882a593Smuzhiyun wait_for_request_quit = 1;
161*4882a593Smuzhiyun break;
162*4882a593Smuzhiyun default:
163*4882a593Smuzhiyun break;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun __quit:
171*4882a593Smuzhiyun at_close();
172*4882a593Smuzhiyun qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
173*4882a593Smuzhiyun dbg_time("%s exit", __func__);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun return NULL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun const struct qmi_device_ops atc_dev_ops = {
179*4882a593Smuzhiyun .init = atc_init,
180*4882a593Smuzhiyun .deinit = atc_deinit,
181*4882a593Smuzhiyun .read = atc_read_thread,
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun
requestBaseBandVersion(PROFILE_T * profile)184*4882a593Smuzhiyun static int requestBaseBandVersion(PROFILE_T *profile) {
185*4882a593Smuzhiyun int err;
186*4882a593Smuzhiyun ATResponse *p_response = NULL;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun (void)profile;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun err = at_send_command_singleline("AT+CGMR", "\0", &p_response);
191*4882a593Smuzhiyun if (at_response_error(err, p_response))
192*4882a593Smuzhiyun goto exit;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun exit:
195*4882a593Smuzhiyun safe_at_response_free(p_response);
196*4882a593Smuzhiyun return err;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
requestGetSIMStatus(SIM_Status * pSIMStatus)199*4882a593Smuzhiyun static int requestGetSIMStatus(SIM_Status *pSIMStatus)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun int err;
202*4882a593Smuzhiyun ATResponse *p_response = NULL;
203*4882a593Smuzhiyun char *cpinLine;
204*4882a593Smuzhiyun char *cpinResult;
205*4882a593Smuzhiyun int ret = SIM_NOT_READY;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &p_response);
208*4882a593Smuzhiyun if (at_response_error(err, p_response))
209*4882a593Smuzhiyun goto done;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun switch (at_get_cme_error(p_response))
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun case CME_SUCCESS:
214*4882a593Smuzhiyun break;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun case CME_SIM_NOT_INSERTED:
217*4882a593Smuzhiyun case CME_OPERATION_NOT_ALLOWED:
218*4882a593Smuzhiyun case CME_FAILURE:
219*4882a593Smuzhiyun ret = SIM_ABSENT;
220*4882a593Smuzhiyun goto done;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun default:
223*4882a593Smuzhiyun ret = SIM_NOT_READY;
224*4882a593Smuzhiyun goto done;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun cpinLine = p_response->p_intermediates->line;
228*4882a593Smuzhiyun err = at_tok_start (&cpinLine);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (err < 0)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun ret = SIM_NOT_READY;
233*4882a593Smuzhiyun goto done;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun err = at_tok_nextstr(&cpinLine, &cpinResult);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (err < 0)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun ret = SIM_NOT_READY;
241*4882a593Smuzhiyun goto done;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (0 == strcmp (cpinResult, "SIM PIN"))
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun ret = SIM_PIN;
247*4882a593Smuzhiyun goto done;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun else if (0 == strcmp (cpinResult, "SIM PUK"))
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun ret = SIM_PUK;
252*4882a593Smuzhiyun goto done;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun else if (0 == strcmp (cpinResult, "PH-NET PIN"))
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun return SIM_NETWORK_PERSONALIZATION;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun else if (0 != strcmp (cpinResult, "READY"))
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun /* we're treating unsupported lock types as "sim absent" */
261*4882a593Smuzhiyun ret = SIM_ABSENT;
262*4882a593Smuzhiyun goto done;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun ret = SIM_READY;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun done:
268*4882a593Smuzhiyun safe_at_response_free(p_response);
269*4882a593Smuzhiyun *pSIMStatus = ret;
270*4882a593Smuzhiyun return err;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
requestRegistrationState(UCHAR * pPSAttachedState)273*4882a593Smuzhiyun static int requestRegistrationState(UCHAR *pPSAttachedState) {
274*4882a593Smuzhiyun int err;
275*4882a593Smuzhiyun ATResponse *p_response = NULL;
276*4882a593Smuzhiyun ATLine *p_cur;
277*4882a593Smuzhiyun int i;
278*4882a593Smuzhiyun int cops_atc = -1;
279*4882a593Smuzhiyun char *response[3] = {NULL, NULL, NULL};
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun *pPSAttachedState = 0;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun err = at_send_command_multiline(
284*4882a593Smuzhiyun "AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?",
285*4882a593Smuzhiyun "+COPS:", &p_response);
286*4882a593Smuzhiyun if (at_response_error(err, p_response))
287*4882a593Smuzhiyun goto error;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun for ( i = 0, p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next, i++) {
290*4882a593Smuzhiyun int skip;
291*4882a593Smuzhiyun char *line = p_cur->line;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun err = at_tok_start(&line);
294*4882a593Smuzhiyun if (err < 0) goto error;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun err = at_tok_nextint(&line, &skip);
297*4882a593Smuzhiyun if (err < 0) goto error;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (!at_tok_hasmore(&line))
300*4882a593Smuzhiyun continue;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun err = at_tok_nextint(&line, &skip);
303*4882a593Smuzhiyun if (err < 0) goto error;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (!at_tok_hasmore(&line))
306*4882a593Smuzhiyun continue;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun err = at_tok_nextstr(&line, &(response[i]));
309*4882a593Smuzhiyun if (err < 0) goto error;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (!at_tok_hasmore(&line))
312*4882a593Smuzhiyun continue;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun err = at_tok_nextint(&line, &cops_atc);
315*4882a593Smuzhiyun if (err < 0) goto error;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (cops_atc != -1) {
319*4882a593Smuzhiyun *pPSAttachedState = 1;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun error:
323*4882a593Smuzhiyun safe_at_response_free(p_response);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun return err;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
requestSetupDataCall(PROFILE_T * profile,int curIpFamily)328*4882a593Smuzhiyun static int requestSetupDataCall(PROFILE_T *profile, int curIpFamily) {
329*4882a593Smuzhiyun int err;
330*4882a593Smuzhiyun ATResponse *p_response = NULL;
331*4882a593Smuzhiyun char *cmd = NULL;
332*4882a593Smuzhiyun ATLine *p_cur = NULL;
333*4882a593Smuzhiyun char *line = NULL;
334*4882a593Smuzhiyun int pdp = profile->pdp;
335*4882a593Smuzhiyun int state = 0;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun (void)curIpFamily;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (asr_style_atc) {
340*4882a593Smuzhiyun err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &p_response);
341*4882a593Smuzhiyun if (at_response_error(err, p_response))
342*4882a593Smuzhiyun goto _error;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next) {
345*4882a593Smuzhiyun int cid = 0;
346*4882a593Smuzhiyun line = p_cur->line;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun err = at_tok_start(&line);
349*4882a593Smuzhiyun if (err < 0) goto _error;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun err = at_tok_nextint(&line, &cid);
352*4882a593Smuzhiyun if (err < 0) goto _error;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if (cid != pdp)
355*4882a593Smuzhiyun continue;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun err = at_tok_nextint(&line, &state);
358*4882a593Smuzhiyun if (err < 0) goto _error;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun safe_at_response_free(p_response);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (state == 0) {
363*4882a593Smuzhiyun asprintf(&cmd, "AT+CGACT=1,%d", pdp);
364*4882a593Smuzhiyun err = at_send_command(cmd, &p_response);
365*4882a593Smuzhiyun safe_free(cmd);
366*4882a593Smuzhiyun if (at_response_error(err, p_response))
367*4882a593Smuzhiyun goto _error;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if(asr_style_atc)
372*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVCTL=1,%d,%d", pdp, 1);
373*4882a593Smuzhiyun else
374*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVCTL=%d,1,%d", pdp, 0);
375*4882a593Smuzhiyun err = at_send_command(cmd, &p_response);
376*4882a593Smuzhiyun safe_free(cmd);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun if (at_response_error(err, p_response))
379*4882a593Smuzhiyun goto _error;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (!asr_style_atc) { //TODO some modems do not sync return setup call resule
382*4882a593Smuzhiyun int t = 0;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVSTATUS=%d", pdp);
385*4882a593Smuzhiyun while (t++ < 30) {
386*4882a593Smuzhiyun err = at_send_command_singleline(cmd, "+QNETDEVSTATUS", &p_response);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun if (!at_response_error(err, p_response)) {
389*4882a593Smuzhiyun safe_at_response_free(p_response);
390*4882a593Smuzhiyun break;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun safe_at_response_free(p_response);
393*4882a593Smuzhiyun sleep(1);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun safe_free(cmd);
396*4882a593Smuzhiyun if (t > 15)
397*4882a593Smuzhiyun goto _error;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun //some modem do not report URC
400*4882a593Smuzhiyun qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED);
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun _error:
403*4882a593Smuzhiyun safe_at_response_free(p_response);
404*4882a593Smuzhiyun dbg_time("%s err=%d", __func__, err);
405*4882a593Smuzhiyun return err;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
at_netdevstatus(int pdp,unsigned int * pV4Addr)408*4882a593Smuzhiyun static int at_netdevstatus(int pdp, unsigned int *pV4Addr) {
409*4882a593Smuzhiyun int err;
410*4882a593Smuzhiyun ATResponse *p_response = NULL;
411*4882a593Smuzhiyun char *cmd = NULL;
412*4882a593Smuzhiyun char *line;
413*4882a593Smuzhiyun char *ipv4 = NULL;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun *pV4Addr = 0;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVSTATUS=%d", pdp);
418*4882a593Smuzhiyun err = at_send_command_singleline(cmd, "+QNETDEVSTATUS", &p_response);
419*4882a593Smuzhiyun safe_free(cmd);
420*4882a593Smuzhiyun if (at_response_error(err, p_response))
421*4882a593Smuzhiyun goto _error;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun line = p_response->p_intermediates->line;
424*4882a593Smuzhiyun err = at_tok_start(&line);
425*4882a593Smuzhiyun if (err < 0)
426*4882a593Smuzhiyun goto _error;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun err = at_tok_nextstr(&line, &ipv4);
429*4882a593Smuzhiyun if (err < 0) goto _error;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (ipv4) {
432*4882a593Smuzhiyun int addr[4] = {0, 0, 0, 0};
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun sscanf(ipv4, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]);
435*4882a593Smuzhiyun *pV4Addr = (addr[0]) | (addr[1]<<8) | (addr[2]<<16) | (addr[3]<<24);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun _error:
439*4882a593Smuzhiyun return err;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
requestQueryDataCall(UCHAR * pConnectionStatus,int curIpFamily)442*4882a593Smuzhiyun static int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily) {
443*4882a593Smuzhiyun int err;
444*4882a593Smuzhiyun ATResponse *p_response = NULL;
445*4882a593Smuzhiyun ATLine *p_cur = NULL;
446*4882a593Smuzhiyun char *line = NULL;
447*4882a593Smuzhiyun int state = 0;
448*4882a593Smuzhiyun int bind = 0;
449*4882a593Smuzhiyun int cid;
450*4882a593Smuzhiyun int pdp = 1;
451*4882a593Smuzhiyun unsigned int v4Addr = 0;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun (void)curIpFamily;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if (asr_style_atc)
458*4882a593Smuzhiyun goto _asr_style_atc;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun err = at_netdevstatus(pdp, &v4Addr);
461*4882a593Smuzhiyun if (!err && v4Addr) {
462*4882a593Smuzhiyun *pConnectionStatus = QWDS_PKT_DATA_CONNECTED;
463*4882a593Smuzhiyun //if (profile->ipv4.Address == 0) {} //TODO
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun goto _error;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun _asr_style_atc:
468*4882a593Smuzhiyun err = at_send_command_multiline("AT+QNETDEVCTL?", "+QNETDEVCTL:", &p_response);
469*4882a593Smuzhiyun if (at_response_error(err, p_response))
470*4882a593Smuzhiyun goto _error;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun int tmp;
475*4882a593Smuzhiyun //+QNETDECTL:<op>,<cid>,<urc_en>,<state>
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun line = p_cur->line;
478*4882a593Smuzhiyun err = at_tok_start(&line);
479*4882a593Smuzhiyun if (err < 0)
480*4882a593Smuzhiyun goto _error;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun err = at_tok_nextint(&line, &bind);
483*4882a593Smuzhiyun if (err < 0)
484*4882a593Smuzhiyun goto _error;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun err = at_tok_nextint(&line, &cid);
487*4882a593Smuzhiyun if (err < 0)
488*4882a593Smuzhiyun goto _error;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (cid != pdp)
491*4882a593Smuzhiyun continue;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun err = at_tok_nextint(&line, &tmp);
494*4882a593Smuzhiyun if(err < 0)
495*4882a593Smuzhiyun goto _error;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun err = at_tok_nextint(&line, &state);
498*4882a593Smuzhiyun if(err < 0)
499*4882a593Smuzhiyun goto _error;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun safe_at_response_free(p_response);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (bind == 0 || state == 0)
504*4882a593Smuzhiyun goto _error;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun err = at_send_command_multiline("AT+CGACT?", "+CGACT:", &p_response);
507*4882a593Smuzhiyun if (at_response_error(err, p_response))
508*4882a593Smuzhiyun goto _error;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun line = p_cur->line;
513*4882a593Smuzhiyun err = at_tok_start(&line);
514*4882a593Smuzhiyun if (err < 0)
515*4882a593Smuzhiyun goto _error;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun err = at_tok_nextint(&line, &cid);
518*4882a593Smuzhiyun if (err < 0)
519*4882a593Smuzhiyun goto _error;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun if (cid != pdp)
522*4882a593Smuzhiyun continue;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun err = at_tok_nextint(&line, &state);
525*4882a593Smuzhiyun if (err < 0)
526*4882a593Smuzhiyun goto _error;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun safe_at_response_free(p_response);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if (bind && state)
531*4882a593Smuzhiyun *pConnectionStatus = QWDS_PKT_DATA_CONNECTED;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun _error:
534*4882a593Smuzhiyun safe_at_response_free(p_response);
535*4882a593Smuzhiyun dbg_time("%s err=%d, call_state=%d", __func__, err, *pConnectionStatus);
536*4882a593Smuzhiyun return err;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
requestDeactivateDefaultPDP(PROFILE_T * profile,int curIpFamily)539*4882a593Smuzhiyun static int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily) {
540*4882a593Smuzhiyun int err;
541*4882a593Smuzhiyun char *cmd = NULL;
542*4882a593Smuzhiyun int pdp = profile->pdp;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun (void)curIpFamily;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun if (asr_style_atc)
547*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVCTL=0,%d,%d", pdp, 0);
548*4882a593Smuzhiyun else
549*4882a593Smuzhiyun asprintf(&cmd, "AT+QNETDEVCTL=%d,0,%d", pdp, 0);
550*4882a593Smuzhiyun err = at_send_command(cmd, NULL);
551*4882a593Smuzhiyun safe_free(cmd);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun dbg_time("%s err=%d", __func__, err);
554*4882a593Smuzhiyun return err;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
requestGetIPAddress(PROFILE_T * profile,int curIpFamily)557*4882a593Smuzhiyun static int requestGetIPAddress(PROFILE_T *profile, int curIpFamily) {
558*4882a593Smuzhiyun int err;
559*4882a593Smuzhiyun ATResponse *p_response = NULL;
560*4882a593Smuzhiyun char *cmd = NULL;
561*4882a593Smuzhiyun ATLine *p_cur = NULL;
562*4882a593Smuzhiyun char *line = NULL;
563*4882a593Smuzhiyun int pdp = profile->pdp;
564*4882a593Smuzhiyun unsigned int v4Addr = 0;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun (void)curIpFamily;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (asr_style_atc)
569*4882a593Smuzhiyun goto _asr_style_atc;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun err = at_netdevstatus(pdp, &v4Addr);
572*4882a593Smuzhiyun if (err < 0) goto _error;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun goto _error;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun _asr_style_atc:
577*4882a593Smuzhiyun asprintf(&cmd, "AT+CGPADDR=%d", profile->pdp);
578*4882a593Smuzhiyun err = at_send_command_singleline(cmd, "+CGPADDR:", &p_response);
579*4882a593Smuzhiyun safe_free(cmd);
580*4882a593Smuzhiyun if (at_response_error(err, p_response))
581*4882a593Smuzhiyun goto _error;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun //+CGPADDR: 1,"10.201.80.91","2409:8930:4B3:41C7:F9B8:3D9B:A2F7:CA96"
584*4882a593Smuzhiyun for (p_cur = p_response->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun char *ipv4 = NULL;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun line = p_cur->line;
589*4882a593Smuzhiyun err = at_tok_start(&line);
590*4882a593Smuzhiyun if (err < 0)
591*4882a593Smuzhiyun goto _error;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun err = at_tok_nextint(&line, &pdp);
594*4882a593Smuzhiyun if (err < 0)
595*4882a593Smuzhiyun goto _error;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (pdp != profile->pdp)
598*4882a593Smuzhiyun continue;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun if (!at_tok_hasmore(&line))
601*4882a593Smuzhiyun continue;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun err = at_tok_nextstr(&line, &ipv4);
604*4882a593Smuzhiyun if (err < 0) goto _error;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun if (ipv4) {
607*4882a593Smuzhiyun int addr[4] = {0, 0, 0, 0};
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun sscanf(ipv4, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]);
610*4882a593Smuzhiyun v4Addr = (addr[0]) | (addr[1]<<8) | (addr[2]<<16) | (addr[3]<<24);
611*4882a593Smuzhiyun break;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun _error:
616*4882a593Smuzhiyun if (!v4Addr && !err) {
617*4882a593Smuzhiyun err = -1;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun if (profile->ipv4.Address != v4Addr) {
620*4882a593Smuzhiyun profile->ipv4.Address = v4Addr;
621*4882a593Smuzhiyun if (v4Addr) {
622*4882a593Smuzhiyun unsigned char *v4 = (unsigned char *)&v4Addr;
623*4882a593Smuzhiyun dbg_time("%s %d.%d.%d.%d", __func__, v4[0], v4[1], v4[2], v4[3]);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun dbg_time("%s err=%d", __func__, err);
628*4882a593Smuzhiyun return err;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
requestGetICCID(void)631*4882a593Smuzhiyun static int requestGetICCID(void) {
632*4882a593Smuzhiyun int err;
633*4882a593Smuzhiyun ATResponse *p_response = NULL;
634*4882a593Smuzhiyun char *line;
635*4882a593Smuzhiyun char *iccid;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun err = at_send_command_singleline("AT+QCCID", "+QCCID:", &p_response);
638*4882a593Smuzhiyun if (at_response_error(err, p_response))
639*4882a593Smuzhiyun goto _error;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun line = p_response->p_intermediates->line;
642*4882a593Smuzhiyun err = at_tok_start(&line);
643*4882a593Smuzhiyun if (err < 0)
644*4882a593Smuzhiyun goto _error;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun err = at_tok_nextstr(&line, &iccid);
647*4882a593Smuzhiyun if (err < 0)
648*4882a593Smuzhiyun goto _error;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun dbg_time("%s %s", __func__, iccid);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun _error:
653*4882a593Smuzhiyun safe_at_response_free(p_response);
654*4882a593Smuzhiyun return err;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
requestGetIMSI(void)657*4882a593Smuzhiyun static int requestGetIMSI(void) {
658*4882a593Smuzhiyun int err;
659*4882a593Smuzhiyun ATResponse *p_response = NULL;
660*4882a593Smuzhiyun char *imsi;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun err = at_send_command_numeric("AT+CIMI", &p_response);
663*4882a593Smuzhiyun if (at_response_error(err, p_response))
664*4882a593Smuzhiyun goto exit;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun imsi = p_response->p_intermediates->line;
667*4882a593Smuzhiyun if (imsi) {
668*4882a593Smuzhiyun dbg_time("%s %s", __func__, imsi);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun exit:
672*4882a593Smuzhiyun safe_at_response_free(p_response);
673*4882a593Smuzhiyun return err;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun const struct request_ops atc_request_ops = {
677*4882a593Smuzhiyun .requestBaseBandVersion = requestBaseBandVersion,
678*4882a593Smuzhiyun .requestGetSIMStatus = requestGetSIMStatus,
679*4882a593Smuzhiyun .requestRegistrationState = requestRegistrationState,
680*4882a593Smuzhiyun .requestSetupDataCall = requestSetupDataCall,
681*4882a593Smuzhiyun .requestQueryDataCall = requestQueryDataCall,
682*4882a593Smuzhiyun .requestDeactivateDefaultPDP = requestDeactivateDefaultPDP,
683*4882a593Smuzhiyun .requestGetIPAddress = requestGetIPAddress,
684*4882a593Smuzhiyun .requestGetICCID = requestGetICCID,
685*4882a593Smuzhiyun .requestGetIMSI = requestGetIMSI,
686*4882a593Smuzhiyun };
687*4882a593Smuzhiyun
688