xref: /OK3568_Linux_fs/app/forlinx/quectelCM/main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /******************************************************************************
2   @file    main.c
3   @brief   The entry program.
4 
5   DESCRIPTION
6   Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7 
8   INITIALIZATION AND SEQUENCING REQUIREMENTS
9   None.
10 
11   ---------------------------------------------------------------------------
12   Copyright (c) 2016 -2020 Quectel Wireless Solution, Co., Ltd.  All Rights Reserved.
13   Quectel Wireless Solution Proprietary and Confidential.
14   ---------------------------------------------------------------------------
15 ******************************************************************************/
16 
17 #include "QMIThread.h"
18 #include <sys/wait.h>
19 #include <sys/utsname.h>
20 #include <sys/time.h>
21 #include <dirent.h>
22 
23 #include "util.h"
24 //#define CONFIG_PID_FILE_FORMAT "/var/run/quectel-CM-%s.pid" //for example /var/run/quectel-CM-wwan0.pid
25 
26 int debug_qmi = 0;
27 int qmidevice_control_fd[2];
28 static int signal_control_fd[2];
29 
30 extern int ql_ifconfig(int argc, char *argv[]);
31 extern int ql_get_netcard_driver_info(const char*);
32 extern int ql_capture_usbmon_log(PROFILE_T *profile, const char *log_path);
33 extern void ql_stop_usbmon_log(PROFILE_T *profile);
34 
35 //UINT ifc_get_addr(const char *ifname);
36 static int s_link = -1;
usbnet_link_state(int state)37 static void usbnet_link_state(int state)
38 {
39     s_link = state ? 1 : 0;
40 }
usbnet_link_change(int link,PROFILE_T * profile)41 static void usbnet_link_change(int link, PROFILE_T *profile) {
42     if (s_link == link)
43         return;
44 
45     s_link = link;
46 
47     if (!(link & (1<<IpFamilyV4)))
48         memset(&profile->ipv4, 0, sizeof(IPV4_T));
49 
50     if (!(link & (1<<IpFamilyV6)))
51         memset(&profile->ipv6, 0, sizeof(IPV6_T));
52 
53     if (link) {
54         udhcpc_start(profile);
55     } else {
56         udhcpc_stop(profile);
57     }
58 }
59 
check_ipv4_address(PROFILE_T * profile)60 static int check_ipv4_address(PROFILE_T *profile) {
61     uint32_t oldAddress = profile->ipv4.Address;
62 
63     if (profile->request_ops == &mbim_request_ops)
64         return 1; //we will get a new ipv6 address per requestGetIPAddress()
65     if (profile->request_ops == &atc_request_ops)
66         return 1; //TODO
67 
68     if (profile->request_ops->requestGetIPAddress(profile, IpFamilyV4) == 0) {
69          if (profile->ipv4.Address != oldAddress || debug_qmi) {
70              unsigned char *l = (unsigned char *)&oldAddress;
71              unsigned char *r = (unsigned char *)&profile->ipv4.Address;
72              dbg_time("localIP: %d.%d.%d.%d VS remoteIP: %d.%d.%d.%d",
73                      l[3], l[2], l[1], l[0], r[3], r[2], r[1], r[0]);
74         }
75         return (profile->ipv4.Address == oldAddress);
76     }
77 
78     return 0;
79 }
80 
main_send_event_to_qmidevice(int triger_event)81 static void main_send_event_to_qmidevice(int triger_event) {
82      if (write(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)) == -1) {};
83 }
84 
send_signo_to_main(int signo)85 static void send_signo_to_main(int signo) {
86      if (write(signal_control_fd[0], &signo, sizeof(signo)) == -1) {};
87 }
88 
qmidevice_send_event_to_main(int triger_event)89 void qmidevice_send_event_to_main(int triger_event) {
90      if (write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event)) == -1) {};
91 }
92 
qmidevice_send_event_to_main_ext(int triger_event,void * data,unsigned len)93 void qmidevice_send_event_to_main_ext(int triger_event, void *data, unsigned len) {
94      if (write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event)) == -1) {};
95      if (write(qmidevice_control_fd[1], data, len) == -1) {};
96 }
97 
98 #define MAX_PATH 256
99 
ls_dir(const char * dir,int (* match)(const char * dir,const char * file,void * argv[]),void * argv[])100 static int ls_dir(const char *dir, int (*match)(const char *dir, const char *file, void *argv[]), void *argv[])
101 {
102     DIR *pDir;
103     struct dirent* ent = NULL;
104     int match_times = 0;
105 
106     pDir = opendir(dir);
107     if (pDir == NULL)  {
108         dbg_time("Cannot open directory: %s, errno: %d (%s)", dir, errno, strerror(errno));
109         return 0;
110     }
111 
112     while ((ent = readdir(pDir)) != NULL)  {
113         match_times += match(dir, ent->d_name, argv);
114     }
115     closedir(pDir);
116 
117     return match_times;
118 }
119 
is_same_linkfile(const char * dir,const char * file,void * argv[])120 static int is_same_linkfile(const char *dir, const char *file,  void *argv[])
121 {
122     const char *qmichannel = (const char *)argv[1];
123     char linkname[MAX_PATH];
124     char filename[MAX_PATH];
125     int linksize;
126 
127     snprintf(linkname, MAX_PATH, "%s/%s", dir, file);
128     linksize = readlink(linkname, filename, MAX_PATH);
129     if (linksize <= 0)
130         return 0;
131 
132     filename[linksize] = 0;
133     if (strcmp(filename, qmichannel))
134         return 0;
135 
136     dbg_time("%s -> %s", linkname, filename);
137     return 1;
138 }
139 
is_brother_process(const char * dir,const char * file,void * argv[])140 static int is_brother_process(const char *dir, const char *file, void *argv[])
141 {
142     //const char *myself = (const char *)argv[0];
143     char linkname[MAX_PATH];
144     char filename[MAX_PATH];
145     int linksize;
146     int i = 0, kill_timeout = 15;
147     pid_t pid;
148 
149     //dbg_time("%s", file);
150     while (file[i]) {
151         if (!isdigit(file[i]))
152             break;
153         i++;
154     }
155 
156     if (file[i]) {
157         //dbg_time("%s not digit", file);
158         return 0;
159     }
160 
161     snprintf(linkname, MAX_PATH, "%s/%s/exe", dir, file);
162     linksize = readlink(linkname, filename, MAX_PATH);
163     if (linksize <= 0)
164         return 0;
165 
166     filename[linksize] = 0;
167 
168     pid = atoi(file);
169     if (pid >= getpid())
170         return 0;
171 
172     snprintf(linkname, MAX_PATH, "%s/%s/fd", dir, file);
173     if (!ls_dir(linkname, is_same_linkfile, argv))
174         return 0;
175 
176     dbg_time("%s/%s/exe -> %s", dir, file, filename);
177     while (kill_timeout-- && !kill(pid, 0))
178     {
179         kill(pid, SIGTERM);
180         sleep(1);
181     }
182     if (!kill(pid, 0))
183     {
184         dbg_time("force kill %s/%s/exe -> %s", dir, file, filename);
185         kill(pid, SIGKILL);
186         sleep(1);
187     }
188 
189     return 1;
190 }
191 
kill_brothers(const char * qmichannel)192 static int kill_brothers(const char *qmichannel)
193 {
194     char myself[MAX_PATH];
195     int filenamesize;
196     void *argv[2] = {myself, (void *)qmichannel};
197 
198     filenamesize = readlink("/proc/self/exe", myself, MAX_PATH);
199     if (filenamesize <= 0)
200         return 0;
201     myself[filenamesize] = 0;
202 
203     if (ls_dir("/proc", is_brother_process, argv))
204         sleep(1);
205 
206     return 0;
207 }
208 
kill_data_call_pdp(int pdp,char * self)209 static int kill_data_call_pdp(int pdp, char *self) {
210     int pid;
211     char *p = NULL;
212 
213     p = self;
214     while (*self) {
215         if (*self == '/')
216             p = self+1;
217         self++;
218     }
219 
220     pid = getpid_by_pdp(pdp, p);
221     if (pid > 0) {
222         dbg_time("send SIGINT to process %d", pid);
223         return kill(pid, SIGINT);
224     }
225 
226     return -1;
227 }
228 
ql_sigaction(int signo)229 static void ql_sigaction(int signo) {
230      if (SIGALRM == signo)
231          send_signo_to_main(SIG_EVENT_START);
232      else
233      {
234         send_signo_to_main(SIG_EVENT_STOP);
235         main_send_event_to_qmidevice(SIG_EVENT_STOP); //main may be wating qmi response
236     }
237 }
238 
239 static pthread_t gQmiThreadID = 0;
240 
usage(const char * progname)241 static int usage(const char *progname) {
242     dbg_time("Usage: %s [options]", progname);
243     dbg_time("-s [apn [user password auth]]          Set apn/user/password/auth get from your network provider. auth: 1~pap, 2~chap");
244     dbg_time("-p pincode                             Verify sim card pin if sim card is locked");
245     dbg_time("-p [quectel-][qmi|mbim]-proxy          Request to use proxy");
246     dbg_time("-f logfilename                         Save log message of this program to file");
247     dbg_time("-u usbmonlog filename                  Save usbmon log to file");
248     dbg_time("-i interface                           Specify which network interface to setup data call when multi-modems exits");
249     dbg_time("-4                                     Setup IPv4 data call (default)");
250     dbg_time("-6                                     Setup IPv6 data call");
251     dbg_time("-n pdn                                 Specify which pdn to setup data call (default 1 for QMI, 0 for MBIM)");
252     dbg_time("-k pdn                                 Specify which pdn to hangup data call (by send SIGINT to 'quectel-CM -n pdn')");
253     dbg_time("-m iface-idx                           Bind QMI data call to wwan0_<iface idx> when QMAP used. E.g '-n 7 -m 1' bind pdn-7 data call to wwan0_1");
254     dbg_time("-b                                     Enable network interface bridge function (default 0)");
255     dbg_time("-v                                     Verbose log mode, for debug purpose.");
256     dbg_time("[Examples]");
257     dbg_time("Example 1: %s ", progname);
258     dbg_time("Example 2: %s -s 3gnet ", progname);
259     dbg_time("Example 3: %s -s 3gnet carl 1234 1 -p 1234 -f gobinet_log.txt", progname);
260     return 0;
261 }
262 
qmi_main(PROFILE_T * profile)263 int qmi_main(PROFILE_T *profile)
264 {
265     int triger_event = 0;
266     int signo;
267 #ifdef CONFIG_SIM
268     SIM_Status SIMStatus;
269 #endif
270     UCHAR PSAttachedState = 0;
271     UCHAR  IPv4ConnectionStatus = QWDS_PKT_DATA_UNKNOW;
272     UCHAR  IPv6ConnectionStatus = QWDS_PKT_DATA_UNKNOW;
273     unsigned SetupCallFail = 0;
274     unsigned long SetupCallAllowTime = clock_msec();
275     int qmierr = 0;
276     const struct request_ops *request_ops = profile ->request_ops;
277 
278     /* signal trigger quit event */
279     signal(SIGINT, ql_sigaction);
280     signal(SIGTERM, ql_sigaction);
281     /* timer routine */
282     signal(SIGALRM, ql_sigaction);
283 
284 //sudo apt-get install udhcpc
285 //sudo apt-get remove ModemManager
286 __main_loop:
287     if (profile->reattach_flag) {
288         if (!reattach_driver(profile))
289             sleep(2);
290     }
291 
292     /* try to recreate FDs*/
293     if (socketpair( AF_LOCAL, SOCK_STREAM, 0, signal_control_fd) < 0 ) {
294         dbg_time("%s Faild to create main_control_fd: %d (%s)", __func__, errno, strerror(errno));
295         return -1;
296     }
297 
298     if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, qmidevice_control_fd ) < 0 ) {
299         dbg_time("%s Failed to create thread control socket pair: %d (%s)", __func__, errno, strerror(errno));
300         return 0;
301     }
302 
303     if ((profile->qmap_mode == 0 || profile->qmap_mode == 1) && (!profile->proxy[0])) {
304         kill_brothers(profile->qmichannel);
305      }
306 
307     if (pthread_create( &gQmiThreadID, 0, profile->qmi_ops->read, (void *)profile) != 0) {
308         dbg_time("%s Failed to create QMIThread: %d (%s)", __func__, errno, strerror(errno));
309             return 0;
310     }
311 
312     if ((read(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)) != sizeof(triger_event))
313         || (triger_event != RIL_INDICATE_DEVICE_CONNECTED)) {
314         dbg_time("%s Failed to init QMIThread: %d (%s)", __func__, errno, strerror(errno));
315         return 0;
316     }
317 
318     if (profile->qmi_ops->init && profile->qmi_ops->init(profile)) {
319         dbg_time("%s Failed to qmi init: %d (%s)", __func__, errno, strerror(errno));
320         return 0;
321     }
322 
323     if (request_ops->requestBaseBandVersion)
324         request_ops->requestBaseBandVersion(profile);
325 
326     if (request_ops->requestSetEthMode)
327         request_ops->requestSetEthMode(profile);
328 
329     if (request_ops->requestSetLoopBackState && profile->loopback_state) {
330     	request_ops->requestSetLoopBackState(profile->loopback_state, profile->replication_factor);
331     	profile->loopback_state = 0;
332     }
333 
334     if (request_ops->requestGetSIMStatus) {
335         qmierr = request_ops->requestGetSIMStatus(&SIMStatus);
336 
337         while (qmierr == QMI_ERR_OP_DEVICE_UNSUPPORTED) {
338             sleep(1);
339             qmierr = request_ops->requestGetSIMStatus(&SIMStatus);
340         }
341 
342         if ((SIMStatus == SIM_PIN) && profile->pincode && request_ops->requestEnterSimPin) {
343             request_ops->requestEnterSimPin(profile->pincode);
344         }
345     }
346 
347     if (SIMStatus == SIM_READY) {
348         if (request_ops->requestGetICCID)
349             request_ops->requestGetICCID();
350 
351         if (request_ops->requestGetIMSI)
352             request_ops->requestGetIMSI();
353     }
354 
355     if (request_ops->requestSetProfile && (profile->apn || profile->user || profile->password)) {
356         request_ops->requestSetProfile(profile);
357     }
358 
359     if (request_ops->requestGetProfile)
360         request_ops->requestGetProfile(profile);
361 
362     request_ops->requestRegistrationState(&PSAttachedState);
363 
364     send_signo_to_main(SIG_EVENT_CHECK);
365 
366     while (1)
367     {
368         struct pollfd pollfds[] = {{signal_control_fd[1], POLLIN, 0}, {qmidevice_control_fd[0], POLLIN, 0}};
369         int ne, ret, nevents = sizeof(pollfds)/sizeof(pollfds[0]);
370 
371         do {
372             ret = poll(pollfds, nevents,  15*1000);
373         } while ((ret < 0) && (errno == EINTR));
374 
375         if (ret == 0)
376         {
377             send_signo_to_main(SIG_EVENT_CHECK);
378             continue;
379         }
380 
381         if (ret <= 0) {
382             dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
383             goto __main_quit;
384         }
385 
386         for (ne = 0; ne < nevents; ne++) {
387             int fd = pollfds[ne].fd;
388             short revents = pollfds[ne].revents;
389 
390             if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
391                 dbg_time("%s poll err/hup", __func__);
392                 dbg_time("epoll fd = %d, events = 0x%04x", fd, revents);
393                 main_send_event_to_qmidevice(RIL_REQUEST_QUIT);
394                 if (revents & POLLHUP)
395                     goto __main_quit;
396             }
397 
398             if ((revents & POLLIN) == 0)
399                 continue;
400 
401             if (fd == signal_control_fd[1])
402             {
403                 if (read(fd, &signo, sizeof(signo)) == sizeof(signo))
404                 {
405                     alarm(0);
406                     switch (signo)
407                     {
408                         case SIG_EVENT_START:
409                             if (PSAttachedState != 1 && profile->loopback_state == 0)
410                                 break;
411 
412                             if (SetupCallAllowTime > clock_msec()) {
413                                 alarm((SetupCallAllowTime - clock_msec()+999)/1000);
414                                 break;
415                             }
416 
417                             if (profile->enable_ipv4 && IPv4ConnectionStatus !=  QWDS_PKT_DATA_CONNECTED) {
418                                 qmierr = request_ops->requestSetupDataCall(profile, IpFamilyV4);
419 
420                                 if ((qmierr > 0) && profile->user && profile->user[0] && profile->password && profile->password[0]) {
421                                     int old_auto =  profile->auth;
422 
423                                     //may be fail because wrong auth mode, try pap->chap, or chap->pap
424                                     profile->auth = (profile->auth == 1) ? 2 : 1;
425                                 	qmierr = request_ops->requestSetupDataCall(profile, IpFamilyV4);
426 
427                                     if (qmierr)
428                                         profile->auth = old_auto; //still fail, restore old auth moe
429                                 }
430 
431                                 if (!qmierr) {
432                                     qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV4);
433                                     if (!qmierr)
434                                         IPv4ConnectionStatus = QWDS_PKT_DATA_CONNECTED;
435                                 }
436 
437                             }
438 
439                             if (profile->enable_ipv6 && IPv6ConnectionStatus !=  QWDS_PKT_DATA_CONNECTED) {
440                                 if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
441                                     IPv6ConnectionStatus = IPv4ConnectionStatus;
442                                 }
443                                 else {
444                                     qmierr = request_ops->requestSetupDataCall(profile, IpFamilyV6);
445 
446                                     if (!qmierr) {
447                                         qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV6);
448                                         if (!qmierr)
449                                             IPv6ConnectionStatus = QWDS_PKT_DATA_CONNECTED;
450                                     }
451                                 }
452                             }
453 
454                             if ((profile->enable_ipv4 && IPv4ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)
455                                     || (profile->enable_ipv6 && IPv6ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)) {
456                                 const unsigned allow_time[] = {5, 10, 20, 40, 60};
457 
458                                 if (SetupCallFail < (sizeof(allow_time)/sizeof(unsigned)))
459                                     SetupCallAllowTime = allow_time[SetupCallFail];
460                                 else
461                                     SetupCallAllowTime = 60;
462                                 SetupCallFail++;
463                                 dbg_time("try to requestSetupDataCall %ld second later", SetupCallAllowTime);
464                                 alarm(SetupCallAllowTime);
465                                 SetupCallAllowTime = SetupCallAllowTime*1000 + clock_msec();
466                             }
467                             else if (IPv4ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED) {
468                                 SetupCallFail = 0;
469                                 SetupCallAllowTime = clock_msec();
470                             }
471                         break;
472 
473                         case SIG_EVENT_CHECK:
474                             if (request_ops->requestGetSignalInfo)
475                                 request_ops->requestGetSignalInfo();
476 
477                             if (profile->enable_ipv4 && IPv4ConnectionStatus != QWDS_PKT_DATA_DISCONNECTED
478                                 && !request_ops->requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4))
479                             {
480                                 if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && profile->ipv4.Address == 0) {
481                                     //killall -9 quectel-CM for MBIM and ATC call
482                                     qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV4);
483                                     if (qmierr)
484                                         IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
485                                 }
486 
487                                 //local ip is different with remote ip
488                                 if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && check_ipv4_address(profile) == 0) {
489                                     request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV4);
490                                     IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
491                                 }
492                             }
493                             else {
494                                 IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
495                             }
496 
497                             if (profile->enable_ipv6 && IPv6ConnectionStatus != QWDS_PKT_DATA_DISCONNECTED) {
498                                 if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
499                                     IPv6ConnectionStatus = IPv4ConnectionStatus;
500                                 }
501                                 else {
502                                     request_ops->requestQueryDataCall(&IPv6ConnectionStatus, IpFamilyV6);
503                                 }
504                             }
505                             else {
506                                 IPv6ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
507                             }
508 
509                             if (IPv4ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED && IPv6ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED) {
510                                 usbnet_link_change(0, profile);
511                             }
512                             else if (IPv4ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED) {
513                                 int link = 0;
514                                 if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED)
515                                     link |= (1<<IpFamilyV4);
516                                 if (IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED)
517                                     link |= (1<<IpFamilyV6);
518                                 usbnet_link_change(link, profile);
519                             }
520 
521                             if ((profile->enable_ipv4 && IPv4ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)
522                                 || (profile->enable_ipv6 && IPv6ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)) {
523                                 send_signo_to_main(SIG_EVENT_START);
524                             }
525                         break;
526 
527                         case SIG_EVENT_STOP:
528                             if (profile->enable_ipv4 && IPv4ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED) {
529                                 request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV4);
530                             }
531                             if (profile->enable_ipv6 && IPv6ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED) {
532                                 if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
533 
534                                 }
535                                 else {
536                                     request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV6);
537                                 }
538                             }
539                             usbnet_link_change(0, profile);
540                             if (profile->qmi_ops->deinit)
541                                 profile->qmi_ops->deinit();
542                             main_send_event_to_qmidevice(RIL_REQUEST_QUIT);
543                             goto __main_quit;
544                         break;
545 
546                         default:
547                         break;
548                     }
549                 }
550             }
551 
552             if (fd == qmidevice_control_fd[0]) {
553                 if (read(fd, &triger_event, sizeof(triger_event)) == sizeof(triger_event)) {
554                     switch (triger_event) {
555                         case RIL_INDICATE_DEVICE_DISCONNECTED:
556                             usbnet_link_change(0, profile);
557                             goto __main_quit;
558                         break;
559 
560                         case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
561                             request_ops->requestRegistrationState(&PSAttachedState);
562                             if (PSAttachedState == 1) {
563                                 if ((profile->enable_ipv4 && IPv4ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)
564                                     || (profile->enable_ipv6 && IPv6ConnectionStatus ==  QWDS_PKT_DATA_DISCONNECTED)) {
565                                     send_signo_to_main(SIG_EVENT_START);
566                                 }
567                              } else {
568                                 SetupCallAllowTime = clock_msec();
569                              }
570                         break;
571 
572                         case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
573                             if (IPv4ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus ==  QWDS_PKT_DATA_CONNECTED) {
574                                 SetupCallAllowTime = clock_msec() + 1000; //from connect -> disconnect, do not re-dail immediately, wait network stable
575                             }
576                             send_signo_to_main(SIG_EVENT_CHECK);
577                         break;
578 
579                         case MODEM_REPORT_RESET_EVENT:
580                         {
581                             unsigned int time_to_wait = 20;
582                             unsigned int time_expired = 0;
583                             dbg_time("main recv MODEM RESET SIGNAL");
584                             dbg_time("quit QMI thread and wait %ds and try to restart", time_to_wait);
585                             main_send_event_to_qmidevice(RIL_REQUEST_QUIT);
586                             /** NOTICE
587                              * DO NOT CALL usbnet_link_change(0, profile) DIRECTLLY
588                              * for, the modem may go into wrong state(only ttyUSB0 left) and wont go back
589                              */
590                             usbnet_link_state(0);
591                             /* close FDs, for we want restart. */
592                             close(signal_control_fd[0]);
593                             close(signal_control_fd[1]);
594                             close(qmidevice_control_fd[0]);
595                             close(qmidevice_control_fd[1]);
596                             while (time_expired++ < time_to_wait) {
597                                 sleep(1);
598                                 char qmidev[64] = {'\0'};
599                                 snprintf(qmidev, sizeof(qmidev), "/dev/bus/usb/%03d/%03d", profile->usb_dev.busnum, profile->usb_dev.devnum);
600                                 if (access(qmidev, F_OK)) {
601                                     dbg_time("whoo, fatal error info, qmi device node disappeared!!! cannot continue!\n");
602                                     goto __main_quit;
603                                 }
604                             }
605                             dbg_time("main try do restart");
606                             goto __main_loop;
607                         }
608                     	case RIL_UNSOL_LOOPBACK_CONFIG_IND:
609                         {
610                         	QMI_WDA_SET_LOOPBACK_CONFIG_IND_MSG SetLoopBackInd;
611                         	if (read(fd, &SetLoopBackInd, sizeof(SetLoopBackInd)) == sizeof(SetLoopBackInd)) {
612                             	profile->loopback_state = SetLoopBackInd.loopback_state.TLVVaule;
613                             	profile->replication_factor = le32_to_cpu(SetLoopBackInd.replication_factor.TLVVaule);
614                             	dbg_time("SetLoopBackInd: loopback_state=%d, replication_factor=%u",
615                                 	profile->loopback_state, profile->replication_factor);
616                             	if (profile->loopback_state)
617                                 	send_signo_to_main(SIG_EVENT_START);
618                             }
619                         }
620                     	break;
621                         default:
622                         break;
623                     }
624                 }
625             }
626         }
627     }
628 
629 __main_quit:
630     usbnet_link_change(0, profile);
631     if (gQmiThreadID && pthread_join(gQmiThreadID, NULL)) {
632         dbg_time("%s Error joining to listener thread (%s)", __func__, strerror(errno));
633     }
634     close(signal_control_fd[0]);
635     close(signal_control_fd[1]);
636     close(qmidevice_control_fd[0]);
637     close(qmidevice_control_fd[1]);
638     dbg_time("%s exit", __func__);
639 
640     return 0;
641 }
642 
643 #define has_more_argv() ((opt < argc) && (argv[opt][0] != '-'))
main(int argc,char * argv[])644 int main(int argc, char *argv[])
645 {
646     int opt = 1;
647     const char *usbmon_logfile = NULL;
648     PROFILE_T profile;
649     int ret = -1;
650 
651     dbg_time("Quectel_QConnectManager_Linux_V1.6.0.24");
652     memset(&profile, 0x00, sizeof(profile));
653     profile.pdp = CONFIG_DEFAULT_PDP;
654 
655     if (!strcmp(argv[argc-1], "&"))
656         argc--;
657 
658     opt = 1;
659     while  (opt < argc) {
660         if (argv[opt][0] != '-')
661             return usage(argv[0]);
662 
663         switch (argv[opt++][1])
664         {
665             case 's':
666                 profile.apn = profile.user = profile.password = "";
667                 if (has_more_argv())
668                     profile.apn = argv[opt++];
669                 if (has_more_argv())
670                     profile.user = argv[opt++];
671                 if (has_more_argv())
672                 {
673                     profile.password = argv[opt++];
674                     if (profile.password && profile.password[0])
675                         profile.auth = 2; //default chap, customers may miss auth
676                 }
677                 if (has_more_argv()) {
678                     const char *auth = argv[opt++];
679 
680                     if (!strcmp(auth, "0") || !strcasecmp(auth, "none")) {
681                         profile.auth = 0;
682                     } else if (!strcmp(auth, "1") || !strcasecmp(auth, "pap")) {
683                         profile.auth = 1;
684                     } else if (!strcmp(auth, "2") || !strcasecmp(auth, "chap")) {
685                         profile.auth = 2;
686                     } else {
687                         dbg_time("unknow auth '%s'", auth);
688                         return usage(argv[0]);
689                     }
690                 }
691             break;
692 
693             case 'p':
694                 if (has_more_argv()) {
695                     const char *arg = argv[opt++];
696 
697                     if (!strcmp(arg, QUECTEL_QMI_PROXY) || !strcmp(arg, QUECTEL_MBIM_PROXY)
698                         || !strcmp(arg, LIBQMI_PROXY) || !strcmp(arg, LIBMBIM_PROXY)) {
699                         strncpy(profile.proxy, arg, sizeof(profile.proxy));
700                     }
701                     else if ((999 < atoi(arg)) && (atoi(arg) < 10000)) {
702                         profile.pincode = argv[opt++];
703                     } else {
704                         dbg_time("unknow -p '%s'", arg);
705                         return usage(argv[0]);
706                     }
707                 }
708             break;
709 
710             case 'm':
711                 if (has_more_argv())
712                     profile.muxid = argv[opt++][0] - '0' + 0x80;
713             break;
714 
715             case 'n':
716                 if (has_more_argv())
717                     profile.pdp = argv[opt++][0] - '0';
718             break;
719 
720             case 'f':
721                 if (has_more_argv())
722                 {
723                     const char * filename = argv[opt++];
724                     logfilefp = fopen(filename, "a+");
725                     if (!logfilefp) {
726                         dbg_time("Fail to open %s, errno: %d(%s)", filename, errno, strerror(errno));
727                      }
728                 }
729             break;
730 
731             case 'i':
732                 if (has_more_argv())
733                     strncpy(profile.usbnet_adapter, argv[opt++], sizeof(profile.usbnet_adapter));
734             break;
735 
736             case 'v':
737                 debug_qmi = 1;
738             break;
739 
740             case 'l':
741             	if (has_more_argv()) {
742                     profile.replication_factor = atoi(argv[opt++]);
743                 	if (profile.replication_factor > 0)
744                     	profile.loopback_state = 1;
745                 }
746             break;
747 
748             case '4':
749                 profile.enable_ipv4 = 1;
750             break;
751 
752             case '6':
753                 profile.enable_ipv6 = 1;
754             break;
755 
756             case 'u':
757                 if (has_more_argv()) {
758                     usbmon_logfile = argv[opt++];
759                 }
760             break;
761 
762             case 'b':
763                 profile.enable_bridge = 1;
764             break;
765 
766             case 'k':
767                 if (has_more_argv()) {
768                     return kill_data_call_pdp(argv[opt++][0] - '0', argv[0]);
769                 }
770                 break;
771 
772             default:
773                 return usage(argv[0]);
774             break;
775         }
776     }
777 
778     if (profile.enable_ipv4 != 1 && profile.enable_ipv6 != 1) { // default enable IPv4
779         profile.enable_ipv4 = 1;
780     }
781 
782     if (!(profile.qmichannel[0]) || !(profile.usbnet_adapter[0])) {
783         char qmichannel[32+1] = {'\0'};
784         char usbnet_adapter[32+1] = {'\0'};
785 
786         if (profile.usbnet_adapter[0])
787             strncpy(usbnet_adapter, profile.usbnet_adapter, sizeof(usbnet_adapter));
788 
789         if (qmidevice_detect(qmichannel, usbnet_adapter, sizeof(qmichannel), &profile)) {
790         	profile.hardware_interface = HARDWARE_USB;
791         }
792         else if (mhidevice_detect(qmichannel, usbnet_adapter, &profile)) {
793             profile.hardware_interface = HARDWARE_PCIE;
794         }
795         else {
796             dbg_time("qmidevice_detect failed");
797             goto error;
798         }
799 
800         strncpy(profile.qmichannel, qmichannel, sizeof(profile.qmichannel));
801         strncpy(profile.usbnet_adapter, usbnet_adapter, sizeof(profile.usbnet_adapter));
802         ql_get_netcard_driver_info(profile.usbnet_adapter);
803 
804         if ((profile.hardware_interface == HARDWARE_USB) && usbmon_logfile)
805             ql_capture_usbmon_log(&profile, usbmon_logfile);
806 
807         if (profile.hardware_interface == HARDWARE_USB) {
808             profile.software_interface = get_driver_type(&profile);
809         }
810     }
811 
812     ql_qmap_mode_detect(&profile);
813 
814     if (profile.software_interface == SOFTWARE_MBIM) {
815         dbg_time("Modem works in MBIM mode");
816         profile.request_ops = &mbim_request_ops;
817         profile.qmi_ops = &mbim_dev_ops;
818         ret = qmi_main(&profile);
819     }
820     else if (profile.software_interface == SOFTWARE_QMI) {
821         dbg_time("Modem works in QMI mode");
822         profile.request_ops = &qmi_request_ops;
823         if (qmidev_is_gobinet(profile.qmichannel))
824             profile.qmi_ops = &gobi_qmidev_ops;
825         else
826             profile.qmi_ops = &qmiwwan_qmidev_ops;
827         qmidev_send = profile.qmi_ops->send;
828         ret = qmi_main(&profile);
829     }
830     else if (profile.software_interface == SOFTWARE_ECM_RNDIS_NCM) {
831         dbg_time("Modem works in ECM_RNDIS_NCM mode");
832         profile.request_ops = &atc_request_ops;
833         profile.qmi_ops = &atc_dev_ops;
834         ret = qmi_main(&profile);
835     }
836     else {
837         dbg_time("unsupport software_interface %d", profile.software_interface);
838     }
839 
840     ql_stop_usbmon_log(&profile);
841     if (logfilefp)
842     fclose(logfilefp);
843 
844 error:
845 
846     return ret;
847 }
848