xref: /OK3568_Linux_fs/app/forlinx/quectelCM/quectel-mbim-proxy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun #include <unistd.h>
2*4882a593Smuzhiyun #include <stdlib.h>
3*4882a593Smuzhiyun #include <stdio.h>
4*4882a593Smuzhiyun #include <string.h>
5*4882a593Smuzhiyun #include <errno.h>
6*4882a593Smuzhiyun #include <stdarg.h>
7*4882a593Smuzhiyun #include <stddef.h>
8*4882a593Smuzhiyun #include <fcntl.h>
9*4882a593Smuzhiyun #include <pthread.h>
10*4882a593Smuzhiyun #include <poll.h>
11*4882a593Smuzhiyun #include <sys/socket.h>
12*4882a593Smuzhiyun #include <sys/time.h>
13*4882a593Smuzhiyun #include <sys/ioctl.h>
14*4882a593Smuzhiyun #include <linux/un.h>
15*4882a593Smuzhiyun #include <linux/in.h>
16*4882a593Smuzhiyun #include <linux/if.h>
17*4882a593Smuzhiyun #include <dirent.h>
18*4882a593Smuzhiyun #include <signal.h>
19*4882a593Smuzhiyun #include <endian.h>
20*4882a593Smuzhiyun #include <inttypes.h>
21*4882a593Smuzhiyun #include <getopt.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define QUECTEL_MBIM_PROXY "quectel-mbim-proxy"
24*4882a593Smuzhiyun #define safe_close(_fd) do { if (_fd > 0) { close(_fd); _fd = -1; } } while(0)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define CM_MAX_CLIENT 32
27*4882a593Smuzhiyun #define TID_MASK (0xFFFFFF)
28*4882a593Smuzhiyun #define TID_SHIFT (24)
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun typedef enum {
31*4882a593Smuzhiyun     MBIM_OPEN_MSG = 1,
32*4882a593Smuzhiyun     MBIM_CLOSE_MSG = 2,
33*4882a593Smuzhiyun     MBIM_OPEN_DONE = 0x80000001,
34*4882a593Smuzhiyun     MBIM_CLOSE_DONE = 0x80000002,
35*4882a593Smuzhiyun } MBIM_MSG;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun typedef struct {
38*4882a593Smuzhiyun     unsigned int  MessageType;
39*4882a593Smuzhiyun     unsigned int  MessageLength;
40*4882a593Smuzhiyun     unsigned int  TransactionId;
41*4882a593Smuzhiyun } MBIM_MESSAGE_HEADER;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun typedef struct {
44*4882a593Smuzhiyun     MBIM_MESSAGE_HEADER MessageHeader;
45*4882a593Smuzhiyun     unsigned int MaxControlTransfer;
46*4882a593Smuzhiyun } MBIM_OPEN_MSG_T;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun typedef struct {
49*4882a593Smuzhiyun     MBIM_MESSAGE_HEADER MessageHeader;
50*4882a593Smuzhiyun     unsigned int Status;
51*4882a593Smuzhiyun } MBIM_OPEN_DONE_T;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun typedef struct {
54*4882a593Smuzhiyun     int client_fd;
55*4882a593Smuzhiyun     int client_idx;
56*4882a593Smuzhiyun } CM_CLIENT_T;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun static unsigned char cm_recv_buffer[4096];
59*4882a593Smuzhiyun static CM_CLIENT_T cm_clients[CM_MAX_CLIENT];
60*4882a593Smuzhiyun static int verbose = 0;
61*4882a593Smuzhiyun 
get_time(void)62*4882a593Smuzhiyun const char * get_time(void) {
63*4882a593Smuzhiyun     static char time_buf[128];
64*4882a593Smuzhiyun     struct timeval  tv;
65*4882a593Smuzhiyun     time_t time;
66*4882a593Smuzhiyun     suseconds_t millitm;
67*4882a593Smuzhiyun     struct tm *ti;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun     gettimeofday (&tv, NULL);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun     time= tv.tv_sec;
72*4882a593Smuzhiyun     millitm = (tv.tv_usec + 500) / 1000;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun     if (millitm == 1000) {
75*4882a593Smuzhiyun         ++time;
76*4882a593Smuzhiyun         millitm = 0;
77*4882a593Smuzhiyun     }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun     ti = localtime(&time);
80*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);
81*4882a593Smuzhiyun     return time_buf;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define mbim_debug(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } while(0);
85*4882a593Smuzhiyun 
non_block_write(int fd,void * data,int len)86*4882a593Smuzhiyun static int non_block_write(int fd, void *data, int len)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun     int ret;
89*4882a593Smuzhiyun     struct pollfd pollfd = {fd, POLLOUT, 0};
90*4882a593Smuzhiyun     ret = poll(&pollfd, 1, 3000);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun     if (ret <= 0) {
93*4882a593Smuzhiyun         mbim_debug("%s poll ret=%d, errno: %d(%s)\n", __func__, ret, errno, strerror(errno));
94*4882a593Smuzhiyun     }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun     ret = write (fd, data, len);
97*4882a593Smuzhiyun     if (ret != len)
98*4882a593Smuzhiyun         mbim_debug("%s write ret=%d, errno: %d(%s)\n", __func__, ret, errno, strerror(errno));
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun     return len;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
mbim_send_open_msg(int mbim_dev_fd,uint32_t MaxControlTransfer)103*4882a593Smuzhiyun static int mbim_send_open_msg(int mbim_dev_fd, uint32_t MaxControlTransfer) {
104*4882a593Smuzhiyun     MBIM_OPEN_MSG_T open_msg;
105*4882a593Smuzhiyun     MBIM_OPEN_MSG_T *pRequest = &open_msg;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun     pRequest->MessageHeader.MessageType = (MBIM_OPEN_MSG);
108*4882a593Smuzhiyun     pRequest->MessageHeader.MessageLength = (sizeof(MBIM_OPEN_MSG_T));
109*4882a593Smuzhiyun     pRequest->MessageHeader.TransactionId = (1);
110*4882a593Smuzhiyun     pRequest->MaxControlTransfer = (MaxControlTransfer);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun     mbim_debug("%s()\n", __func__);
113*4882a593Smuzhiyun     return non_block_write(mbim_dev_fd, pRequest, sizeof(MBIM_OPEN_MSG_T));
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun  * parameter: proxy name
118*4882a593Smuzhiyun  * return: local proxy server fd or -1
119*4882a593Smuzhiyun */
proxy_make_server(const char * proxy_name)120*4882a593Smuzhiyun static int proxy_make_server(const char *proxy_name)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun     int len, flag;
123*4882a593Smuzhiyun     struct sockaddr_un sockaddr;
124*4882a593Smuzhiyun     int mbim_server_fd;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun     mbim_server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
127*4882a593Smuzhiyun     if (mbim_server_fd < 0) {
128*4882a593Smuzhiyun         mbim_debug("socket failed: %s\n", strerror(errno));
129*4882a593Smuzhiyun         return -1;
130*4882a593Smuzhiyun     }
131*4882a593Smuzhiyun     if (fcntl(mbim_server_fd, F_SETFL, fcntl(mbim_server_fd, F_GETFL) | O_NONBLOCK) < 0)
132*4882a593Smuzhiyun         mbim_debug("fcntl set server(%d) NONBLOCK attribute failed: %s\n", mbim_server_fd, strerror(errno));
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun     memset(&sockaddr, 0, sizeof(sockaddr));
135*4882a593Smuzhiyun     sockaddr.sun_family = AF_LOCAL;
136*4882a593Smuzhiyun     sockaddr.sun_path[0] = 0;
137*4882a593Smuzhiyun     snprintf(sockaddr.sun_path, UNIX_PATH_MAX, "0%s", proxy_name);
138*4882a593Smuzhiyun     sockaddr.sun_path[0] = '\0';  // string starts with leading '\0'
139*4882a593Smuzhiyun     flag = 1;
140*4882a593Smuzhiyun     if (setsockopt(mbim_server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) {
141*4882a593Smuzhiyun         safe_close(mbim_server_fd);
142*4882a593Smuzhiyun         mbim_debug("setsockopt failed\n");
143*4882a593Smuzhiyun     }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun     len = strlen(proxy_name) + offsetof(struct sockaddr_un, sun_path) + 1;
146*4882a593Smuzhiyun     if (bind(mbim_server_fd, (struct sockaddr*)&sockaddr, len) < 0) {
147*4882a593Smuzhiyun         safe_close(mbim_server_fd);
148*4882a593Smuzhiyun         mbim_debug("bind failed: %s\n", strerror(errno));
149*4882a593Smuzhiyun         return -1;
150*4882a593Smuzhiyun     }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun     listen(mbim_server_fd, 4);
153*4882a593Smuzhiyun     return mbim_server_fd;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
handle_client_connect(int server_fd)156*4882a593Smuzhiyun static int handle_client_connect(int server_fd)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun     int i, client_fd;
159*4882a593Smuzhiyun     struct sockaddr_in cli_addr;
160*4882a593Smuzhiyun     socklen_t len = sizeof(cli_addr);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun     client_fd = accept(server_fd, (struct sockaddr *)&cli_addr, &len);
163*4882a593Smuzhiyun     if (client_fd < 0) {
164*4882a593Smuzhiyun         mbim_debug("proxy accept failed: %s\n", strerror(errno));
165*4882a593Smuzhiyun         return -1;
166*4882a593Smuzhiyun     }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun     if (fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL) | O_NONBLOCK) < 0)
169*4882a593Smuzhiyun         mbim_debug("fcntl set client(%d) NONBLOCK attribute failed: %s\n", client_fd, strerror(errno));
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun     for (i = 0; i < CM_MAX_CLIENT; i++) {
172*4882a593Smuzhiyun         if (cm_clients[i].client_fd <= 0) {
173*4882a593Smuzhiyun             cm_clients[i].client_fd = client_fd;
174*4882a593Smuzhiyun             cm_clients[i].client_idx= i+1;
175*4882a593Smuzhiyun             mbim_debug("%s client_fd=%d, client_idx=%d\n", __func__, cm_clients[i].client_fd, cm_clients[i].client_idx);
176*4882a593Smuzhiyun             return 0;
177*4882a593Smuzhiyun         }
178*4882a593Smuzhiyun     }
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun     close(client_fd);
181*4882a593Smuzhiyun     return -1;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
handle_client_disconnect(int client_fd)184*4882a593Smuzhiyun static void handle_client_disconnect(int client_fd)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun     int i;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun     for (i = 0; i < CM_MAX_CLIENT; i++) {
189*4882a593Smuzhiyun         if (cm_clients[i].client_fd == client_fd) {
190*4882a593Smuzhiyun             mbim_debug("%s client_fd=%d, client_idx=%d\n", __func__, cm_clients[i].client_fd, cm_clients[i].client_idx);
191*4882a593Smuzhiyun             safe_close(cm_clients[i].client_fd);
192*4882a593Smuzhiyun             return;
193*4882a593Smuzhiyun         }
194*4882a593Smuzhiyun     }
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
handle_client_request(int mbim_dev_fd,int client_fd,void * pdata,int len)197*4882a593Smuzhiyun static int handle_client_request(int mbim_dev_fd, int client_fd, void *pdata, int len)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun     int i;
200*4882a593Smuzhiyun     int client_idx = -1;
201*4882a593Smuzhiyun     int ret;
202*4882a593Smuzhiyun     MBIM_MESSAGE_HEADER *pRequest = (MBIM_MESSAGE_HEADER *)pdata;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun     for (i = 0; i < CM_MAX_CLIENT; i++) {
205*4882a593Smuzhiyun         if (cm_clients[i].client_fd == client_fd) {
206*4882a593Smuzhiyun             client_idx = cm_clients[i].client_idx;
207*4882a593Smuzhiyun             break;
208*4882a593Smuzhiyun         }
209*4882a593Smuzhiyun     }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun     if (client_idx == -1) {
212*4882a593Smuzhiyun         goto error;
213*4882a593Smuzhiyun     }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun     /* transfer TransicationID to proxy transicationID and record in sender list */
216*4882a593Smuzhiyun     pRequest->TransactionId = (pRequest->TransactionId & TID_MASK) + (client_idx << TID_SHIFT);
217*4882a593Smuzhiyun     if (verbose) mbim_debug("REQ client_fd=%d, client_idx=%d, tid=%u\n", cm_clients[i].client_fd, cm_clients[i].client_idx, (pRequest->TransactionId & TID_MASK));
218*4882a593Smuzhiyun     ret = non_block_write (mbim_dev_fd, pRequest, len);
219*4882a593Smuzhiyun     if (ret == len)
220*4882a593Smuzhiyun         return 0;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun error:
223*4882a593Smuzhiyun     return -1;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun /*
227*4882a593Smuzhiyun  * Will read message from device and transfer it to clients/client
228*4882a593Smuzhiyun  * Notice:
229*4882a593Smuzhiyun  *  unsocial message will be send to all clients
230*4882a593Smuzhiyun  */
handle_device_response(void * pdata,int len)231*4882a593Smuzhiyun static int handle_device_response(void *pdata, int len)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun     int i;
234*4882a593Smuzhiyun     MBIM_MESSAGE_HEADER *pResponse = (MBIM_MESSAGE_HEADER *)pdata;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun     /* unsocial/function error message */
237*4882a593Smuzhiyun     if (pResponse->TransactionId == 0) {
238*4882a593Smuzhiyun         for (i = 0; i < CM_MAX_CLIENT; i++) {
239*4882a593Smuzhiyun             if (cm_clients[i].client_fd > 0) {
240*4882a593Smuzhiyun                 non_block_write(cm_clients[i].client_fd, pResponse, len);
241*4882a593Smuzhiyun             }
242*4882a593Smuzhiyun         }
243*4882a593Smuzhiyun     }
244*4882a593Smuzhiyun     else {
245*4882a593Smuzhiyun         /* try to find the sender */
246*4882a593Smuzhiyun         int client_idx = (pResponse->TransactionId >> TID_SHIFT);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun         for (i = 0; i < CM_MAX_CLIENT; i++) {
249*4882a593Smuzhiyun             if (cm_clients[i].client_idx == client_idx && cm_clients[i].client_fd > 0) {
250*4882a593Smuzhiyun                 pResponse->TransactionId &= TID_MASK;
251*4882a593Smuzhiyun                 if (verbose) mbim_debug("RSP client_fd=%d, client_idx=%d, tid=%u\n", cm_clients[i].client_fd, cm_clients[i].client_idx, (pResponse->TransactionId & TID_MASK));
252*4882a593Smuzhiyun                 non_block_write(cm_clients[i].client_fd, pResponse, len);
253*4882a593Smuzhiyun                 break;
254*4882a593Smuzhiyun             }
255*4882a593Smuzhiyun         }
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun         if ( i == CM_MAX_CLIENT) {
258*4882a593Smuzhiyun            mbim_debug("%s nobody care tid=%u\n", __func__, pResponse->TransactionId);
259*4882a593Smuzhiyun         }
260*4882a593Smuzhiyun     }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun     return 0;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
proxy_loop(int mbim_dev_fd)265*4882a593Smuzhiyun static int proxy_loop(int mbim_dev_fd)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun     int i;
268*4882a593Smuzhiyun     int mbim_server_fd = -1;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun     while (mbim_dev_fd > 0) {
271*4882a593Smuzhiyun         struct pollfd pollfds[2+CM_MAX_CLIENT];
272*4882a593Smuzhiyun         int ne, ret, nevents = 0;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun         pollfds[nevents].fd = mbim_dev_fd;
275*4882a593Smuzhiyun         pollfds[nevents].events = POLLIN;
276*4882a593Smuzhiyun         pollfds[nevents].revents= 0;
277*4882a593Smuzhiyun         nevents++;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun         if (mbim_server_fd > 0) {
280*4882a593Smuzhiyun             pollfds[nevents].fd = mbim_server_fd;
281*4882a593Smuzhiyun             pollfds[nevents].events = POLLIN;
282*4882a593Smuzhiyun             pollfds[nevents].revents= 0;
283*4882a593Smuzhiyun             nevents++;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun             for (i = 0; i < CM_MAX_CLIENT; i++) {
286*4882a593Smuzhiyun                 if (cm_clients[i].client_fd > 0) {
287*4882a593Smuzhiyun                     pollfds[nevents].fd = cm_clients[i].client_fd;
288*4882a593Smuzhiyun                     pollfds[nevents].events = POLLIN;
289*4882a593Smuzhiyun                     pollfds[nevents].revents= 0;
290*4882a593Smuzhiyun                     nevents++;
291*4882a593Smuzhiyun                 }
292*4882a593Smuzhiyun             }
293*4882a593Smuzhiyun         }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun         ret = poll(pollfds, nevents, (mbim_server_fd > 0) ? -1 : (10*1000));
296*4882a593Smuzhiyun         if (ret <= 0) {
297*4882a593Smuzhiyun             goto error;
298*4882a593Smuzhiyun         }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun         for (ne = 0; ne < nevents; ne++) {
301*4882a593Smuzhiyun             int fd = pollfds[ne].fd;
302*4882a593Smuzhiyun             short revents = pollfds[ne].revents;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun             if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
305*4882a593Smuzhiyun                 mbim_debug("%s poll fd = %d, revents = %04x\n", __func__, fd, revents);
306*4882a593Smuzhiyun                 if (fd == mbim_dev_fd) {
307*4882a593Smuzhiyun                     goto error;
308*4882a593Smuzhiyun                 } else if(fd == mbim_server_fd) {
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun                 } else {
311*4882a593Smuzhiyun                     handle_client_disconnect(fd);
312*4882a593Smuzhiyun                 }
313*4882a593Smuzhiyun                 continue;
314*4882a593Smuzhiyun             }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun             if (!(pollfds[ne].revents & POLLIN)) {
317*4882a593Smuzhiyun                 continue;
318*4882a593Smuzhiyun             }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun             if (fd == mbim_server_fd) {
321*4882a593Smuzhiyun                 handle_client_connect(fd);
322*4882a593Smuzhiyun             }
323*4882a593Smuzhiyun             else {
324*4882a593Smuzhiyun                     int len = read(fd, cm_recv_buffer, sizeof(cm_recv_buffer));
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun                     if (len <= 0) {
327*4882a593Smuzhiyun                         mbim_debug("%s read fd=%d, len=%d, errno: %d(%s)\n", __func__, fd, len, errno, strerror(errno));
328*4882a593Smuzhiyun                         if (fd == mbim_dev_fd)
329*4882a593Smuzhiyun                             goto error;
330*4882a593Smuzhiyun                         else
331*4882a593Smuzhiyun                             handle_client_disconnect(fd);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun                         return len;
334*4882a593Smuzhiyun                     }
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun                     if (fd == mbim_dev_fd) {
337*4882a593Smuzhiyun                         if (mbim_server_fd == -1) {
338*4882a593Smuzhiyun                             MBIM_OPEN_DONE_T *pOpenDone = (MBIM_OPEN_DONE_T *)cm_recv_buffer;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun                             if (pOpenDone->MessageHeader.MessageType == MBIM_OPEN_DONE) {
341*4882a593Smuzhiyun                                 mbim_debug("receive MBIM_OPEN_DONE, status=%d\n", pOpenDone->Status);
342*4882a593Smuzhiyun                                 if (pOpenDone->Status)
343*4882a593Smuzhiyun                                     goto error;
344*4882a593Smuzhiyun                                 mbim_server_fd = proxy_make_server(QUECTEL_MBIM_PROXY);
345*4882a593Smuzhiyun                                 mbim_debug("mbim_server_fd=%d\n", mbim_server_fd);
346*4882a593Smuzhiyun                             }
347*4882a593Smuzhiyun                         }
348*4882a593Smuzhiyun                         else {
349*4882a593Smuzhiyun                             handle_device_response(cm_recv_buffer, len);
350*4882a593Smuzhiyun                         }
351*4882a593Smuzhiyun                     }
352*4882a593Smuzhiyun                     else {
353*4882a593Smuzhiyun                         handle_client_request(mbim_dev_fd, fd, cm_recv_buffer, len);
354*4882a593Smuzhiyun                     }
355*4882a593Smuzhiyun             }
356*4882a593Smuzhiyun         }
357*4882a593Smuzhiyun     }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun error:
360*4882a593Smuzhiyun     safe_close(mbim_server_fd);
361*4882a593Smuzhiyun     for (i = 0; i < CM_MAX_CLIENT; i++) {
362*4882a593Smuzhiyun         safe_close(cm_clients[i].client_fd);
363*4882a593Smuzhiyun     }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun     mbim_debug("%s exit\n", __func__);
366*4882a593Smuzhiyun     return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun /*
370*4882a593Smuzhiyun  * How to use this proxy?
371*4882a593Smuzhiyun  * 1. modprobe -a 8021q
372*4882a593Smuzhiyun  * 2. Create network interface for channels:
373*4882a593Smuzhiyun  *      ip link add link wwan0 name wwan0.1 type vlan id 1
374*4882a593Smuzhiyun  *      ip link add link wwan0 name wwan0.2 type vlan id 2
375*4882a593Smuzhiyun  * 3. Start './mbim-proxy' with -d 'device'
376*4882a593Smuzhiyun  * 4. Start Clients: ./quectel-CM -n id1
377*4882a593Smuzhiyun  * 5. Start Clients: ./quectel-CM -n id2
378*4882a593Smuzhiyun  * ...
379*4882a593Smuzhiyun  * Notice:
380*4882a593Smuzhiyun  *      mbim-proxy can work in backgroud as a daemon
381*4882a593Smuzhiyun  *      '-n' sessionID
382*4882a593Smuzhiyun  *  The modem may not support multi-PDN mode or how many PDN it supports is undefined. It depends!!!
383*4882a593Smuzhiyun  *  Besides, some modem also may not support some sessionID. For instance EC20 doesn't support SessionId 1...
384*4882a593Smuzhiyun  */
main(int argc,char ** argv)385*4882a593Smuzhiyun int main(int argc, char **argv)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun     int optidx = 0;
388*4882a593Smuzhiyun     int opt;
389*4882a593Smuzhiyun     char *optstr = "d:vh";
390*4882a593Smuzhiyun     const char *device = "/dev/cdc-wdm0";
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun     struct option options[] = {
393*4882a593Smuzhiyun         {"verbose", no_argument,        NULL, 'v'},
394*4882a593Smuzhiyun         {"device", required_argument,   NULL, 'd'},
395*4882a593Smuzhiyun         {0, 0, 0, 0},
396*4882a593Smuzhiyun     };
397*4882a593Smuzhiyun     while ((opt = getopt_long(argc, argv, optstr, options, &optidx)) != -1) {
398*4882a593Smuzhiyun         switch (opt) {
399*4882a593Smuzhiyun         case 'v':
400*4882a593Smuzhiyun             verbose = 1;
401*4882a593Smuzhiyun             break;
402*4882a593Smuzhiyun         case 'd':
403*4882a593Smuzhiyun             device = optarg;
404*4882a593Smuzhiyun             break;
405*4882a593Smuzhiyun         case 'h':
406*4882a593Smuzhiyun             mbim_debug("-h              Show this message\n");
407*4882a593Smuzhiyun             mbim_debug("-v              Verbose\n");
408*4882a593Smuzhiyun             mbim_debug("-d [device]     MBIM device\n");
409*4882a593Smuzhiyun             return 0;
410*4882a593Smuzhiyun         default:
411*4882a593Smuzhiyun             mbim_debug("illegal argument\n");
412*4882a593Smuzhiyun             return -1;
413*4882a593Smuzhiyun         }
414*4882a593Smuzhiyun     }
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun     if (!device) {
417*4882a593Smuzhiyun         mbim_debug("Missing parameter: device\n");
418*4882a593Smuzhiyun         return -1;
419*4882a593Smuzhiyun     }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun     while (1) {
422*4882a593Smuzhiyun         int mbim_dev_fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY);
423*4882a593Smuzhiyun         if (mbim_dev_fd < 0) {
424*4882a593Smuzhiyun             mbim_debug("cannot open mbim_device %s: %s\n", device, strerror(errno));
425*4882a593Smuzhiyun             sleep(2);
426*4882a593Smuzhiyun             continue;
427*4882a593Smuzhiyun         }
428*4882a593Smuzhiyun         mbim_debug ("mbim_dev_fd=%d\n", mbim_dev_fd);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun         memset(cm_clients, 0, sizeof(cm_clients));
431*4882a593Smuzhiyun         mbim_send_open_msg(mbim_dev_fd, sizeof(cm_recv_buffer));
432*4882a593Smuzhiyun         proxy_loop(mbim_dev_fd);
433*4882a593Smuzhiyun         safe_close(mbim_dev_fd);
434*4882a593Smuzhiyun     }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun     return -1;
437*4882a593Smuzhiyun }
438