You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

430 lines
13 KiB

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