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.

1546 lines
53 KiB

2 years ago
  1. /******************************************************************************
  2. @file quectel-qmi-proxy.c
  3. @brief The qmi proxy.
  4. DESCRIPTION
  5. Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
  6. INITIALIZATION AND SEQUENCING REQUIREMENTS
  7. None.
  8. ---------------------------------------------------------------------------
  9. Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
  10. Quectel Wireless Solution Proprietary and Confidential.
  11. ---------------------------------------------------------------------------
  12. ******************************************************************************/
  13. #include <unistd.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <stdarg.h>
  19. #include <stddef.h>
  20. #include <fcntl.h>
  21. #include <pthread.h>
  22. #include <poll.h>
  23. #include <sys/socket.h>
  24. #include <sys/time.h>
  25. #include <sys/ioctl.h>
  26. #include <linux/un.h>
  27. #include <linux/if.h>
  28. #include <dirent.h>
  29. #include <signal.h>
  30. #include <endian.h>
  31. #include <inttypes.h>
  32. #ifndef MIN
  33. #define MIN(a, b) ((a) < (b)? (a): (b))
  34. #endif
  35. #ifndef htole32
  36. #if __BYTE_ORDER == __LITTLE_ENDIAN
  37. #define htole16(x) (uint16_t)(x)
  38. #define le16toh(x) (uint16_t)(x)
  39. #define letoh16(x) (uint16_t)(x)
  40. #define htole32(x) (uint32_t)(x)
  41. #define le32toh(x) (uint32_t)(x)
  42. #define letoh32(x) (uint32_t)(x)
  43. #define htole64(x) (uint64_t)(x)
  44. #define le64toh(x) (uint64_t)(x)
  45. #define letoh64(x) (uint64_t)(x)
  46. #else
  47. static __inline uint16_t __bswap16(uint16_t __x) {
  48. return (__x<<8) | (__x>>8);
  49. }
  50. static __inline uint32_t __bswap32(uint32_t __x) {
  51. return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
  52. }
  53. static __inline uint64_t __bswap64(uint64_t __x) {
  54. return (__bswap32(__x)+0ULL<<32) | (__bswap32(__x>>32));
  55. }
  56. #define htole16(x) __bswap16(x)
  57. #define le16toh(x) __bswap16(x)
  58. #define letoh16(x) __bswap16(x)
  59. #define htole32(x) __bswap32(x)
  60. #define le32toh(x) __bswap32(x)
  61. #define letoh32(x) __bswap32(x)
  62. #define htole64(x) __bswap64(x)
  63. #define le64toh(x) __bswap64(x)
  64. #define letoh64(x) __bswap64(x)
  65. #endif
  66. #endif
  67. #define dprintf(fmt, arg...) do { printf(fmt, ##arg); } while(0)
  68. #define SYSCHECK(c) do{if((c)<0) {dprintf("%s %d error: '%s' (code: %d)\n", __func__, __LINE__, strerror(errno), errno); return -1;}}while(0)
  69. #define cfmakenoblock(fd) do{fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);}while(0)
  70. #define qmidev_is_pciemhi(_qmichannel) (strncmp(_qmichannel, "/dev/mhi_", strlen("/dev/mhi_")) == 0)
  71. typedef struct _QCQMI_HDR
  72. {
  73. uint8_t IFType;
  74. uint16_t Length;
  75. uint8_t CtlFlags; // reserved
  76. uint8_t QMIType;
  77. uint8_t ClientId;
  78. } __attribute__ ((packed)) QCQMI_HDR, *PQCQMI_HDR;
  79. typedef struct _QMICTL_SYNC_REQ_MSG
  80. {
  81. uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
  82. uint8_t TransactionId;
  83. uint16_t QMICTLType; // QMICTL_CTL_SYNC_REQ
  84. uint16_t Length; // 0
  85. } __attribute__ ((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG;
  86. typedef struct _QMICTL_SYNC_RESP_MSG
  87. {
  88. uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
  89. uint8_t TransactionId;
  90. uint16_t QMICTLType; // QMICTL_CTL_SYNC_RESP
  91. uint16_t Length;
  92. uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
  93. uint16_t TLVLength; // 0x0004
  94. uint16_t QMIResult;
  95. uint16_t QMIError;
  96. } __attribute__ ((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG;
  97. typedef struct _QMICTL_SYNC_IND_MSG
  98. {
  99. uint8_t CtlFlags; // QMICTL_FLAG_INDICATION
  100. uint8_t TransactionId;
  101. uint16_t QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
  102. uint16_t Length;
  103. } __attribute__ ((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG;
  104. typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG
  105. {
  106. uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
  107. uint8_t TransactionId;
  108. uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_REQ
  109. uint16_t Length;
  110. uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
  111. uint16_t TLVLength; // 1
  112. uint8_t QMIType; // QMUX type
  113. } __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG, *PQMICTL_GET_CLIENT_ID_REQ_MSG;
  114. typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG
  115. {
  116. uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
  117. uint8_t TransactionId;
  118. uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_RESP
  119. uint16_t Length;
  120. uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
  121. uint16_t TLVLength; // 0x0004
  122. uint16_t QMIResult; // result code
  123. uint16_t QMIError; // error code
  124. uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
  125. uint16_t TLV2Length; // 2
  126. uint8_t QMIType;
  127. uint8_t ClientId;
  128. } __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG, *PQMICTL_GET_CLIENT_ID_RESP_MSG;
  129. typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG
  130. {
  131. uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
  132. uint8_t TransactionId;
  133. uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ
  134. uint16_t Length;
  135. uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
  136. uint16_t TLVLength; // 0x0002
  137. uint8_t QMIType;
  138. uint8_t ClientId;
  139. } __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG, *PQMICTL_RELEASE_CLIENT_ID_REQ_MSG;
  140. typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG
  141. {
  142. uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
  143. uint8_t TransactionId;
  144. uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP
  145. uint16_t Length;
  146. uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
  147. uint16_t TLVLength; // 0x0004
  148. uint16_t QMIResult; // result code
  149. uint16_t QMIError; // error code
  150. uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
  151. uint16_t TLV2Length; // 2
  152. uint8_t QMIType;
  153. uint8_t ClientId;
  154. } __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG, *PQMICTL_RELEASE_CLIENT_ID_RESP_MSG;
  155. // QMICTL Control Flags
  156. #define QMICTL_CTL_FLAG_CMD 0x00
  157. #define QMICTL_CTL_FLAG_RSP 0x01
  158. #define QMICTL_CTL_FLAG_IND 0x02
  159. typedef struct _QCQMICTL_MSG_HDR
  160. {
  161. uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind
  162. uint8_t TransactionId;
  163. uint16_t QMICTLType;
  164. uint16_t Length;
  165. } __attribute__ ((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR;
  166. #define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR)
  167. typedef struct _QCQMICTL_MSG_HDR_RESP
  168. {
  169. uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind
  170. uint8_t TransactionId;
  171. uint16_t QMICTLType;
  172. uint16_t Length;
  173. uint8_t TLVType; // 0x02 - result code
  174. uint16_t TLVLength; // 4
  175. uint16_t QMUXResult; // QMI_RESULT_SUCCESS
  176. // QMI_RESULT_FAILURE
  177. uint16_t QMUXError; // QMI_ERR_INVALID_ARG
  178. // QMI_ERR_NO_MEMORY
  179. // QMI_ERR_INTERNAL
  180. // QMI_ERR_FAULT
  181. } __attribute__ ((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP;
  182. typedef struct _QMICTL_GET_VERSION_REQ_MSG
  183. {
  184. uint8_t CtlFlags; // QMICTL_FLAG_REQUEST
  185. uint8_t TransactionId;
  186. uint16_t QMICTLType; // QMICTL_GET_VERSION_REQ
  187. uint16_t Length; // 0
  188. uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
  189. uint16_t TLVLength; // var
  190. uint8_t QMUXTypes; // List of one byte QMUX_TYPE values
  191. // 0xFF returns a list of versions for all
  192. // QMUX_TYPEs implemented on the device
  193. } __attribute__ ((packed)) QMICTL_GET_VERSION_REQ_MSG, *PQMICTL_GET_VERSION_REQ_MSG;
  194. typedef struct _QMUX_TYPE_VERSION_STRUCT
  195. {
  196. uint8_t QMUXType;
  197. uint16_t MajorVersion;
  198. uint16_t MinorVersion;
  199. } __attribute__ ((packed)) QMUX_TYPE_VERSION_STRUCT, *PQMUX_TYPE_VERSION_STRUCT;
  200. typedef struct _QMICTL_GET_VERSION_RESP_MSG
  201. {
  202. uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE
  203. uint8_t TransactionId;
  204. uint16_t QMICTLType; // QMICTL_GET_VERSION_RESP
  205. uint16_t Length;
  206. uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE
  207. uint16_t TLVLength; // 0x0004
  208. uint16_t QMIResult;
  209. uint16_t QMIError;
  210. uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
  211. uint16_t TLV2Length; // var
  212. uint8_t NumElements; // Num of QMUX_TYPE_VERSION_STRUCT
  213. QMUX_TYPE_VERSION_STRUCT TypeVersion[0];
  214. } __attribute__ ((packed)) QMICTL_GET_VERSION_RESP_MSG, *PQMICTL_GET_VERSION_RESP_MSG;
  215. typedef struct _QMICTL_MSG
  216. {
  217. union
  218. {
  219. // Message Header
  220. QCQMICTL_MSG_HDR QMICTLMsgHdr;
  221. QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp;
  222. // QMICTL Message
  223. //QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq;
  224. //QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp;
  225. QMICTL_GET_VERSION_REQ_MSG GetVersionReq;
  226. QMICTL_GET_VERSION_RESP_MSG GetVersionRsp;
  227. QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq;
  228. QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp;
  229. //QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq;
  230. QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp;
  231. //QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd;
  232. //QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd;
  233. //QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
  234. //QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp;
  235. QMICTL_SYNC_REQ_MSG SyncReq;
  236. QMICTL_SYNC_RESP_MSG SyncRsp;
  237. QMICTL_SYNC_IND_MSG SyncInd;
  238. };
  239. } __attribute__ ((packed)) QMICTL_MSG, *PQMICTL_MSG;
  240. typedef struct _QCQMUX_MSG_HDR
  241. {
  242. uint8_t CtlFlags; // 0: single QMUX Msg; 1:
  243. uint16_t TransactionId;
  244. uint16_t Type;
  245. uint16_t Length;
  246. uint8_t payload[0];
  247. } __attribute__ ((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR;
  248. typedef struct _QCQMUX_MSG_HDR_RESP
  249. {
  250. uint8_t CtlFlags; // 0: single QMUX Msg; 1:
  251. uint16_t TransactionId;
  252. uint16_t Type;
  253. uint16_t Length;
  254. uint8_t TLVType; // 0x02 - result code
  255. uint16_t TLVLength; // 4
  256. uint16_t QMUXResult; // QMI_RESULT_SUCCESS
  257. // QMI_RESULT_FAILURE
  258. uint16_t QMUXError; // QMI_ERR_INVALID_ARG
  259. // QMI_ERR_NO_MEMORY
  260. // QMI_ERR_INTERNAL
  261. // QMI_ERR_FAULT
  262. } __attribute__ ((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP;
  263. typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT
  264. {
  265. uint16_t Type; // QMUX type 0x0000
  266. uint16_t Length;
  267. } __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT, *PQMIWDS_ADMIN_SET_DATA_FORMAT;
  268. typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS
  269. {
  270. uint8_t TLVType;
  271. uint16_t TLVLength;
  272. uint8_t QOSSetting;
  273. } __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS, *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS;
  274. typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV
  275. {
  276. uint8_t TLVType;
  277. uint16_t TLVLength;
  278. uint32_t Value;
  279. } __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV, *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV;
  280. typedef struct _QMIWDS_ENDPOINT_TLV
  281. {
  282. uint8_t TLVType;
  283. uint16_t TLVLength;
  284. uint32_t ep_type;
  285. uint32_t iface_id;
  286. } __attribute__ ((packed)) QMIWDS_ENDPOINT_TLV, *PQMIWDS_ENDPOINT_TLV;
  287. #define QUECTEL_UL_DATA_AGG
  288. typedef uint32_t UINT;
  289. typedef struct {
  290. UINT size;
  291. UINT rx_urb_size;
  292. UINT ep_type;
  293. UINT iface_id;
  294. UINT MuxId;
  295. UINT ul_data_aggregation_max_datagrams; //0x17
  296. UINT ul_data_aggregation_max_size ;//0x18
  297. UINT dl_minimum_padding; //0x1A
  298. } QMAP_SETTING;
  299. typedef struct {
  300. unsigned int size;
  301. unsigned int rx_urb_size;
  302. unsigned int ep_type;
  303. unsigned int iface_id;
  304. unsigned int qmap_mode;
  305. unsigned int qmap_version;
  306. unsigned int dl_minimum_padding;
  307. char ifname[8][16];
  308. unsigned char mux_id[8];
  309. } RMNET_INFO;
  310. typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG
  311. {
  312. uint8_t CtlFlags; // 0: single QMUX Msg; 1:
  313. uint16_t TransactionId;
  314. uint16_t Type;
  315. uint16_t Length;
  316. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS QosDataFormatTlv;
  317. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UnderlyingLinkLayerProtocolTlv;
  318. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationProtocolTlv;
  319. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationProtocolTlv;
  320. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxDatagramsTlv;
  321. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxSizeTlv;
  322. QMIWDS_ENDPOINT_TLV epTlv;
  323. #ifdef QUECTEL_UL_DATA_AGG
  324. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DlMinimumPassingTlv;
  325. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationMaxDatagramsTlv;
  326. QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationMaxSizeTlv;
  327. #endif
  328. } __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG, *PQMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG;
  329. typedef struct _QCQMUX_TLV
  330. {
  331. uint8_t Type;
  332. uint16_t Length;
  333. uint8_t Value[0];
  334. } __attribute__ ((packed)) QCQMUX_TLV, *PQCQMUX_TLV;
  335. typedef struct _QMUX_MSG
  336. {
  337. union
  338. {
  339. // Message Header
  340. QCQMUX_MSG_HDR QMUXMsgHdr;
  341. QCQMUX_MSG_HDR_RESP QMUXMsgHdrResp;
  342. QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
  343. };
  344. } __attribute__ ((packed)) QMUX_MSG, *PQMUX_MSG;
  345. typedef struct _QCQMIMSG {
  346. QCQMI_HDR QMIHdr;
  347. union {
  348. QMICTL_MSG CTLMsg;
  349. QMUX_MSG MUXMsg;
  350. };
  351. } __attribute__ ((packed)) QCQMIMSG, *PQCQMIMSG;
  352. // QMUX Message Definitions -- QMI SDU
  353. #define QMUX_CTL_FLAG_SINGLE_MSG 0x00
  354. #define QMUX_CTL_FLAG_COMPOUND_MSG 0x01
  355. #define QMUX_CTL_FLAG_TYPE_CMD 0x00
  356. #define QMUX_CTL_FLAG_TYPE_RSP 0x02
  357. #define QMUX_CTL_FLAG_TYPE_IND 0x04
  358. #define QMUX_CTL_FLAG_MASK_COMPOUND 0x01
  359. #define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind
  360. #define USB_CTL_MSG_TYPE_QMI 0x01
  361. #define QMICTL_FLAG_REQUEST 0x00
  362. #define QMICTL_FLAG_RESPONSE 0x01
  363. #define QMICTL_FLAG_INDICATION 0x02
  364. // QMICTL Type
  365. #define QMICTL_SET_INSTANCE_ID_REQ 0x0020
  366. #define QMICTL_SET_INSTANCE_ID_RESP 0x0020
  367. #define QMICTL_GET_VERSION_REQ 0x0021
  368. #define QMICTL_GET_VERSION_RESP 0x0021
  369. #define QMICTL_GET_CLIENT_ID_REQ 0x0022
  370. #define QMICTL_GET_CLIENT_ID_RESP 0x0022
  371. #define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023
  372. #define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023
  373. #define QMICTL_REVOKE_CLIENT_ID_IND 0x0024
  374. #define QMICTL_INVALID_CLIENT_ID_IND 0x0025
  375. #define QMICTL_SET_DATA_FORMAT_REQ 0x0026
  376. #define QMICTL_SET_DATA_FORMAT_RESP 0x0026
  377. #define QMICTL_SYNC_REQ 0x0027
  378. #define QMICTL_SYNC_RESP 0x0027
  379. #define QMICTL_SYNC_IND 0x0027
  380. #define QCTLV_TYPE_REQUIRED_PARAMETER 0x01
  381. // Define QMI Type
  382. typedef enum _QMI_SERVICE_TYPE
  383. {
  384. QMUX_TYPE_CTL = 0x00,
  385. QMUX_TYPE_WDS = 0x01,
  386. QMUX_TYPE_DMS = 0x02,
  387. QMUX_TYPE_NAS = 0x03,
  388. QMUX_TYPE_QOS = 0x04,
  389. QMUX_TYPE_WMS = 0x05,
  390. QMUX_TYPE_PDS = 0x06,
  391. QMUX_TYPE_UIM = 0x0B,
  392. QMUX_TYPE_WDS_IPV6 = 0x11,
  393. QMUX_TYPE_WDS_ADMIN = 0x1A,
  394. QMUX_TYPE_MAX = 0xFF,
  395. QMUX_TYPE_ALL = 0xFF
  396. } QMI_SERVICE_TYPE;
  397. #define QMIWDS_ADMIN_SET_DATA_FORMAT_REQ 0x0020
  398. #define QMIWDS_ADMIN_SET_DATA_FORMAT_RESP 0x0020
  399. struct qlistnode
  400. {
  401. struct qlistnode *next;
  402. struct qlistnode *prev;
  403. };
  404. #define qnode_to_item(node, container, member) \
  405. (container *) (((char*) (node)) - offsetof(container, member))
  406. #define qlist_for_each(node, list) \
  407. for (node = (list)->next; node != (list); node = node->next)
  408. #define qlist_empty(list) ((list) == (list)->next)
  409. #define qlist_head(list) ((list)->next)
  410. #define qlist_tail(list) ((list)->prev)
  411. typedef struct {
  412. struct qlistnode qnode;
  413. uint8_t ClientFd;
  414. QCQMIMSG qmi[0];
  415. } QMI_PROXY_MSG;
  416. typedef struct {
  417. struct qlistnode qnode;
  418. uint8_t QMIType;
  419. uint8_t ClientId;
  420. unsigned AccessTime;
  421. } QMI_PROXY_CLINET;
  422. typedef struct {
  423. struct qlistnode qnode;
  424. struct qlistnode client_qnode;
  425. uint8_t ClientFd;
  426. unsigned AccessTime;
  427. } QMI_PROXY_CONNECTION;
  428. static void qlist_init(struct qlistnode *node)
  429. {
  430. node->next = node;
  431. node->prev = node;
  432. }
  433. static void qlist_add_tail(struct qlistnode *head, struct qlistnode *item)
  434. {
  435. item->next = head;
  436. item->prev = head->prev;
  437. head->prev->next = item;
  438. head->prev = item;
  439. }
  440. static void qlist_remove(struct qlistnode *item)
  441. {
  442. item->next->prev = item->prev;
  443. item->prev->next = item->next;
  444. }
  445. static int qmi_proxy_quit = 0;
  446. static pthread_t thread_id = 0;
  447. static int cdc_wdm_fd = -1;
  448. static int qmi_proxy_server_fd = -1;
  449. static struct qlistnode qmi_proxy_connection;
  450. static struct qlistnode qmi_proxy_ctl_msg;
  451. static PQCQMIMSG s_pCtlReq;
  452. static PQCQMIMSG s_pCtlRsq;
  453. static pthread_mutex_t s_ctlmutex = PTHREAD_MUTEX_INITIALIZER;
  454. static pthread_cond_t s_ctlcond = PTHREAD_COND_INITIALIZER;
  455. static void ql_get_driver_rmnet_info(char *ifname, RMNET_INFO *rmnet_info) {
  456. int ifc_ctl_sock;
  457. struct ifreq ifr;
  458. int rc;
  459. int request = 0x89F3;
  460. unsigned char data[512];
  461. memset(rmnet_info, 0x00, sizeof(*rmnet_info));
  462. ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
  463. if (ifc_ctl_sock <= 0) {
  464. dprintf("socket() failed: %s\n", strerror(errno));
  465. return;
  466. }
  467. memset(&ifr, 0, sizeof(struct ifreq));
  468. strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  469. ifr.ifr_name[IFNAMSIZ - 1] = 0;
  470. ifr.ifr_ifru.ifru_data = (void *)data;
  471. rc = ioctl(ifc_ctl_sock, request, &ifr);
  472. if (rc < 0) {
  473. dprintf("ioctl(0x%x, rmnet_info) failed: %s, rc=%d", request, strerror(errno), rc);
  474. }
  475. else {
  476. memcpy(rmnet_info, data, sizeof(*rmnet_info));
  477. }
  478. close(ifc_ctl_sock);
  479. }
  480. static void ql_set_driver_qmap_setting(char *ifname, QMAP_SETTING *qmap_settings) {
  481. int ifc_ctl_sock;
  482. struct ifreq ifr;
  483. int rc;
  484. int request = 0x89F2;
  485. ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
  486. if (ifc_ctl_sock <= 0) {
  487. dprintf("socket() failed: %s\n", strerror(errno));
  488. return;
  489. }
  490. memset(&ifr, 0, sizeof(struct ifreq));
  491. strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  492. ifr.ifr_name[IFNAMSIZ - 1] = 0;
  493. ifr.ifr_ifru.ifru_data = (void *)qmap_settings;
  494. rc = ioctl(ifc_ctl_sock, request, &ifr);
  495. if (rc < 0) {
  496. dprintf("ioctl(0x%x, qmap_settings) failed: %s, rc=%d\n", request, strerror(errno), rc);
  497. }
  498. close(ifc_ctl_sock);
  499. }
  500. static void setTimespecRelative(struct timespec *p_ts, long long msec)
  501. {
  502. struct timeval tv;
  503. gettimeofday(&tv, (struct timezone *) NULL);
  504. /* what's really funny about this is that I know
  505. pthread_cond_timedwait just turns around and makes this
  506. a relative time again */
  507. p_ts->tv_sec = tv.tv_sec + (msec / 1000);
  508. p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L;
  509. if (p_ts->tv_nsec >= 1000000000UL) {
  510. p_ts->tv_sec += 1;
  511. p_ts->tv_nsec -= 1000000000UL;
  512. }
  513. }
  514. static int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs) {
  515. if (msecs != 0) {
  516. unsigned i;
  517. unsigned t = msecs/4;
  518. int ret = 0;
  519. if (t == 0)
  520. t = 1;
  521. for (i = 0; i < msecs; i += t) {
  522. struct timespec ts;
  523. setTimespecRelative(&ts, t);
  524. ret = pthread_cond_timedwait(cond, mutex, &ts); //to advoid system time change
  525. if (ret != ETIMEDOUT) {
  526. if(ret) dprintf("ret=%d, msecs=%u, t=%u", ret, msecs, t);
  527. break;
  528. }
  529. }
  530. return ret;
  531. } else {
  532. return pthread_cond_wait(cond, mutex);
  533. }
  534. }
  535. static int create_local_server(const char *name) {
  536. int sockfd = -1;
  537. int reuse_addr = 1;
  538. struct sockaddr_un sockaddr;
  539. socklen_t alen;
  540. /*Create server socket*/
  541. SYSCHECK(sockfd = socket(AF_LOCAL, SOCK_STREAM, 0));
  542. memset(&sockaddr, 0, sizeof(sockaddr));
  543. sockaddr.sun_family = AF_LOCAL;
  544. sockaddr.sun_path[0] = 0;
  545. memcpy(sockaddr.sun_path + 1, name, strlen(name) );
  546. alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
  547. SYSCHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr)));
  548. if(bind(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) {
  549. close(sockfd);
  550. dprintf("%s bind %s errno: %d (%s)\n", __func__, name, errno, strerror(errno));
  551. return -1;
  552. }
  553. dprintf("local server: %s sockfd = %d\n", name, sockfd);
  554. cfmakenoblock(sockfd);
  555. listen(sockfd, 1);
  556. return sockfd;
  557. }
  558. static void accept_qmi_connection(int serverfd) {
  559. int clientfd = -1;
  560. unsigned char addr[128];
  561. socklen_t alen = sizeof(addr);
  562. QMI_PROXY_CONNECTION *qmi_con;
  563. clientfd = accept(serverfd, (struct sockaddr *)addr, &alen);
  564. qmi_con = (QMI_PROXY_CONNECTION *)malloc(sizeof(QMI_PROXY_CONNECTION));
  565. if (qmi_con) {
  566. qlist_init(&qmi_con->qnode);
  567. qlist_init(&qmi_con->client_qnode);
  568. qmi_con->ClientFd= clientfd;
  569. qmi_con->AccessTime = 0;
  570. dprintf("+++ ClientFd=%d\n", qmi_con->ClientFd);
  571. qlist_add_tail(&qmi_proxy_connection, &qmi_con->qnode);
  572. }
  573. cfmakenoblock(clientfd);
  574. }
  575. static void cleanup_qmi_connection(int clientfd) {
  576. struct qlistnode *con_node, *qmi_node;
  577. qlist_for_each(con_node, &qmi_proxy_connection) {
  578. QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
  579. if (qmi_con->ClientFd == clientfd) {
  580. while (!qlist_empty(&qmi_con->client_qnode)) {
  581. QMI_PROXY_CLINET *qmi_client = qnode_to_item(qlist_head(&qmi_con->client_qnode), QMI_PROXY_CLINET, qnode);
  582. dprintf("xxx ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
  583. qlist_remove(&qmi_client->qnode);
  584. free(qmi_client);
  585. }
  586. qlist_for_each(qmi_node, &qmi_proxy_ctl_msg) {
  587. QMI_PROXY_MSG *qmi_msg = qnode_to_item(qmi_node, QMI_PROXY_MSG, qnode);
  588. if (qmi_msg->ClientFd == qmi_con->ClientFd) {
  589. qlist_remove(&qmi_msg->qnode);
  590. free(qmi_msg);
  591. break;
  592. }
  593. }
  594. dprintf("--- ClientFd=%d\n", qmi_con->ClientFd);
  595. close(qmi_con->ClientFd);
  596. qlist_remove(&qmi_con->qnode);
  597. free(qmi_con);
  598. break;
  599. }
  600. }
  601. }
  602. static void get_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_GET_CLIENT_ID_RESP_MSG pClient) {
  603. if (pClient->QMIResult == 0 && pClient->QMIError == 0) {
  604. QMI_PROXY_CLINET *qmi_client = (QMI_PROXY_CLINET *)malloc(sizeof(QMI_PROXY_CLINET));
  605. qlist_init(&qmi_client->qnode);
  606. qmi_client->QMIType = pClient->QMIType;
  607. qmi_client->ClientId = pClient->ClientId;
  608. qmi_client->AccessTime = 0;
  609. dprintf("+++ ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
  610. qlist_add_tail(&qmi_con->client_qnode, &qmi_client->qnode);
  611. }
  612. }
  613. static void release_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_RELEASE_CLIENT_ID_RESP_MSG pClient) {
  614. struct qlistnode *client_node;
  615. if (pClient->QMIResult == 0 && pClient->QMIError == 0) {
  616. qlist_for_each (client_node, &qmi_con->client_qnode) {
  617. QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode);
  618. if (pClient->QMIType == qmi_client->QMIType && pClient->ClientId == qmi_client->ClientId) {
  619. dprintf("--- ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
  620. qlist_remove(&qmi_client->qnode);
  621. free(qmi_client);
  622. break;
  623. }
  624. }
  625. }
  626. }
  627. static int verbose_debug = 0;
  628. static int send_qmi_to_cdc_wdm(PQCQMIMSG pQMI) {
  629. struct pollfd pollfds[]= {{cdc_wdm_fd, POLLOUT, 0}};
  630. ssize_t ret = 0;
  631. do {
  632. ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
  633. } while ((ret < 0) && (errno == EINTR));
  634. if (pollfds[0].revents & POLLOUT) {
  635. ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
  636. ret = write(cdc_wdm_fd, pQMI, size);
  637. if (verbose_debug)
  638. {
  639. ssize_t i;
  640. printf("w %d %zd: ", cdc_wdm_fd, ret);
  641. for (i = 0; i < size; i++)
  642. printf("%02x ", ((uint8_t *)pQMI)[i]);
  643. printf("\n");
  644. }
  645. }
  646. return ret;
  647. }
  648. static int send_qmi_to_client(PQCQMIMSG pQMI, int clientFd) {
  649. struct pollfd pollfds[]= {{clientFd, POLLOUT, 0}};
  650. ssize_t ret = 0;
  651. do {
  652. ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
  653. } while ((ret < 0) && (errno == EINTR));
  654. if (pollfds[0].revents & POLLOUT) {
  655. ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
  656. ret = write(clientFd, pQMI, size);
  657. if (verbose_debug)
  658. {
  659. ssize_t i;
  660. printf("w %d %zd: ", clientFd, ret);
  661. for (i = 0; i < 16; i++)
  662. printf("%02x ", ((uint8_t *)pQMI)[i]);
  663. printf("\n");
  664. }
  665. }
  666. return ret;
  667. }
  668. static int modem_reset_flag = 0;
  669. static void recv_qmi(PQCQMIMSG pQMI, unsigned size) {
  670. struct qlistnode *con_node, *client_node;
  671. if (qmi_proxy_server_fd <= 0) {
  672. pthread_mutex_lock(&s_ctlmutex);
  673. if (s_pCtlReq != NULL) {
  674. if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL
  675. && s_pCtlReq->CTLMsg.QMICTLMsgHdrRsp.TransactionId == pQMI->CTLMsg.QMICTLMsgHdrRsp.TransactionId) {
  676. s_pCtlRsq = malloc(size);
  677. memcpy(s_pCtlRsq, pQMI, size);
  678. pthread_cond_signal(&s_ctlcond);
  679. }
  680. else if (pQMI->QMIHdr.QMIType != QMUX_TYPE_CTL
  681. && s_pCtlReq->MUXMsg.QMUXMsgHdr.TransactionId == pQMI->MUXMsg.QMUXMsgHdr.TransactionId) {
  682. s_pCtlRsq = malloc(size);
  683. memcpy(s_pCtlRsq, pQMI, size);
  684. pthread_cond_signal(&s_ctlcond);
  685. }
  686. }
  687. pthread_mutex_unlock(&s_ctlmutex);
  688. }
  689. else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) {
  690. if (pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags == QMICTL_CTL_FLAG_RSP) {
  691. if (!qlist_empty(&qmi_proxy_ctl_msg)) {
  692. QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode);
  693. qlist_for_each(con_node, &qmi_proxy_connection) {
  694. QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
  695. if (qmi_con->ClientFd == qmi_msg->ClientFd) {
  696. send_qmi_to_client(pQMI, qmi_msg->ClientFd);
  697. if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_GET_CLIENT_ID_RESP)
  698. get_client_id(qmi_con, &pQMI->CTLMsg.GetClientIdRsp);
  699. else if ((le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_RELEASE_CLIENT_ID_RESP) ||
  700. (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_REVOKE_CLIENT_ID_IND)) {
  701. release_client_id(qmi_con, &pQMI->CTLMsg.ReleaseClientIdRsp);
  702. if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_REVOKE_CLIENT_ID_IND)
  703. modem_reset_flag = 1;
  704. }
  705. else {
  706. }
  707. }
  708. }
  709. qlist_remove(&qmi_msg->qnode);
  710. free(qmi_msg);
  711. }
  712. }
  713. if (!qlist_empty(&qmi_proxy_ctl_msg)) {
  714. QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode);
  715. qlist_for_each(con_node, &qmi_proxy_connection) {
  716. QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
  717. if (qmi_con->ClientFd == qmi_msg->ClientFd) {
  718. send_qmi_to_cdc_wdm(qmi_msg->qmi);
  719. }
  720. }
  721. }
  722. }
  723. else {
  724. qlist_for_each(con_node, &qmi_proxy_connection) {
  725. QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
  726. qlist_for_each(client_node, &qmi_con->client_qnode) {
  727. QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode);
  728. if (pQMI->QMIHdr.QMIType == qmi_client->QMIType) {
  729. if (pQMI->QMIHdr.ClientId == 0 || pQMI->QMIHdr.ClientId == qmi_client->ClientId) {
  730. send_qmi_to_client(pQMI, qmi_con->ClientFd);
  731. }
  732. }
  733. }
  734. }
  735. }
  736. }
  737. static int send_qmi(PQCQMIMSG pQMI, unsigned size, int clientfd) {
  738. if (qmi_proxy_server_fd <= 0) {
  739. send_qmi_to_cdc_wdm(pQMI);
  740. }
  741. else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) {
  742. QMI_PROXY_MSG *qmi_msg;
  743. if (qlist_empty(&qmi_proxy_ctl_msg))
  744. send_qmi_to_cdc_wdm(pQMI);
  745. qmi_msg = malloc(sizeof(QMI_PROXY_MSG) + size);
  746. qlist_init(&qmi_msg->qnode);
  747. qmi_msg->ClientFd = clientfd;
  748. memcpy(qmi_msg->qmi, pQMI, size);
  749. qlist_add_tail(&qmi_proxy_ctl_msg, &qmi_msg->qnode);
  750. }
  751. else {
  752. send_qmi_to_cdc_wdm(pQMI);
  753. }
  754. return 0;
  755. }
  756. static int send_qmi_timeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, unsigned mseconds) {
  757. int ret;
  758. pthread_mutex_lock(&s_ctlmutex);
  759. s_pCtlReq = pRequest;
  760. s_pCtlRsq = NULL;
  761. if (ppResponse) *ppResponse = NULL;
  762. send_qmi_to_cdc_wdm(pRequest);
  763. ret = pthread_cond_timeout_np(&s_ctlcond, &s_ctlmutex, mseconds);
  764. if (!ret) {
  765. if (s_pCtlRsq && ppResponse) {
  766. *ppResponse = s_pCtlRsq;
  767. } else if (s_pCtlRsq) {
  768. free(s_pCtlRsq);
  769. }
  770. } else {
  771. dprintf("%s ret=%d\n", __func__, ret);
  772. }
  773. s_pCtlReq = NULL;
  774. pthread_mutex_unlock(&s_ctlmutex);
  775. return ret;
  776. }
  777. static PQCQMUX_TLV qmi_find_tlv (PQCQMIMSG pQMI, uint8_t TLVType) {
  778. int Length = 0;
  779. while (Length < le16toh(pQMI->MUXMsg.QMUXMsgHdr.Length)) {
  780. PQCQMUX_TLV pTLV = (PQCQMUX_TLV)(&pQMI->MUXMsg.QMUXMsgHdr.payload[Length]);
  781. //dprintf("TLV {%02x, %04x}\n", pTLV->Type, pTLV->Length);
  782. if (pTLV->Type == TLVType) {
  783. return pTLV;
  784. }
  785. Length += (le16toh((pTLV->Length)) + sizeof(QCQMUX_TLV));
  786. }
  787. return NULL;
  788. }
  789. static int qmi_proxy_init(char *qmi_device, char *ifname) {
  790. unsigned i;
  791. int ret;
  792. QCQMIMSG _QMI;
  793. PQCQMIMSG pQMI = &_QMI;
  794. PQCQMIMSG pRsp;
  795. uint8_t TransactionId = 0xC1;
  796. uint8_t WDAClientId = 0;
  797. unsigned rx_urb_size = 0;
  798. unsigned ep_type, iface_id;
  799. unsigned qmap_version;
  800. QMAP_SETTING qmap_settings = {0};
  801. RMNET_INFO rmnet_info;
  802. dprintf("%s enter\n", __func__);
  803. pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
  804. pQMI->QMIHdr.CtlFlags = 0x00;
  805. pQMI->QMIHdr.QMIType = QMUX_TYPE_CTL;
  806. pQMI->QMIHdr.ClientId= 0x00;
  807. pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST;
  808. for (i = 0; i < 10; i++) {
  809. pQMI->CTLMsg.SyncReq.TransactionId = TransactionId++;
  810. pQMI->CTLMsg.SyncReq.QMICTLType = QMICTL_SYNC_REQ;
  811. pQMI->CTLMsg.SyncReq.Length = 0;
  812. pQMI->QMIHdr.Length =
  813. htole16(le16toh(pQMI->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1);
  814. ret = send_qmi_timeout(pQMI, NULL, 1000);
  815. if (!ret)
  816. break;
  817. }
  818. if (ret)
  819. goto qmi_proxy_init_fail;
  820. pQMI->CTLMsg.GetVersionReq.TransactionId = TransactionId++;
  821. pQMI->CTLMsg.GetVersionReq.QMICTLType = htole16(QMICTL_GET_VERSION_REQ);
  822. pQMI->CTLMsg.GetVersionReq.Length = htole16(0x0004);
  823. pQMI->CTLMsg.GetVersionReq.TLVType= QCTLV_TYPE_REQUIRED_PARAMETER;
  824. pQMI->CTLMsg.GetVersionReq.TLVLength = htole16(0x0001);
  825. pQMI->CTLMsg.GetVersionReq.QMUXTypes = QMUX_TYPE_ALL;
  826. pQMI->QMIHdr.Length = htole16(le16toh(pQMI->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1);
  827. ret = send_qmi_timeout(pQMI, &pRsp, 3000);
  828. if (ret || (pRsp == NULL))
  829. goto qmi_proxy_init_fail;
  830. if (pRsp) {
  831. uint8_t NumElements = 0;
  832. if (pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult ||pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError) {
  833. dprintf("QMICTL_GET_VERSION_REQ QMUXResult=%d, QMUXError=%d\n",
  834. le16toh(pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult), le16toh(pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError));
  835. goto qmi_proxy_init_fail;
  836. }
  837. for (NumElements = 0; NumElements < pRsp->CTLMsg.GetVersionRsp.NumElements; NumElements++) {
  838. if (verbose_debug)
  839. dprintf("QMUXType = %02x Version = %d.%d\n",
  840. pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].QMUXType,
  841. le16toh(pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MajorVersion),
  842. le16toh(pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MinorVersion));
  843. }
  844. }
  845. free(pRsp);
  846. pQMI->CTLMsg.GetClientIdReq.TransactionId = TransactionId++;
  847. pQMI->CTLMsg.GetClientIdReq.QMICTLType = htole16(QMICTL_GET_CLIENT_ID_REQ);
  848. pQMI->CTLMsg.GetClientIdReq.Length = htole16(0x0004);
  849. pQMI->CTLMsg.GetClientIdReq.TLVType= QCTLV_TYPE_REQUIRED_PARAMETER;
  850. pQMI->CTLMsg.GetClientIdReq.TLVLength = htole16(0x0001);
  851. pQMI->CTLMsg.GetClientIdReq.QMIType = QMUX_TYPE_WDS_ADMIN;
  852. pQMI->QMIHdr.Length = htole16(le16toh(pQMI->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1);
  853. ret = send_qmi_timeout(pQMI, &pRsp, 3000);
  854. if (ret || (pRsp == NULL))
  855. goto qmi_proxy_init_fail;
  856. if (pRsp) {
  857. if (pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult ||pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError) {
  858. dprintf("QMICTL_GET_CLIENT_ID_REQ QMUXResult=%d, QMUXError=%d\n",
  859. le16toh(pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult), le16toh(pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError));
  860. goto qmi_proxy_init_fail;
  861. }
  862. WDAClientId = pRsp->CTLMsg.GetClientIdRsp.ClientId;
  863. if (verbose_debug) dprintf("WDAClientId = %d\n", WDAClientId);
  864. }
  865. free(pRsp);
  866. rx_urb_size = 16*1024; //must same as rx_urb_size defined in GobiNet&qmi_wwan driver //SDX24&SDX55 support 32KB
  867. if(qmidev_is_pciemhi(qmi_device))
  868. ep_type = 0x03;
  869. else
  870. ep_type = 0x02;
  871. iface_id = 0x04;
  872. qmap_version = 5;
  873. qmap_settings.size = sizeof(qmap_settings);
  874. qmap_settings.ul_data_aggregation_max_datagrams = 16;
  875. qmap_settings.ul_data_aggregation_max_size = 8*1024;
  876. qmap_settings.dl_minimum_padding = 11; //16->11
  877. ql_get_driver_rmnet_info(ifname, &rmnet_info);
  878. if (rmnet_info.size) {
  879. rx_urb_size = rmnet_info.rx_urb_size;
  880. ep_type = rmnet_info.ep_type;
  881. iface_id = rmnet_info.iface_id;
  882. qmap_version = rmnet_info.qmap_version;
  883. qmap_settings.dl_minimum_padding = rmnet_info.dl_minimum_padding;
  884. }
  885. qmap_settings.dl_minimum_padding = 0; //no effect when register to real netowrk
  886. pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
  887. pQMI->QMIHdr.CtlFlags = 0x00;
  888. pQMI->QMIHdr.QMIType = QMUX_TYPE_WDS_ADMIN;
  889. pQMI->QMIHdr.ClientId= WDAClientId;
  890. pQMI->MUXMsg.QMUXMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST;
  891. pQMI->MUXMsg.QMUXMsgHdr.TransactionId = htole16(TransactionId++);
  892. pQMI->MUXMsg.SetDataFormatReq.Type = htole16(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ);
  893. pQMI->MUXMsg.SetDataFormatReq.Length = htole16(sizeof(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG) - sizeof(QCQMUX_MSG_HDR));
  894. //Indicates whether the Quality of Service(QOS) data format is used by the client.
  895. pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.TLVType = 0x10;
  896. pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.TLVLength = htole16(0x0001);
  897. pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.QOSSetting = 0; /* no-QOS header */
  898. //Underlying Link Layer Protocol
  899. pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVType = 0x11;
  900. pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVLength = htole16(4);
  901. pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.Value = htole32(0x02); /* Set IP mode */
  902. //Uplink (UL) data aggregation protocol to be used for uplink data transfer.
  903. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVType = 0x12;
  904. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVLength = htole16(4);
  905. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.Value = htole32(qmap_version); //UL QMAP is enabled
  906. //Downlink (DL) data aggregation protocol to be used for downlink data transfer
  907. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVType = 0x13;
  908. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVLength = htole16(4);
  909. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.Value = htole32(qmap_version); //UL QMAP is enabled
  910. //Maximum number of datagrams in a single aggregated packet on downlink
  911. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.TLVType = 0x15;
  912. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.TLVLength = htole16(4);
  913. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.Value = htole32((rx_urb_size>2048)?(rx_urb_size/1024):1);
  914. //Maximum size in bytes of a single aggregated packet allowed on downlink
  915. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVType = 0x16;
  916. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVLength = htole16(4);
  917. pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.Value = htole32(rx_urb_size);
  918. //Peripheral End Point ID
  919. pQMI->MUXMsg.SetDataFormatReq.epTlv.TLVType = 0x17;
  920. pQMI->MUXMsg.SetDataFormatReq.epTlv.TLVLength = htole16(8);
  921. pQMI->MUXMsg.SetDataFormatReq.epTlv.ep_type = htole32(ep_type); // DATA_EP_TYPE_BAM_DMUX
  922. pQMI->MUXMsg.SetDataFormatReq.epTlv.iface_id = htole32(iface_id);
  923. #ifdef QUECTEL_UL_DATA_AGG
  924. //Maximum number of datagrams in a single aggregated packet on uplink
  925. pQMI->MUXMsg.SetDataFormatReq.DlMinimumPassingTlv.TLVType = 0x19;
  926. pQMI->MUXMsg.SetDataFormatReq.DlMinimumPassingTlv.TLVLength = htole16(4);
  927. pQMI->MUXMsg.SetDataFormatReq.DlMinimumPassingTlv.Value = htole32(qmap_settings.dl_minimum_padding);
  928. //Maximum number of datagrams in a single aggregated packet on uplink
  929. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxDatagramsTlv.TLVType = 0x1B;
  930. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxDatagramsTlv.TLVLength = htole16(4);
  931. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxDatagramsTlv.Value = htole32(qmap_settings.ul_data_aggregation_max_datagrams);
  932. //Maximum size in bytes of a single aggregated packet allowed on downlink
  933. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxSizeTlv.TLVType = 0x1C;
  934. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxSizeTlv.TLVLength = htole16(4);
  935. pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationMaxSizeTlv.Value = htole32(qmap_settings.ul_data_aggregation_max_size);
  936. #endif
  937. pQMI->QMIHdr.Length = htole16(le16toh(pQMI->MUXMsg.QMUXMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMUX_MSG_HDR) - 1);
  938. ret = send_qmi_timeout(pQMI, &pRsp, 3000);
  939. if (ret || (pRsp == NULL))
  940. goto qmi_proxy_init_fail;
  941. if (pRsp) {
  942. PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV pFormat;
  943. if (pRsp->MUXMsg.QMUXMsgHdrResp.QMUXResult || pRsp->MUXMsg.QMUXMsgHdrResp.QMUXError) {
  944. dprintf("QMIWDS_ADMIN_SET_DATA_FORMAT_REQ QMUXResult=%d, QMUXError=%d\n",
  945. le16toh(pRsp->MUXMsg.QMUXMsgHdrResp.QMUXResult), le16toh(pRsp->MUXMsg.QMUXMsgHdrResp.QMUXError));
  946. goto qmi_proxy_init_fail;
  947. }
  948. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x11);
  949. if (pFormat)
  950. dprintf("link_prot %d\n", le32toh(pFormat->Value));
  951. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x12);
  952. if (pFormat)
  953. dprintf("ul_data_aggregation_protocol %d\n", le32toh(pFormat->Value));
  954. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x13);
  955. if (pFormat)
  956. dprintf("dl_data_aggregation_protocol %d\n", le32toh(pFormat->Value));
  957. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x15);
  958. if (pFormat)
  959. dprintf("dl_data_aggregation_max_datagrams %d\n", le32toh(pFormat->Value));
  960. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x16);
  961. if (pFormat) {
  962. dprintf("dl_data_aggregation_max_size %d\n", le32toh(pFormat->Value));
  963. rx_urb_size = le32toh(pFormat->Value);
  964. }
  965. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x17);
  966. if (pFormat) {
  967. qmap_settings.ul_data_aggregation_max_datagrams = MIN(qmap_settings.ul_data_aggregation_max_datagrams, le32toh(pFormat->Value));
  968. dprintf("ul_data_aggregation_max_datagrams %d\n", qmap_settings.ul_data_aggregation_max_datagrams);
  969. }
  970. pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x18);
  971. if (pFormat) {
  972. qmap_settings.ul_data_aggregation_max_size = MIN(qmap_settings.ul_data_aggregation_max_size, le32toh(pFormat->Value));
  973. dprintf("ul_data_aggregation_max_size %d\n", qmap_settings.ul_data_aggregation_max_size);
  974. }
  975. if (qmap_settings.ul_data_aggregation_max_datagrams > 1) {
  976. ql_set_driver_qmap_setting(ifname, &qmap_settings);
  977. }
  978. }
  979. free(pRsp);
  980. dprintf("%s finished, rx_urb_size is %u\n", __func__, rx_urb_size);
  981. return 0;
  982. qmi_proxy_init_fail:
  983. dprintf("%s failed\n", __func__);
  984. return -1;
  985. }
  986. static void qmi_start_server(const char* servername) {
  987. qmi_proxy_server_fd = create_local_server(servername);
  988. printf("%s: qmi_proxy_server_fd = %d\n", __func__, qmi_proxy_server_fd);
  989. if (qmi_proxy_server_fd == -1) {
  990. dprintf("%s Failed to create %s, errno: %d (%s)\n", __func__, "quectel-qmi-proxy", errno, strerror(errno));
  991. }
  992. }
  993. static void qmi_close_server(const char* servername) {
  994. if (qmi_proxy_server_fd != -1) {
  995. dprintf("%s %s close server\n", __func__, servername);
  996. close(qmi_proxy_server_fd);
  997. qmi_proxy_server_fd = -1;
  998. }
  999. }
  1000. static uint8_t qmi_buf[2048];
  1001. static void *qmi_proxy_loop(void *param)
  1002. {
  1003. PQCQMIMSG pQMI = (PQCQMIMSG)qmi_buf;
  1004. struct qlistnode *con_node;
  1005. QMI_PROXY_CONNECTION *qmi_con;
  1006. dprintf("%s enter thread_id %p\n", __func__, (void *)pthread_self());
  1007. qlist_init(&qmi_proxy_connection);
  1008. qlist_init(&qmi_proxy_ctl_msg);
  1009. while (cdc_wdm_fd > 0 && qmi_proxy_quit == 0) {
  1010. struct pollfd pollfds[2+64];
  1011. int ne, ret, nevents = 0;
  1012. ssize_t nreads;
  1013. pollfds[nevents].fd = cdc_wdm_fd;
  1014. pollfds[nevents].events = POLLIN;
  1015. pollfds[nevents].revents= 0;
  1016. nevents++;
  1017. if (qmi_proxy_server_fd > 0) {
  1018. pollfds[nevents].fd = qmi_proxy_server_fd;
  1019. pollfds[nevents].events = POLLIN;
  1020. pollfds[nevents].revents= 0;
  1021. nevents++;
  1022. }
  1023. qlist_for_each(con_node, &qmi_proxy_connection) {
  1024. qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode);
  1025. pollfds[nevents].fd = qmi_con->ClientFd;
  1026. pollfds[nevents].events = POLLIN;
  1027. pollfds[nevents].revents= 0;
  1028. nevents++;
  1029. if (nevents == (sizeof(pollfds)/sizeof(pollfds[0])))
  1030. break;
  1031. }
  1032. #if 0
  1033. dprintf("poll ");
  1034. for (ne = 0; ne < nevents; ne++) {
  1035. dprintf("%d ", pollfds[ne].fd);
  1036. }
  1037. dprintf("\n");
  1038. #endif
  1039. do {
  1040. //ret = poll(pollfds, nevents, -1);
  1041. ret = poll(pollfds, nevents, (qmi_proxy_server_fd > 0) ? -1 : 200);
  1042. } while (ret < 0 && errno == EINTR && qmi_proxy_quit == 0);
  1043. if (ret < 0) {
  1044. dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno));
  1045. goto qmi_proxy_loop_exit;
  1046. }
  1047. for (ne = 0; ne < nevents; ne++) {
  1048. int fd = pollfds[ne].fd;
  1049. short revents = pollfds[ne].revents;
  1050. if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
  1051. dprintf("%s poll fd = %d, revents = %04x\n", __func__, fd, revents);
  1052. if (fd == cdc_wdm_fd) {
  1053. goto qmi_proxy_loop_exit;
  1054. } else if(fd == qmi_proxy_server_fd) {
  1055. } else {
  1056. cleanup_qmi_connection(fd);
  1057. }
  1058. continue;
  1059. }
  1060. if (!(pollfds[ne].revents & POLLIN)) {
  1061. continue;
  1062. }
  1063. if (fd == qmi_proxy_server_fd) {
  1064. accept_qmi_connection(fd);
  1065. }
  1066. else if (fd == cdc_wdm_fd) {
  1067. nreads = read(fd, pQMI, sizeof(qmi_buf));
  1068. if (verbose_debug)
  1069. {
  1070. ssize_t i;
  1071. printf("r %d %zd: ", fd, nreads);
  1072. for (i = 0; i < nreads; i++)
  1073. printf("%02x ", ((uint8_t *)pQMI)[i]);
  1074. printf("\n");
  1075. }
  1076. if (nreads <= 0) {
  1077. dprintf("%s read=%d errno: %d (%s)\n", __func__, (int)nreads, errno, strerror(errno));
  1078. goto qmi_proxy_loop_exit;
  1079. }
  1080. if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
  1081. dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
  1082. continue;
  1083. }
  1084. recv_qmi(pQMI, nreads);
  1085. if (modem_reset_flag)
  1086. goto qmi_proxy_loop_exit;
  1087. }
  1088. else {
  1089. nreads = read(fd, pQMI, sizeof(qmi_buf));
  1090. if (verbose_debug)
  1091. {
  1092. ssize_t i;
  1093. printf("r %d %zd: ", fd, nreads);
  1094. for (i = 0; i < 16; i++)
  1095. printf("%02x ", ((uint8_t *)pQMI)[i]);
  1096. printf("\n");
  1097. }
  1098. if (nreads <= 0) {
  1099. dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
  1100. cleanup_qmi_connection(fd);
  1101. break;
  1102. }
  1103. if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
  1104. dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
  1105. continue;
  1106. }
  1107. send_qmi(pQMI, nreads, fd);
  1108. }
  1109. }
  1110. }
  1111. qmi_proxy_loop_exit:
  1112. while (!qlist_empty(&qmi_proxy_connection)) {
  1113. QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(qlist_head(&qmi_proxy_connection), QMI_PROXY_CONNECTION, qnode);
  1114. cleanup_qmi_connection(qmi_con->ClientFd);
  1115. }
  1116. dprintf("%s exit, thread_id %p\n", __func__, (void *)pthread_self());
  1117. return NULL;
  1118. }
  1119. static int dir_get_child(const char *dirname, char *buff, unsigned bufsize)
  1120. {
  1121. struct dirent *entptr = NULL;
  1122. DIR *dirptr = opendir(dirname);
  1123. if (!dirptr)
  1124. goto error;
  1125. while ((entptr = readdir(dirptr))) {
  1126. if (entptr->d_name[0] == '.')
  1127. continue;
  1128. snprintf(buff, bufsize, "%s", entptr->d_name);
  1129. break;
  1130. }
  1131. closedir(dirptr);
  1132. return 0;
  1133. error:
  1134. buff[0] = '\0';
  1135. if (dirptr) closedir(dirptr);
  1136. return -1;
  1137. }
  1138. static int mhidevice_detect(char *device_name, char *ifname) {
  1139. if (!access("/sys/class/net/pcie_mhi0", F_OK))
  1140. strcpy(ifname, "pcie_mhi0");
  1141. else if (!access("/sys/class/net/rmnet_mhi0", F_OK))
  1142. strcpy(ifname, "rmnet_mhi0");
  1143. else {
  1144. goto error;
  1145. }
  1146. if (!access("/dev/mhi_QMI0", F_OK)) {
  1147. strcpy(device_name, "/dev/mhi_QMI0");
  1148. }
  1149. else {
  1150. goto error;
  1151. }
  1152. return 0;
  1153. error:
  1154. return -1;
  1155. }
  1156. static int qmidevice_detect(char *device_name, char *ifname) {
  1157. struct dirent* ent = NULL;
  1158. DIR *pDir;
  1159. char dir[255] = "/sys/bus/usb/devices";
  1160. pDir = opendir(dir);
  1161. if (pDir) {
  1162. struct {
  1163. char subdir[255 * 3];
  1164. char qmifile[255];
  1165. char ifname[255];
  1166. } *pl;
  1167. char qmidevice[255] = {'\0'};
  1168. pl = (typeof(pl)) malloc(sizeof(*pl));
  1169. memset(pl, 0x00, sizeof(*pl));
  1170. while ((ent = readdir(pDir)) != NULL) {
  1171. char idVendor[4+1] = {0};
  1172. char idProduct[4+1] = {0};
  1173. int fd = 0;
  1174. memset(pl, 0x00, sizeof(*pl));
  1175. snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idVendor", dir, ent->d_name);
  1176. fd = open(pl->subdir, O_RDONLY);
  1177. if (fd > 0) {
  1178. read(fd, idVendor, 4);
  1179. close(fd);
  1180. }
  1181. snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idProduct", dir, ent->d_name);
  1182. fd = open(pl->subdir, O_RDONLY);
  1183. if (fd > 0) {
  1184. read(fd, idProduct, 4);
  1185. close(fd);
  1186. }
  1187. if (strncasecmp(idVendor, "05c6", 4) && strncasecmp(idVendor, "2c7c", 4))
  1188. continue;
  1189. dprintf("Find %s/%s idVendor=%s idProduct=%s\n", dir, ent->d_name, idVendor, idProduct);
  1190. snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.4/usbmisc", dir, ent->d_name);
  1191. if (access(pl->subdir, R_OK)) {
  1192. snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.4/usb", dir, ent->d_name);
  1193. if (access(pl->subdir, R_OK)) {
  1194. dprintf("no GobiQMI/usbmic/usb found in %s/%s:1.4\n", dir, ent->d_name);
  1195. continue;
  1196. }
  1197. }
  1198. dir_get_child(pl->subdir, pl->qmifile, sizeof(pl->qmifile));
  1199. snprintf(qmidevice, sizeof(qmidevice), "/dev/%.*s", 100, pl->qmifile);
  1200. strcpy(device_name, qmidevice);
  1201. snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.4/net", dir, ent->d_name);
  1202. dir_get_child(pl->subdir, pl->ifname, sizeof(pl->ifname));
  1203. strcpy(ifname, pl->ifname);
  1204. }
  1205. closedir(pDir);
  1206. free(pl);
  1207. if (device_name[0] == '\0' || ifname[0] == '\0') {
  1208. goto error;
  1209. }
  1210. return 0;
  1211. }
  1212. error:
  1213. return -1;
  1214. }
  1215. static void usage(void) {
  1216. dprintf(" -d <device_name> A valid qmi device\n"
  1217. " default /dev/cdc-wdm0, but cdc-wdm0 may be invalid\n"
  1218. " -i <netcard_name> netcard name\n"
  1219. " -v Will show all details\n");
  1220. }
  1221. static void sig_action(int sig) {
  1222. if (qmi_proxy_quit == 0) {
  1223. qmi_proxy_quit = 1;
  1224. if (thread_id)
  1225. pthread_kill(thread_id, sig);
  1226. }
  1227. }
  1228. int main(int argc, char *argv[]) {
  1229. int opt;
  1230. char cdc_wdm[32+1] = {'\0'};
  1231. char ifname[32+1] = {'\0'};
  1232. int retry_times = 0;
  1233. char servername[64] = {0};
  1234. optind = 1;
  1235. signal(SIGINT, sig_action);
  1236. while ( -1 != (opt = getopt(argc, argv, "d:i:vh"))) {
  1237. switch (opt) {
  1238. case 'd':
  1239. strcpy(cdc_wdm, optarg);
  1240. break;
  1241. case 'v':
  1242. verbose_debug = 1;
  1243. break;
  1244. case 'i':
  1245. strcpy(ifname, optarg);
  1246. break;
  1247. default:
  1248. usage();
  1249. return 0;
  1250. }
  1251. }
  1252. if (cdc_wdm[0] == '\0' || ifname[0] == '\0') {
  1253. if(qmidevice_detect(cdc_wdm, ifname) && mhidevice_detect(cdc_wdm, ifname)) {
  1254. dprintf("network interface '%s' or qmidev '%s' is not exist\n", ifname, cdc_wdm);
  1255. return -1;
  1256. }
  1257. }
  1258. if (cdc_wdm[0] == '\0' || ifname[0] == '\0') {
  1259. dprintf("network interface '%s' or qmidev '%s' is not exist\n", ifname, cdc_wdm);
  1260. return -1;
  1261. }
  1262. sprintf(servername, "quectel-qmi-proxy%d", cdc_wdm[strlen(cdc_wdm)-1]-'0');
  1263. if (access(cdc_wdm, R_OK | W_OK)) {
  1264. dprintf("Fail to access %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno));
  1265. return -1;
  1266. }
  1267. while (qmi_proxy_quit == 0) {
  1268. if (access(cdc_wdm, R_OK | W_OK)) {
  1269. dprintf("Fail to access %s, errno: %d (%s). continue\n", cdc_wdm, errno, strerror(errno));
  1270. // wait device
  1271. sleep(3);
  1272. continue;
  1273. }
  1274. dprintf("Will use cdc-wdm='%s', ifname='%s'\n", cdc_wdm, ifname);
  1275. cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY);
  1276. if (cdc_wdm_fd == -1) {
  1277. dprintf("Failed to open %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno));
  1278. return -1;
  1279. }
  1280. cfmakenoblock(cdc_wdm_fd);
  1281. /* no qmi_proxy_loop lives, create one */
  1282. pthread_create(&thread_id, NULL, qmi_proxy_loop, NULL);
  1283. /* try to redo init if failed, init function must be successfully */
  1284. while (qmi_proxy_init(cdc_wdm, ifname) != 0) {
  1285. if (retry_times < 5) {
  1286. dprintf("fail to init proxy, try again in 2 seconds.\n");
  1287. sleep(2);
  1288. retry_times++;
  1289. } else {
  1290. dprintf("has failed too much times, restart the modem and have a try...\n");
  1291. break;
  1292. }
  1293. /* break loop if modem is detached */
  1294. if (access(cdc_wdm, F_OK|R_OK|W_OK))
  1295. break;
  1296. }
  1297. retry_times = 0;
  1298. qmi_start_server(servername);
  1299. pthread_join(thread_id, NULL);
  1300. /* close local server at last */
  1301. qmi_close_server(servername);
  1302. close(cdc_wdm_fd);
  1303. /* DO RESTART IN 20s IF MODEM RESET ITSELF */
  1304. if (modem_reset_flag) {
  1305. unsigned int time_to_wait = 20;
  1306. while (time_to_wait) {
  1307. time_to_wait = sleep(time_to_wait);
  1308. }
  1309. modem_reset_flag = 0;
  1310. }
  1311. }
  1312. return 0;
  1313. }