xref: /OK3568_Linux_fs/app/forlinx/quectelCM/quectel-qmi-proxy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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