1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun @file quectel-qmi-proxy.c
3*4882a593Smuzhiyun @brief The qmi proxy.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun DESCRIPTION
6*4882a593Smuzhiyun Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun INITIALIZATION AND SEQUENCING REQUIREMENTS
9*4882a593Smuzhiyun None.
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun ---------------------------------------------------------------------------
12*4882a593Smuzhiyun Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
13*4882a593Smuzhiyun Quectel Wireless Solution Proprietary and Confidential.
14*4882a593Smuzhiyun ---------------------------------------------------------------------------
15*4882a593Smuzhiyun ******************************************************************************/
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun #include <stdlib.h>
18*4882a593Smuzhiyun #include <stdio.h>
19*4882a593Smuzhiyun #include <string.h>
20*4882a593Smuzhiyun #include <errno.h>
21*4882a593Smuzhiyun #include <stdarg.h>
22*4882a593Smuzhiyun #include <stddef.h>
23*4882a593Smuzhiyun #include <fcntl.h>
24*4882a593Smuzhiyun #include <pthread.h>
25*4882a593Smuzhiyun #include <poll.h>
26*4882a593Smuzhiyun #include <sys/socket.h>
27*4882a593Smuzhiyun #include <sys/time.h>
28*4882a593Smuzhiyun #include <sys/ioctl.h>
29*4882a593Smuzhiyun #include <linux/un.h>
30*4882a593Smuzhiyun #include <linux/if.h>
31*4882a593Smuzhiyun #include <dirent.h>
32*4882a593Smuzhiyun #include <signal.h>
33*4882a593Smuzhiyun #include <endian.h>
34*4882a593Smuzhiyun #include <inttypes.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #ifndef MIN
37*4882a593Smuzhiyun #define MIN(a, b) ((a) < (b)? (a): (b))
38*4882a593Smuzhiyun #endif
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #ifndef htole32
41*4882a593Smuzhiyun #if __BYTE_ORDER == __LITTLE_ENDIAN
42*4882a593Smuzhiyun #define htole16(x) (uint16_t)(x)
43*4882a593Smuzhiyun #define le16toh(x) (uint16_t)(x)
44*4882a593Smuzhiyun #define letoh16(x) (uint16_t)(x)
45*4882a593Smuzhiyun #define htole32(x) (uint32_t)(x)
46*4882a593Smuzhiyun #define le32toh(x) (uint32_t)(x)
47*4882a593Smuzhiyun #define letoh32(x) (uint32_t)(x)
48*4882a593Smuzhiyun #define htole64(x) (uint64_t)(x)
49*4882a593Smuzhiyun #define le64toh(x) (uint64_t)(x)
50*4882a593Smuzhiyun #define letoh64(x) (uint64_t)(x)
51*4882a593Smuzhiyun #else
__bswap16(uint16_t __x)52*4882a593Smuzhiyun static __inline uint16_t __bswap16(uint16_t __x) {
53*4882a593Smuzhiyun return (__x<<8) | (__x>>8);
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
__bswap32(uint32_t __x)56*4882a593Smuzhiyun static __inline uint32_t __bswap32(uint32_t __x) {
57*4882a593Smuzhiyun return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
__bswap64(uint64_t __x)60*4882a593Smuzhiyun static __inline uint64_t __bswap64(uint64_t __x) {
61*4882a593Smuzhiyun return (__bswap32(__x)+0ULL<<32) | (__bswap32(__x>>32));
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #define htole16(x) __bswap16(x)
65*4882a593Smuzhiyun #define le16toh(x) __bswap16(x)
66*4882a593Smuzhiyun #define letoh16(x) __bswap16(x)
67*4882a593Smuzhiyun #define htole32(x) __bswap32(x)
68*4882a593Smuzhiyun #define le32toh(x) __bswap32(x)
69*4882a593Smuzhiyun #define letoh32(x) __bswap32(x)
70*4882a593Smuzhiyun #define htole64(x) __bswap64(x)
71*4882a593Smuzhiyun #define le64toh(x) __bswap64(x)
72*4882a593Smuzhiyun #define letoh64(x) __bswap64(x)
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun #endif
75*4882a593Smuzhiyun
get_time(void)76*4882a593Smuzhiyun const char * get_time(void) {
77*4882a593Smuzhiyun static char time_buf[128];
78*4882a593Smuzhiyun struct timeval tv;
79*4882a593Smuzhiyun time_t time;
80*4882a593Smuzhiyun suseconds_t millitm;
81*4882a593Smuzhiyun struct tm *ti;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun gettimeofday (&tv, NULL);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun time= tv.tv_sec;
86*4882a593Smuzhiyun millitm = (tv.tv_usec + 500) / 1000;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (millitm == 1000) {
89*4882a593Smuzhiyun ++time;
90*4882a593Smuzhiyun millitm = 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun ti = localtime(&time);
94*4882a593Smuzhiyun sprintf(time_buf, "[%02d-%02d_%02d:%02d:%02d:%03d]", ti->tm_mon+1, ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec, (int)millitm);
95*4882a593Smuzhiyun return time_buf;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun #define dprintf(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } while(0);
99*4882a593Smuzhiyun #define SYSCHECK(c) do{if((c)<0) {dprintf("%s %d error: '%s' (code: %d)\n", __func__, __LINE__, strerror(errno), errno); return -1;}}while(0)
100*4882a593Smuzhiyun #define cfmakenoblock(fd) do{fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);}while(0)
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun typedef struct _QCQMI_HDR
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun uint8_t IFType;
105*4882a593Smuzhiyun uint16_t Length;
106*4882a593Smuzhiyun uint8_t CtlFlags; // reserved
107*4882a593Smuzhiyun uint8_t QMIType;
108*4882a593Smuzhiyun uint8_t ClientId;
109*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMI_HDR, *PQCQMI_HDR;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun typedef struct _QMICTL_SYNC_REQ_MSG
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
114*4882a593Smuzhiyun uint8_t TransactionId;
115*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_CTL_SYNC_REQ
116*4882a593Smuzhiyun uint16_t Length; // 0
117*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun typedef struct _QMICTL_SYNC_RESP_MSG
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
122*4882a593Smuzhiyun uint8_t TransactionId;
123*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_CTL_SYNC_RESP
124*4882a593Smuzhiyun uint16_t Length;
125*4882a593Smuzhiyun uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
126*4882a593Smuzhiyun uint16_t TLVLength; // 0x0004
127*4882a593Smuzhiyun uint16_t QMIResult;
128*4882a593Smuzhiyun uint16_t QMIError;
129*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun typedef struct _QMICTL_SYNC_IND_MSG
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_INDICATION
134*4882a593Smuzhiyun uint8_t TransactionId;
135*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
136*4882a593Smuzhiyun uint16_t Length;
137*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
142*4882a593Smuzhiyun uint8_t TransactionId;
143*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_REQ
144*4882a593Smuzhiyun uint16_t Length;
145*4882a593Smuzhiyun uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
146*4882a593Smuzhiyun uint16_t TLVLength; // 1
147*4882a593Smuzhiyun uint8_t QMIType; // QMUX type
148*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG, *PQMICTL_GET_CLIENT_ID_REQ_MSG;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
153*4882a593Smuzhiyun uint8_t TransactionId;
154*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_RESP
155*4882a593Smuzhiyun uint16_t Length;
156*4882a593Smuzhiyun uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
157*4882a593Smuzhiyun uint16_t TLVLength; // 0x0004
158*4882a593Smuzhiyun uint16_t QMIResult; // result code
159*4882a593Smuzhiyun uint16_t QMIError; // error code
160*4882a593Smuzhiyun uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
161*4882a593Smuzhiyun uint16_t TLV2Length; // 2
162*4882a593Smuzhiyun uint8_t QMIType;
163*4882a593Smuzhiyun uint8_t ClientId;
164*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG, *PQMICTL_GET_CLIENT_ID_RESP_MSG;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
169*4882a593Smuzhiyun uint8_t TransactionId;
170*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ
171*4882a593Smuzhiyun uint16_t Length;
172*4882a593Smuzhiyun uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
173*4882a593Smuzhiyun uint16_t TLVLength; // 0x0002
174*4882a593Smuzhiyun uint8_t QMIType;
175*4882a593Smuzhiyun uint8_t ClientId;
176*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG, *PQMICTL_RELEASE_CLIENT_ID_REQ_MSG;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
181*4882a593Smuzhiyun uint8_t TransactionId;
182*4882a593Smuzhiyun uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP
183*4882a593Smuzhiyun uint16_t Length;
184*4882a593Smuzhiyun uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
185*4882a593Smuzhiyun uint16_t TLVLength; // 0x0004
186*4882a593Smuzhiyun uint16_t QMIResult; // result code
187*4882a593Smuzhiyun uint16_t QMIError; // error code
188*4882a593Smuzhiyun uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
189*4882a593Smuzhiyun uint16_t TLV2Length; // 2
190*4882a593Smuzhiyun uint8_t QMIType;
191*4882a593Smuzhiyun uint8_t ClientId;
192*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG, *PQMICTL_RELEASE_CLIENT_ID_RESP_MSG;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun // QMICTL Control Flags
195*4882a593Smuzhiyun #define QMICTL_CTL_FLAG_CMD 0x00
196*4882a593Smuzhiyun #define QMICTL_CTL_FLAG_RSP 0x01
197*4882a593Smuzhiyun #define QMICTL_CTL_FLAG_IND 0x02
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun typedef struct _QCQMICTL_MSG_HDR
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind
202*4882a593Smuzhiyun uint8_t TransactionId;
203*4882a593Smuzhiyun uint16_t QMICTLType;
204*4882a593Smuzhiyun uint16_t Length;
205*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun #define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR)
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun typedef struct _QCQMICTL_MSG_HDR_RESP
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind
212*4882a593Smuzhiyun uint8_t TransactionId;
213*4882a593Smuzhiyun uint16_t QMICTLType;
214*4882a593Smuzhiyun uint16_t Length;
215*4882a593Smuzhiyun uint8_t TLVType; // 0x02 - result code
216*4882a593Smuzhiyun uint16_t TLVLength; // 4
217*4882a593Smuzhiyun uint16_t QMUXResult; // QMI_RESULT_SUCCESS
218*4882a593Smuzhiyun // QMI_RESULT_FAILURE
219*4882a593Smuzhiyun uint16_t QMUXError; // QMI_ERR_INVALID_ARG
220*4882a593Smuzhiyun // QMI_ERR_NO_MEMORY
221*4882a593Smuzhiyun // QMI_ERR_INTERNAL
222*4882a593Smuzhiyun // QMI_ERR_FAULT
223*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun typedef struct _QMICTL_MSG
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun union
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun // Message Header
231*4882a593Smuzhiyun QCQMICTL_MSG_HDR QMICTLMsgHdr;
232*4882a593Smuzhiyun QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun // QMICTL Message
235*4882a593Smuzhiyun //QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq;
236*4882a593Smuzhiyun //QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp;
237*4882a593Smuzhiyun //QMICTL_GET_VERSION_REQ_MSG GetVersionReq;
238*4882a593Smuzhiyun //QMICTL_GET_VERSION_RESP_MSG GetVersionRsp;
239*4882a593Smuzhiyun QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq;
240*4882a593Smuzhiyun QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp;
241*4882a593Smuzhiyun //QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq;
242*4882a593Smuzhiyun QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp;
243*4882a593Smuzhiyun //QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd;
244*4882a593Smuzhiyun //QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd;
245*4882a593Smuzhiyun //QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
246*4882a593Smuzhiyun //QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp;
247*4882a593Smuzhiyun QMICTL_SYNC_REQ_MSG SyncReq;
248*4882a593Smuzhiyun QMICTL_SYNC_RESP_MSG SyncRsp;
249*4882a593Smuzhiyun QMICTL_SYNC_IND_MSG SyncInd;
250*4882a593Smuzhiyun };
251*4882a593Smuzhiyun } __attribute__ ((packed)) QMICTL_MSG, *PQMICTL_MSG;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun typedef struct _QCQMUX_MSG_HDR
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun uint8_t CtlFlags; // 0: single QMUX Msg; 1:
256*4882a593Smuzhiyun uint16_t TransactionId;
257*4882a593Smuzhiyun uint16_t Type;
258*4882a593Smuzhiyun uint16_t Length;
259*4882a593Smuzhiyun uint8_t payload[0];
260*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun typedef struct _QCQMUX_MSG_HDR_RESP
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun uint8_t CtlFlags; // 0: single QMUX Msg; 1:
265*4882a593Smuzhiyun uint16_t TransactionId;
266*4882a593Smuzhiyun uint16_t Type;
267*4882a593Smuzhiyun uint16_t Length;
268*4882a593Smuzhiyun uint8_t TLVType; // 0x02 - result code
269*4882a593Smuzhiyun uint16_t TLVLength; // 4
270*4882a593Smuzhiyun uint16_t QMUXResult; // QMI_RESULT_SUCCESS
271*4882a593Smuzhiyun // QMI_RESULT_FAILURE
272*4882a593Smuzhiyun uint16_t QMUXError; // QMI_ERR_INVALID_ARG
273*4882a593Smuzhiyun // QMI_ERR_NO_MEMORY
274*4882a593Smuzhiyun // QMI_ERR_INTERNAL
275*4882a593Smuzhiyun // QMI_ERR_FAULT
276*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun //#define QUECTEL_QMI_MERGE
279*4882a593Smuzhiyun typedef uint32_t UINT;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun typedef struct _QCQMUX_TLV
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun uint8_t Type;
284*4882a593Smuzhiyun uint16_t Length;
285*4882a593Smuzhiyun uint8_t Value[0];
286*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMUX_TLV, *PQCQMUX_TLV;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun typedef struct _QMUX_MSG
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun union
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun // Message Header
293*4882a593Smuzhiyun QCQMUX_MSG_HDR QMUXMsgHdr;
294*4882a593Smuzhiyun QCQMUX_MSG_HDR_RESP QMUXMsgHdrResp;
295*4882a593Smuzhiyun //QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
296*4882a593Smuzhiyun };
297*4882a593Smuzhiyun } __attribute__ ((packed)) QMUX_MSG, *PQMUX_MSG;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun typedef struct _QCQMIMSG {
300*4882a593Smuzhiyun QCQMI_HDR QMIHdr;
301*4882a593Smuzhiyun union {
302*4882a593Smuzhiyun QMICTL_MSG CTLMsg;
303*4882a593Smuzhiyun QMUX_MSG MUXMsg;
304*4882a593Smuzhiyun };
305*4882a593Smuzhiyun } __attribute__ ((packed)) QCQMIMSG, *PQCQMIMSG;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun // QMUX Message Definitions -- QMI SDU
309*4882a593Smuzhiyun #define QMUX_CTL_FLAG_SINGLE_MSG 0x00
310*4882a593Smuzhiyun #define QMUX_CTL_FLAG_COMPOUND_MSG 0x01
311*4882a593Smuzhiyun #define QMUX_CTL_FLAG_TYPE_CMD 0x00
312*4882a593Smuzhiyun #define QMUX_CTL_FLAG_TYPE_RSP 0x02
313*4882a593Smuzhiyun #define QMUX_CTL_FLAG_TYPE_IND 0x04
314*4882a593Smuzhiyun #define QMUX_CTL_FLAG_MASK_COMPOUND 0x01
315*4882a593Smuzhiyun #define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun #define USB_CTL_MSG_TYPE_QMI 0x01
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun #define QMICTL_FLAG_REQUEST 0x00
320*4882a593Smuzhiyun #define QMICTL_FLAG_RESPONSE 0x01
321*4882a593Smuzhiyun #define QMICTL_FLAG_INDICATION 0x02
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun // QMICTL Type
324*4882a593Smuzhiyun #define QMICTL_SET_INSTANCE_ID_REQ 0x0020
325*4882a593Smuzhiyun #define QMICTL_SET_INSTANCE_ID_RESP 0x0020
326*4882a593Smuzhiyun #define QMICTL_GET_VERSION_REQ 0x0021
327*4882a593Smuzhiyun #define QMICTL_GET_VERSION_RESP 0x0021
328*4882a593Smuzhiyun #define QMICTL_GET_CLIENT_ID_REQ 0x0022
329*4882a593Smuzhiyun #define QMICTL_GET_CLIENT_ID_RESP 0x0022
330*4882a593Smuzhiyun #define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023
331*4882a593Smuzhiyun #define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023
332*4882a593Smuzhiyun #define QMICTL_REVOKE_CLIENT_ID_IND 0x0024
333*4882a593Smuzhiyun #define QMICTL_INVALID_CLIENT_ID_IND 0x0025
334*4882a593Smuzhiyun #define QMICTL_SET_DATA_FORMAT_REQ 0x0026
335*4882a593Smuzhiyun #define QMICTL_SET_DATA_FORMAT_RESP 0x0026
336*4882a593Smuzhiyun #define QMICTL_SYNC_REQ 0x0027
337*4882a593Smuzhiyun #define QMICTL_SYNC_RESP 0x0027
338*4882a593Smuzhiyun #define QMICTL_SYNC_IND 0x0027
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun #define QCTLV_TYPE_REQUIRED_PARAMETER 0x01
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun // Define QMI Type
343*4882a593Smuzhiyun typedef enum _QMI_SERVICE_TYPE
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun QMUX_TYPE_CTL = 0x00,
346*4882a593Smuzhiyun QMUX_TYPE_WDS = 0x01,
347*4882a593Smuzhiyun QMUX_TYPE_DMS = 0x02,
348*4882a593Smuzhiyun QMUX_TYPE_NAS = 0x03,
349*4882a593Smuzhiyun QMUX_TYPE_QOS = 0x04,
350*4882a593Smuzhiyun QMUX_TYPE_WMS = 0x05,
351*4882a593Smuzhiyun QMUX_TYPE_PDS = 0x06,
352*4882a593Smuzhiyun QMUX_TYPE_UIM = 0x0B,
353*4882a593Smuzhiyun QMUX_TYPE_WDS_IPV6 = 0x11,
354*4882a593Smuzhiyun QMUX_TYPE_WDS_ADMIN = 0x1A,
355*4882a593Smuzhiyun QMUX_TYPE_MAX = 0xFF,
356*4882a593Smuzhiyun QMUX_TYPE_ALL = 0xFF
357*4882a593Smuzhiyun } QMI_SERVICE_TYPE;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun #define QMIWDS_ADMIN_SET_DATA_FORMAT_REQ 0x0020
360*4882a593Smuzhiyun #define QMIWDS_ADMIN_SET_DATA_FORMAT_RESP 0x0020
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun struct qlistnode
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct qlistnode *next;
365*4882a593Smuzhiyun struct qlistnode *prev;
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun #define qnode_to_item(node, container, member) \
369*4882a593Smuzhiyun (container *) (((char*) (node)) - offsetof(container, member))
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun #define qlist_for_each(node, list) \
372*4882a593Smuzhiyun for (node = (list)->next; node != (list); node = node->next)
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun #define qlist_empty(list) ((list) == (list)->next)
375*4882a593Smuzhiyun #define qlist_head(list) ((list)->next)
376*4882a593Smuzhiyun #define qlist_tail(list) ((list)->prev)
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun typedef struct {
379*4882a593Smuzhiyun struct qlistnode qnode;
380*4882a593Smuzhiyun int ClientFd;
381*4882a593Smuzhiyun QCQMIMSG qmi[0];
382*4882a593Smuzhiyun } QMI_PROXY_MSG;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun typedef struct {
385*4882a593Smuzhiyun struct qlistnode qnode;
386*4882a593Smuzhiyun uint8_t QMIType;
387*4882a593Smuzhiyun uint8_t ClientId;
388*4882a593Smuzhiyun unsigned AccessTime;
389*4882a593Smuzhiyun } QMI_PROXY_CLINET;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun typedef struct {
392*4882a593Smuzhiyun struct qlistnode qnode;
393*4882a593Smuzhiyun struct qlistnode client_qnode;
394*4882a593Smuzhiyun int ClientFd;
395*4882a593Smuzhiyun unsigned AccessTime;
396*4882a593Smuzhiyun } QMI_PROXY_CONNECTION;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun #ifdef QUECTEL_QMI_MERGE
399*4882a593Smuzhiyun #define MERGE_PACKET_IDENTITY 0x2c7c
400*4882a593Smuzhiyun #define MERGE_PACKET_VERSION 0x0001
401*4882a593Smuzhiyun #define MERGE_PACKET_MAX_PAYLOAD_SIZE 56
402*4882a593Smuzhiyun typedef struct __QMI_MSG_HEADER {
403*4882a593Smuzhiyun uint16_t idenity;
404*4882a593Smuzhiyun uint16_t version;
405*4882a593Smuzhiyun uint16_t cur_len;
406*4882a593Smuzhiyun uint16_t total_len;
407*4882a593Smuzhiyun } QMI_MSG_HEADER;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun typedef struct __QMI_MSG_PACKET {
410*4882a593Smuzhiyun QMI_MSG_HEADER header;
411*4882a593Smuzhiyun uint16_t len;
412*4882a593Smuzhiyun char buf[4096];
413*4882a593Smuzhiyun } QMI_MSG_PACKET;
414*4882a593Smuzhiyun #endif
415*4882a593Smuzhiyun
qlist_init(struct qlistnode * node)416*4882a593Smuzhiyun static void qlist_init(struct qlistnode *node)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun node->next = node;
419*4882a593Smuzhiyun node->prev = node;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
qlist_add_tail(struct qlistnode * head,struct qlistnode * item)422*4882a593Smuzhiyun static void qlist_add_tail(struct qlistnode *head, struct qlistnode *item)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun item->next = head;
425*4882a593Smuzhiyun item->prev = head->prev;
426*4882a593Smuzhiyun head->prev->next = item;
427*4882a593Smuzhiyun head->prev = item;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
qlist_remove(struct qlistnode * item)430*4882a593Smuzhiyun static void qlist_remove(struct qlistnode *item)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun item->next->prev = item->prev;
433*4882a593Smuzhiyun item->prev->next = item->next;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun static int qmi_proxy_quit = 0;
437*4882a593Smuzhiyun static pthread_t thread_id = 0;
438*4882a593Smuzhiyun static int cdc_wdm_fd = -1;
439*4882a593Smuzhiyun static int qmi_proxy_server_fd = -1;
440*4882a593Smuzhiyun static struct qlistnode qmi_proxy_connection;
441*4882a593Smuzhiyun static struct qlistnode qmi_proxy_ctl_msg;
442*4882a593Smuzhiyun static int verbose_debug = 0;
443*4882a593Smuzhiyun static int modem_reset_flag = 0;
444*4882a593Smuzhiyun static int qmi_sync_done = 0;
445*4882a593Smuzhiyun static uint8_t qmi_buf[4096];
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun #ifdef QUECTEL_QMI_MERGE
merge_qmi_rsp_packet(void * buf,ssize_t * src_size)448*4882a593Smuzhiyun static int merge_qmi_rsp_packet(void *buf, ssize_t *src_size) {
449*4882a593Smuzhiyun static QMI_MSG_PACKET s_QMIPacket;
450*4882a593Smuzhiyun QMI_MSG_HEADER *header = NULL;
451*4882a593Smuzhiyun ssize_t size = *src_size;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if((uint16_t)size < sizeof(QMI_MSG_HEADER))
454*4882a593Smuzhiyun return -1;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun header = (QMI_MSG_HEADER *)buf;
457*4882a593Smuzhiyun if(le16toh(header->idenity) != MERGE_PACKET_IDENTITY || le16toh(header->version) != MERGE_PACKET_VERSION || le16toh(header->cur_len) > le16toh(header->total_len))
458*4882a593Smuzhiyun return -1;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun if(le16toh(header->cur_len) == le16toh(header->total_len)) {
461*4882a593Smuzhiyun *src_size = le16toh(header->total_len);
462*4882a593Smuzhiyun memcpy(buf, buf + sizeof(QMI_MSG_HEADER), *src_size);
463*4882a593Smuzhiyun s_QMIPacket.len = 0;
464*4882a593Smuzhiyun return 0;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun memcpy(s_QMIPacket.buf + s_QMIPacket.len, buf + sizeof(QMI_MSG_HEADER), le16toh(header->cur_len));
468*4882a593Smuzhiyun s_QMIPacket.len += le16toh(header->cur_len);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (le16toh(header->cur_len) < MERGE_PACKET_MAX_PAYLOAD_SIZE || s_QMIPacket.len >= le16toh(header->total_len)) {
471*4882a593Smuzhiyun memcpy(buf, s_QMIPacket.buf, s_QMIPacket.len);
472*4882a593Smuzhiyun *src_size = s_QMIPacket.len;
473*4882a593Smuzhiyun s_QMIPacket.len = 0;
474*4882a593Smuzhiyun return 0;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return -1;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun #endif
480*4882a593Smuzhiyun
create_local_server(const char * name)481*4882a593Smuzhiyun static int create_local_server(const char *name) {
482*4882a593Smuzhiyun int sockfd = -1;
483*4882a593Smuzhiyun int reuse_addr = 1;
484*4882a593Smuzhiyun struct sockaddr_un sockaddr;
485*4882a593Smuzhiyun socklen_t alen;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /*Create server socket*/
488*4882a593Smuzhiyun SYSCHECK(sockfd = socket(AF_LOCAL, SOCK_STREAM, 0));
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun memset(&sockaddr, 0, sizeof(sockaddr));
491*4882a593Smuzhiyun sockaddr.sun_family = AF_LOCAL;
492*4882a593Smuzhiyun sockaddr.sun_path[0] = 0;
493*4882a593Smuzhiyun memcpy(sockaddr.sun_path + 1, name, strlen(name) );
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
496*4882a593Smuzhiyun SYSCHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr)));
497*4882a593Smuzhiyun if(bind(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) {
498*4882a593Smuzhiyun close(sockfd);
499*4882a593Smuzhiyun dprintf("bind %s errno: %d (%s)\n", name, errno, strerror(errno));
500*4882a593Smuzhiyun return -1;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun dprintf("local server: %s sockfd = %d\n", name, sockfd);
504*4882a593Smuzhiyun cfmakenoblock(sockfd);
505*4882a593Smuzhiyun listen(sockfd, 1);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return sockfd;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
accept_qmi_connection(int serverfd)510*4882a593Smuzhiyun static void accept_qmi_connection(int serverfd) {
511*4882a593Smuzhiyun int clientfd = -1;
512*4882a593Smuzhiyun unsigned char addr[128];
513*4882a593Smuzhiyun socklen_t alen = sizeof(addr);
514*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun clientfd = accept(serverfd, (struct sockaddr *)addr, &alen);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun qmi_con = (QMI_PROXY_CONNECTION *)malloc(sizeof(QMI_PROXY_CONNECTION));
519*4882a593Smuzhiyun if (qmi_con) {
520*4882a593Smuzhiyun qlist_init(&qmi_con->qnode);
521*4882a593Smuzhiyun qlist_init(&qmi_con->client_qnode);
522*4882a593Smuzhiyun qmi_con->ClientFd= clientfd;
523*4882a593Smuzhiyun qmi_con->AccessTime = 0;
524*4882a593Smuzhiyun dprintf("+++ ClientFd=%d\n", qmi_con->ClientFd);
525*4882a593Smuzhiyun qlist_add_tail(&qmi_proxy_connection, &qmi_con->qnode);
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun cfmakenoblock(clientfd);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
cleanup_qmi_connection(int clientfd)531*4882a593Smuzhiyun static void cleanup_qmi_connection(int clientfd) {
532*4882a593Smuzhiyun struct qlistnode *con_node, *qmi_node;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun qlist_for_each(con_node, &qmi_proxy_connection) {
535*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (qmi_con->ClientFd == clientfd) {
538*4882a593Smuzhiyun while (!qlist_empty(&qmi_con->client_qnode)) {
539*4882a593Smuzhiyun QMI_PROXY_CLINET *qmi_client = qnode_to_item(qlist_head(&qmi_con->client_qnode), QMI_PROXY_CLINET, qnode);
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun dprintf("xxx ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun qlist_remove(&qmi_client->qnode);
544*4882a593Smuzhiyun free(qmi_client);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun qlist_for_each(qmi_node, &qmi_proxy_ctl_msg) {
548*4882a593Smuzhiyun QMI_PROXY_MSG *qmi_msg = qnode_to_item(qmi_node, QMI_PROXY_MSG, qnode);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun if (qmi_msg->ClientFd == qmi_con->ClientFd) {
551*4882a593Smuzhiyun qlist_remove(&qmi_msg->qnode);
552*4882a593Smuzhiyun free(qmi_msg);
553*4882a593Smuzhiyun break;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun dprintf("--- ClientFd=%d\n", qmi_con->ClientFd);
558*4882a593Smuzhiyun close(qmi_con->ClientFd);
559*4882a593Smuzhiyun qlist_remove(&qmi_con->qnode);
560*4882a593Smuzhiyun free(qmi_con);
561*4882a593Smuzhiyun break;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
get_client_id(QMI_PROXY_CONNECTION * qmi_con,PQMICTL_GET_CLIENT_ID_RESP_MSG pClient)566*4882a593Smuzhiyun static void get_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_GET_CLIENT_ID_RESP_MSG pClient) {
567*4882a593Smuzhiyun if (pClient->QMIResult == 0 && pClient->QMIError == 0) {
568*4882a593Smuzhiyun QMI_PROXY_CLINET *qmi_client = (QMI_PROXY_CLINET *)malloc(sizeof(QMI_PROXY_CLINET));
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun qlist_init(&qmi_client->qnode);
571*4882a593Smuzhiyun qmi_client->QMIType = pClient->QMIType;
572*4882a593Smuzhiyun qmi_client->ClientId = pClient->ClientId;
573*4882a593Smuzhiyun qmi_client->AccessTime = 0;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun dprintf("+++ ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
576*4882a593Smuzhiyun qlist_add_tail(&qmi_con->client_qnode, &qmi_client->qnode);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
release_client_id(QMI_PROXY_CONNECTION * qmi_con,PQMICTL_RELEASE_CLIENT_ID_RESP_MSG pClient)580*4882a593Smuzhiyun static void release_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_RELEASE_CLIENT_ID_RESP_MSG pClient) {
581*4882a593Smuzhiyun struct qlistnode *client_node;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun if (pClient->QMIResult == 0 && pClient->QMIError == 0) {
584*4882a593Smuzhiyun qlist_for_each (client_node, &qmi_con->client_qnode) {
585*4882a593Smuzhiyun QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun if (pClient->QMIType == qmi_client->QMIType && pClient->ClientId == qmi_client->ClientId) {
588*4882a593Smuzhiyun dprintf("--- ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
589*4882a593Smuzhiyun qlist_remove(&qmi_client->qnode);
590*4882a593Smuzhiyun free(qmi_client);
591*4882a593Smuzhiyun break;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
dump_qmi(PQCQMIMSG pQMI,int fd,const char flag)597*4882a593Smuzhiyun static void dump_qmi(PQCQMIMSG pQMI, int fd, const char flag)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun if (verbose_debug)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun unsigned i;
602*4882a593Smuzhiyun unsigned size = le16toh(pQMI->QMIHdr.Length) + 1;
603*4882a593Smuzhiyun printf("%c %d %u: ", flag, fd, size);
604*4882a593Smuzhiyun if (size > 16)
605*4882a593Smuzhiyun size = 16;
606*4882a593Smuzhiyun for (i = 0; i < size; i++)
607*4882a593Smuzhiyun printf("%02x ", ((uint8_t *)pQMI)[i]);
608*4882a593Smuzhiyun printf("\n");
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
send_qmi_to_cdc_wdm(PQCQMIMSG pQMI)612*4882a593Smuzhiyun static int send_qmi_to_cdc_wdm(PQCQMIMSG pQMI) {
613*4882a593Smuzhiyun struct pollfd pollfds[]= {{cdc_wdm_fd, POLLOUT, 0}};
614*4882a593Smuzhiyun ssize_t ret = 0;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun do {
617*4882a593Smuzhiyun ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
618*4882a593Smuzhiyun } while (ret == -1 && errno == EINTR && qmi_proxy_quit == 0);
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if (pollfds[0].revents & POLLOUT) {
621*4882a593Smuzhiyun ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
622*4882a593Smuzhiyun ret = write(cdc_wdm_fd, pQMI, size);
623*4882a593Smuzhiyun dump_qmi(pQMI, cdc_wdm_fd, 'w');
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun return ret;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
send_qmi_to_client(PQCQMIMSG pQMI,int clientFd)629*4882a593Smuzhiyun static int send_qmi_to_client(PQCQMIMSG pQMI, int clientFd) {
630*4882a593Smuzhiyun struct pollfd pollfds[]= {{clientFd, POLLOUT, 0}};
631*4882a593Smuzhiyun ssize_t ret = 0;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun do {
634*4882a593Smuzhiyun ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
635*4882a593Smuzhiyun } while (ret == -1 && errno == EINTR && qmi_proxy_quit == 0);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (pollfds[0].revents & POLLOUT) {
638*4882a593Smuzhiyun ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
639*4882a593Smuzhiyun ret = write(clientFd, pQMI, size);
640*4882a593Smuzhiyun dump_qmi(pQMI, clientFd, 'w');
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun return ret;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
recv_qmi_from_dev(PQCQMIMSG pQMI)646*4882a593Smuzhiyun static void recv_qmi_from_dev(PQCQMIMSG pQMI) {
647*4882a593Smuzhiyun struct qlistnode *con_node, *client_node;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun if (qmi_proxy_server_fd == -1) {
650*4882a593Smuzhiyun qmi_sync_done = 1;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) {
653*4882a593Smuzhiyun if (pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags == QMICTL_CTL_FLAG_RSP) {
654*4882a593Smuzhiyun if (!qlist_empty(&qmi_proxy_ctl_msg)) {
655*4882a593Smuzhiyun QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun qlist_for_each(con_node, &qmi_proxy_connection) {
658*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if (qmi_con->ClientFd == qmi_msg->ClientFd) {
661*4882a593Smuzhiyun send_qmi_to_client(pQMI, qmi_msg->ClientFd);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_GET_CLIENT_ID_RESP)
664*4882a593Smuzhiyun get_client_id(qmi_con, &pQMI->CTLMsg.GetClientIdRsp);
665*4882a593Smuzhiyun else if ((le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_RELEASE_CLIENT_ID_RESP) ||
666*4882a593Smuzhiyun (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_REVOKE_CLIENT_ID_IND)) {
667*4882a593Smuzhiyun release_client_id(qmi_con, &pQMI->CTLMsg.ReleaseClientIdRsp);
668*4882a593Smuzhiyun if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_REVOKE_CLIENT_ID_IND)
669*4882a593Smuzhiyun modem_reset_flag = 1;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun else {
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun qlist_remove(&qmi_msg->qnode);
677*4882a593Smuzhiyun free(qmi_msg);
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (!qlist_empty(&qmi_proxy_ctl_msg)) {
682*4882a593Smuzhiyun QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun qlist_for_each(con_node, &qmi_proxy_connection) {
685*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun if (qmi_con->ClientFd == qmi_msg->ClientFd) {
688*4882a593Smuzhiyun send_qmi_to_cdc_wdm(qmi_msg->qmi);
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun else {
694*4882a593Smuzhiyun qlist_for_each(con_node, &qmi_proxy_connection) {
695*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun qlist_for_each(client_node, &qmi_con->client_qnode) {
698*4882a593Smuzhiyun QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode);
699*4882a593Smuzhiyun if (pQMI->QMIHdr.QMIType == qmi_client->QMIType) {
700*4882a593Smuzhiyun if (pQMI->QMIHdr.ClientId == 0 || pQMI->QMIHdr.ClientId == qmi_client->ClientId) {
701*4882a593Smuzhiyun send_qmi_to_client(pQMI, qmi_con->ClientFd);
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
recv_qmi_from_client(PQCQMIMSG pQMI,unsigned size,int clientfd)709*4882a593Smuzhiyun static int recv_qmi_from_client(PQCQMIMSG pQMI, unsigned size, int clientfd) {
710*4882a593Smuzhiyun if (qmi_proxy_server_fd <= 0) {
711*4882a593Smuzhiyun send_qmi_to_cdc_wdm(pQMI);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) {
714*4882a593Smuzhiyun QMI_PROXY_MSG *qmi_msg;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun if (pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType == QMICTL_SYNC_REQ) {
717*4882a593Smuzhiyun dprintf("do not allow client send QMICTL_SYNC_REQ\n");
718*4882a593Smuzhiyun return 0;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun if (qlist_empty(&qmi_proxy_ctl_msg))
722*4882a593Smuzhiyun send_qmi_to_cdc_wdm(pQMI);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun qmi_msg = malloc(sizeof(QMI_PROXY_MSG) + size);
725*4882a593Smuzhiyun qlist_init(&qmi_msg->qnode);
726*4882a593Smuzhiyun qmi_msg->ClientFd = clientfd;
727*4882a593Smuzhiyun memcpy(qmi_msg->qmi, pQMI, size);
728*4882a593Smuzhiyun qlist_add_tail(&qmi_proxy_ctl_msg, &qmi_msg->qnode);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun else {
731*4882a593Smuzhiyun send_qmi_to_cdc_wdm(pQMI);
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun return 0;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
qmi_proxy_init(void)737*4882a593Smuzhiyun static int qmi_proxy_init(void) {
738*4882a593Smuzhiyun unsigned i;
739*4882a593Smuzhiyun QCQMIMSG _QMI;
740*4882a593Smuzhiyun PQCQMIMSG pQMI = &_QMI;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun dprintf("%s enter\n", __func__);
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
745*4882a593Smuzhiyun pQMI->QMIHdr.CtlFlags = 0x00;
746*4882a593Smuzhiyun pQMI->QMIHdr.QMIType = QMUX_TYPE_CTL;
747*4882a593Smuzhiyun pQMI->QMIHdr.ClientId= 0x00;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun qmi_sync_done = 0;
752*4882a593Smuzhiyun for (i = 0; i < 10; i++) {
753*4882a593Smuzhiyun pQMI->CTLMsg.SyncReq.TransactionId = i+1;
754*4882a593Smuzhiyun pQMI->CTLMsg.SyncReq.QMICTLType = QMICTL_SYNC_REQ;
755*4882a593Smuzhiyun pQMI->CTLMsg.SyncReq.Length = 0;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun pQMI->QMIHdr.Length =
758*4882a593Smuzhiyun htole16(le16toh(pQMI->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1);
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun if (send_qmi_to_cdc_wdm(pQMI) <= 0)
761*4882a593Smuzhiyun break;
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun sleep(1);
764*4882a593Smuzhiyun if (qmi_sync_done)
765*4882a593Smuzhiyun break;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun dprintf("%s %s\n", __func__, qmi_sync_done ? "succful" : "fail");
769*4882a593Smuzhiyun return qmi_sync_done ? 0 : -1;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
qmi_start_server(const char * servername)772*4882a593Smuzhiyun static void qmi_start_server(const char* servername) {
773*4882a593Smuzhiyun qmi_proxy_server_fd = create_local_server(servername);
774*4882a593Smuzhiyun dprintf("qmi_proxy_server_fd = %d\n", qmi_proxy_server_fd);
775*4882a593Smuzhiyun if (qmi_proxy_server_fd == -1) {
776*4882a593Smuzhiyun dprintf("Failed to create %s, errno: %d (%s)\n", servername, errno, strerror(errno));
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
qmi_close_server(const char * servername)780*4882a593Smuzhiyun static void qmi_close_server(const char* servername) {
781*4882a593Smuzhiyun if (qmi_proxy_server_fd != -1) {
782*4882a593Smuzhiyun dprintf("%s %s close server\n", __func__, servername);
783*4882a593Smuzhiyun close(qmi_proxy_server_fd);
784*4882a593Smuzhiyun qmi_proxy_server_fd = -1;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
qmi_proxy_loop(void * param)788*4882a593Smuzhiyun static void *qmi_proxy_loop(void *param)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun PQCQMIMSG pQMI = (PQCQMIMSG)qmi_buf;
791*4882a593Smuzhiyun struct qlistnode *con_node;
792*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con;
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun (void)param;
795*4882a593Smuzhiyun dprintf("%s enter thread_id %p\n", __func__, (void *)pthread_self());
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun qlist_init(&qmi_proxy_connection);
798*4882a593Smuzhiyun qlist_init(&qmi_proxy_ctl_msg);
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun while (cdc_wdm_fd > 0 && qmi_proxy_quit == 0) {
801*4882a593Smuzhiyun struct pollfd pollfds[2+64];
802*4882a593Smuzhiyun int ne, ret, nevents = 0;
803*4882a593Smuzhiyun ssize_t nreads;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun pollfds[nevents].fd = cdc_wdm_fd;
806*4882a593Smuzhiyun pollfds[nevents].events = POLLIN;
807*4882a593Smuzhiyun pollfds[nevents].revents= 0;
808*4882a593Smuzhiyun nevents++;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun if (qmi_proxy_server_fd > 0) {
811*4882a593Smuzhiyun pollfds[nevents].fd = qmi_proxy_server_fd;
812*4882a593Smuzhiyun pollfds[nevents].events = POLLIN;
813*4882a593Smuzhiyun pollfds[nevents].revents= 0;
814*4882a593Smuzhiyun nevents++;
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun qlist_for_each(con_node, &qmi_proxy_connection) {
818*4882a593Smuzhiyun qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun pollfds[nevents].fd = qmi_con->ClientFd;
821*4882a593Smuzhiyun pollfds[nevents].events = POLLIN;
822*4882a593Smuzhiyun pollfds[nevents].revents= 0;
823*4882a593Smuzhiyun nevents++;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (nevents == (sizeof(pollfds)/sizeof(pollfds[0])))
826*4882a593Smuzhiyun break;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun #if 0
830*4882a593Smuzhiyun dprintf("poll ");
831*4882a593Smuzhiyun for (ne = 0; ne < nevents; ne++) {
832*4882a593Smuzhiyun dprintf("%d ", pollfds[ne].fd);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun dprintf("\n");
835*4882a593Smuzhiyun #endif
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun do {
838*4882a593Smuzhiyun //ret = poll(pollfds, nevents, -1);
839*4882a593Smuzhiyun ret = poll(pollfds, nevents, (qmi_proxy_server_fd > 0) ? -1 : 200);
840*4882a593Smuzhiyun } while (ret == -1 && errno == EINTR && qmi_proxy_quit == 0);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun if (ret < 0) {
843*4882a593Smuzhiyun dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno));
844*4882a593Smuzhiyun goto qmi_proxy_loop_exit;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun for (ne = 0; ne < nevents; ne++) {
848*4882a593Smuzhiyun int fd = pollfds[ne].fd;
849*4882a593Smuzhiyun short revents = pollfds[ne].revents;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
852*4882a593Smuzhiyun dprintf("%s poll fd = %d, revents = %04x\n", __func__, fd, revents);
853*4882a593Smuzhiyun if (fd == cdc_wdm_fd) {
854*4882a593Smuzhiyun goto qmi_proxy_loop_exit;
855*4882a593Smuzhiyun } else if(fd == qmi_proxy_server_fd) {
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun } else {
858*4882a593Smuzhiyun cleanup_qmi_connection(fd);
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun continue;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun if (!(pollfds[ne].revents & POLLIN)) {
865*4882a593Smuzhiyun continue;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun if (fd == qmi_proxy_server_fd) {
869*4882a593Smuzhiyun accept_qmi_connection(fd);
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun else if (fd == cdc_wdm_fd) {
872*4882a593Smuzhiyun nreads = read(fd, pQMI, sizeof(qmi_buf));
873*4882a593Smuzhiyun if (nreads <= 0) {
874*4882a593Smuzhiyun dprintf("%s read=%d errno: %d (%s)\n", __func__, (int)nreads, errno, strerror(errno));
875*4882a593Smuzhiyun goto qmi_proxy_loop_exit;
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun #ifdef QUECTEL_QMI_MERGE
878*4882a593Smuzhiyun if(merge_qmi_rsp_packet(pQMI, &nreads))
879*4882a593Smuzhiyun continue;
880*4882a593Smuzhiyun #endif
881*4882a593Smuzhiyun if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
882*4882a593Smuzhiyun dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
883*4882a593Smuzhiyun continue;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun dump_qmi(pQMI, fd, 'r');
887*4882a593Smuzhiyun recv_qmi_from_dev(pQMI);
888*4882a593Smuzhiyun if (modem_reset_flag)
889*4882a593Smuzhiyun goto qmi_proxy_loop_exit;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun else {
892*4882a593Smuzhiyun nreads = read(fd, pQMI, sizeof(qmi_buf));
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun if (nreads <= 0) {
895*4882a593Smuzhiyun dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
896*4882a593Smuzhiyun cleanup_qmi_connection(fd);
897*4882a593Smuzhiyun break;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
901*4882a593Smuzhiyun dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
902*4882a593Smuzhiyun continue;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun dump_qmi(pQMI, fd, 'r');
906*4882a593Smuzhiyun recv_qmi_from_client(pQMI, nreads, fd);
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun qmi_proxy_loop_exit:
912*4882a593Smuzhiyun while (!qlist_empty(&qmi_proxy_connection)) {
913*4882a593Smuzhiyun QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(qlist_head(&qmi_proxy_connection), QMI_PROXY_CONNECTION, qnode);
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun cleanup_qmi_connection(qmi_con->ClientFd);
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun dprintf("%s exit, thread_id %p\n", __func__, (void *)pthread_self());
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun return NULL;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun
usage(void)923*4882a593Smuzhiyun static void usage(void) {
924*4882a593Smuzhiyun dprintf(" -d <device_name> A valid qmi device\n"
925*4882a593Smuzhiyun " default /dev/cdc-wdm0, but cdc-wdm0 may be invalid\n"
926*4882a593Smuzhiyun " -i <netcard_name> netcard name\n"
927*4882a593Smuzhiyun " -v Will show all details\n");
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun
sig_action(int sig)930*4882a593Smuzhiyun static void sig_action(int sig) {
931*4882a593Smuzhiyun if (qmi_proxy_quit == 0) {
932*4882a593Smuzhiyun qmi_proxy_quit = 1;
933*4882a593Smuzhiyun if (thread_id)
934*4882a593Smuzhiyun pthread_kill(thread_id, sig);
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
main(int argc,char * argv[])938*4882a593Smuzhiyun int main(int argc, char *argv[]) {
939*4882a593Smuzhiyun int opt;
940*4882a593Smuzhiyun char cdc_wdm[32+1] = "/dev/cdc-wdm0";
941*4882a593Smuzhiyun int retry_times = 0;
942*4882a593Smuzhiyun char servername[64] = {0};
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun optind = 1;
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun signal(SIGINT, sig_action);
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun while ( -1 != (opt = getopt(argc, argv, "d:i:vh"))) {
949*4882a593Smuzhiyun switch (opt) {
950*4882a593Smuzhiyun case 'd':
951*4882a593Smuzhiyun strcpy(cdc_wdm, optarg);
952*4882a593Smuzhiyun break;
953*4882a593Smuzhiyun case 'v':
954*4882a593Smuzhiyun verbose_debug = 1;
955*4882a593Smuzhiyun break;
956*4882a593Smuzhiyun default:
957*4882a593Smuzhiyun usage();
958*4882a593Smuzhiyun return 0;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun if (access(cdc_wdm, R_OK | W_OK)) {
963*4882a593Smuzhiyun dprintf("Fail to access %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno));
964*4882a593Smuzhiyun return -1;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun sprintf(servername, "quectel-qmi-proxy%c", cdc_wdm[strlen(cdc_wdm)-1]);
968*4882a593Smuzhiyun dprintf("Will use cdc-wdm='%s', proxy='%s'\n", cdc_wdm, servername);
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun while (qmi_proxy_quit == 0) {
971*4882a593Smuzhiyun if (access(cdc_wdm, R_OK | W_OK)) {
972*4882a593Smuzhiyun dprintf("Fail to access %s, errno: %d (%s). continue\n", cdc_wdm, errno, strerror(errno));
973*4882a593Smuzhiyun // wait device
974*4882a593Smuzhiyun sleep(3);
975*4882a593Smuzhiyun continue;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY);
979*4882a593Smuzhiyun if (cdc_wdm_fd == -1) {
980*4882a593Smuzhiyun dprintf("Failed to open %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno));
981*4882a593Smuzhiyun return -1;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun cfmakenoblock(cdc_wdm_fd);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun /* no qmi_proxy_loop lives, create one */
986*4882a593Smuzhiyun pthread_create(&thread_id, NULL, qmi_proxy_loop, NULL);
987*4882a593Smuzhiyun /* try to redo init if failed, init function must be successfully */
988*4882a593Smuzhiyun while (qmi_proxy_init() != 0) {
989*4882a593Smuzhiyun if (retry_times < 5) {
990*4882a593Smuzhiyun dprintf("fail to init proxy, try again in 2 seconds.\n");
991*4882a593Smuzhiyun sleep(2);
992*4882a593Smuzhiyun retry_times++;
993*4882a593Smuzhiyun } else {
994*4882a593Smuzhiyun dprintf("has failed too much times, restart the modem and have a try...\n");
995*4882a593Smuzhiyun break;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun /* break loop if modem is detached */
998*4882a593Smuzhiyun if (access(cdc_wdm, F_OK|R_OK|W_OK))
999*4882a593Smuzhiyun break;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun retry_times = 0;
1002*4882a593Smuzhiyun qmi_start_server(servername);
1003*4882a593Smuzhiyun if (qmi_proxy_server_fd == -1)
1004*4882a593Smuzhiyun pthread_cancel(thread_id);
1005*4882a593Smuzhiyun pthread_join(thread_id, NULL);
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun /* close local server at last */
1008*4882a593Smuzhiyun qmi_close_server(servername);
1009*4882a593Smuzhiyun close(cdc_wdm_fd);
1010*4882a593Smuzhiyun /* DO RESTART IN 20s IF MODEM RESET ITSELF */
1011*4882a593Smuzhiyun if (modem_reset_flag) {
1012*4882a593Smuzhiyun unsigned int time_to_wait = 20;
1013*4882a593Smuzhiyun while (time_to_wait) {
1014*4882a593Smuzhiyun time_to_wait = sleep(time_to_wait);
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun modem_reset_flag = 0;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun return 0;
1021*4882a593Smuzhiyun }
1022