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