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