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.

409 lines
15 KiB

2 years ago
  1. /******************************************************************************
  2. @file qmap_bridge_mode.c
  3. @brief Connectivity bridge manager.
  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 "QMIThread.h"
  14. static size_t ql_fread(const char *filename, void *buf, size_t size) {
  15. FILE *fp = fopen(filename , "r");
  16. size_t n = 0;
  17. memset(buf, 0x00, size);
  18. if (fp) {
  19. n = fread(buf, 1, size, fp);
  20. if (n <= 0 || n == size) {
  21. dbg_time("warnning: fail to fread(%s), fread=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
  22. }
  23. fclose(fp);
  24. }
  25. return n > 0 ? n : 0;
  26. }
  27. static size_t ql_fwrite(const char *filename, const void *buf, size_t size) {
  28. FILE *fp = fopen(filename , "w");
  29. size_t n = 0;
  30. if (fp) {
  31. n = fwrite(buf, 1, size, fp);
  32. if (n != size) {
  33. dbg_time("warnning: fail to fwrite(%s), fwrite=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
  34. }
  35. fclose(fp);
  36. }
  37. return n > 0 ? n : 0;
  38. }
  39. int ql_bridge_mode_detect(PROFILE_T *profile) {
  40. const char *ifname = profile->qmapnet_adapter ? profile->qmapnet_adapter : profile->usbnet_adapter;
  41. const char *driver;
  42. char bridge_mode[128];
  43. char bridge_ipv4[128];
  44. char ipv4[128];
  45. char buf[64];
  46. size_t n;
  47. int in_bridge = 0;
  48. driver = profile->driver_name;
  49. snprintf(bridge_mode, sizeof(bridge_mode), "/sys/class/net/%s/bridge_mode", ifname);
  50. snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/class/net/%s/bridge_ipv4", ifname);
  51. if (access(bridge_ipv4, R_OK)) {
  52. if (errno != ENOENT) {
  53. dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
  54. return 0;
  55. }
  56. snprintf(bridge_mode, sizeof(bridge_mode), "/sys/module/%s/parameters/bridge_mode", driver);
  57. snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/module/%s/parameters/bridge_ipv4", driver);
  58. if (access(bridge_mode, R_OK)) {
  59. if (errno != ENOENT) {
  60. dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
  61. }
  62. return 0;
  63. }
  64. }
  65. n = ql_fread(bridge_mode, buf, sizeof(buf));
  66. if (n > 0) {
  67. in_bridge = (buf[0] != '0');
  68. }
  69. if (!in_bridge)
  70. return 0;
  71. memset(ipv4, 0, sizeof(ipv4));
  72. if (strstr(bridge_ipv4, "/sys/class/net/") || profile->qmap_mode == 0 || profile->qmap_mode == 1) {
  73. snprintf(ipv4, sizeof(ipv4), "0x%x", profile->ipv4.Address);
  74. dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
  75. ql_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
  76. }
  77. else {
  78. snprintf(ipv4, sizeof(ipv4), "0x%x:%d", profile->ipv4.Address, profile->muxid);
  79. dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
  80. ql_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
  81. }
  82. return in_bridge;
  83. }
  84. int ql_enable_qmi_wwan_rawip_mode(PROFILE_T *profile) {
  85. char filename[256];
  86. char buf[4];
  87. size_t n;
  88. FILE *fp;
  89. if (!qmidev_is_qmiwwan(profile->qmichannel))
  90. return 0;
  91. snprintf(filename, sizeof(filename), "/sys/class/net/%s/qmi/rawip", profile->usbnet_adapter);
  92. n = ql_fread(filename, buf, sizeof(buf));
  93. if (n == 0)
  94. return 0;
  95. if (buf[0] == '1' || buf[0] == 'Y')
  96. return 0;
  97. fp = fopen(filename , "w");
  98. if (fp == NULL) {
  99. dbg_time("Fail to fopen(%s, \"w\"), errno: %d (%s)", filename, errno, strerror(errno));
  100. return 1;
  101. }
  102. buf[0] = 'Y';
  103. n = fwrite(buf, 1, 1, fp);
  104. if (n != 1) {
  105. dbg_time("Fail to fwrite(%s), errno: %d (%s)", filename, errno, strerror(errno));
  106. fclose(fp);
  107. return 1;
  108. }
  109. fclose(fp);
  110. return 0;
  111. }
  112. int ql_driver_type_detect(PROFILE_T *profile) {
  113. if (qmidev_is_gobinet(profile->qmichannel)) {
  114. profile->qmi_ops = &gobi_qmidev_ops;
  115. }
  116. else {
  117. profile->qmi_ops = &qmiwwan_qmidev_ops;
  118. }
  119. qmidev_send = profile->qmi_ops->send;
  120. return 0;
  121. }
  122. void ql_set_driver_bridge_mode(PROFILE_T *profile) {
  123. char enable[8];
  124. char filename[256];
  125. if(profile->qmap_mode)
  126. snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->qmapnet_adapter);
  127. else
  128. snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->usbnet_adapter);
  129. snprintf(enable, sizeof(enable), "%d\n", profile->enable_bridge);
  130. ql_fwrite(filename, enable, sizeof(enable));
  131. }
  132. static int ql_qmi_qmap_mode_detect(PROFILE_T *profile) {
  133. char buf[128];
  134. int n;
  135. char qmap_netcard[128];
  136. struct {
  137. char filename[255 * 2];
  138. char linkname[255 * 2];
  139. } *pl;
  140. pl = (typeof(pl)) malloc(sizeof(*pl));
  141. if (profile->qmapnet_adapter) {
  142. free(profile->qmapnet_adapter);;
  143. profile->qmapnet_adapter = NULL;
  144. }
  145. snprintf(pl->linkname, sizeof(pl->linkname), "/sys/class/net/%s/device/driver", profile->usbnet_adapter);
  146. n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
  147. pl->filename[n] = '\0';
  148. while (pl->filename[n] != '/')
  149. n--;
  150. strset(profile->driver_name, &pl->filename[n+1]);
  151. ql_get_driver_rmnet_info(profile, &profile->rmnet_info);
  152. if (profile->rmnet_info.size) {
  153. profile->qmap_mode = profile->rmnet_info.qmap_mode;
  154. if (profile->qmap_mode) {
  155. int offset_id = profile->pdp - 1;
  156. if (profile->qmap_mode == 1)
  157. offset_id = 0;
  158. profile->muxid = profile->rmnet_info.mux_id[offset_id];
  159. profile->qmapnet_adapter = strdup( profile->rmnet_info.ifname[offset_id]);
  160. profile->qmap_size = profile->rmnet_info.rx_urb_size;
  161. profile->qmap_version = profile->rmnet_info.qmap_version;
  162. }
  163. goto _out;
  164. }
  165. snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode", profile->usbnet_adapter);
  166. if (access(pl->filename, R_OK)) {
  167. if (errno != ENOENT) {
  168. dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
  169. goto _out;
  170. }
  171. snprintf(pl->filename, sizeof(pl->filename), "/sys/module/%s/parameters/qmap_mode", profile->driver_name);
  172. if (access(pl->filename, R_OK)) {
  173. if (errno != ENOENT) {
  174. dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
  175. goto _out;
  176. }
  177. snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/device/driver/module/parameters/qmap_mode", profile->usbnet_adapter);
  178. if (access(pl->filename, R_OK)) {
  179. if (errno != ENOENT) {
  180. dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
  181. goto _out;
  182. }
  183. }
  184. }
  185. }
  186. if (!access(pl->filename, R_OK)) {
  187. n = ql_fread(pl->filename, buf, sizeof(buf));
  188. if (n > 0) {
  189. profile->qmap_mode = atoi(buf);
  190. if (profile->qmap_mode > 1) {
  191. profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
  192. sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter, profile->pdp);
  193. profile->qmapnet_adapter = strdup(qmap_netcard);
  194. } if (profile->qmap_mode == 1) {
  195. profile->muxid = 0x81;
  196. profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
  197. }
  198. }
  199. }
  200. else if (qmidev_is_qmiwwan(profile->qmichannel)) {
  201. snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/qmimux%d", profile->pdp - 1);
  202. if (access(pl->filename, R_OK)) {
  203. if (errno != ENOENT) {
  204. dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
  205. }
  206. goto _out;
  207. }
  208. //upstream Kernel Style QMAP qmi_wwan.c
  209. snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
  210. n = ql_fread(pl->filename, buf, sizeof(buf));
  211. if (n >= 5) {
  212. dbg_time("If use QMAP by /sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
  213. dbg_time("File:%s Line:%d Please make sure add next patch to qmi_wwan.c", __func__, __LINE__);
  214. /*
  215. diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
  216. index 74bebbd..db8a777 100644
  217. --- a/drivers/net/usb/qmi_wwan.c
  218. +++ b/drivers/net/usb/qmi_wwan.c
  219. @@ -379,6 +379,24 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
  220. if (!ret) {
  221. info->flags |= QMI_WWAN_FLAG_MUX;
  222. ret = len;
  223. +#if 1 //Add by Quectel
  224. + if (le16_to_cpu(dev->udev->descriptor.idVendor) == 0x2c7c) {
  225. + int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct);
  226. +
  227. + if (idProduct == 0x0121 || idProduct == 0x0125 || idProduct == 0x0435) //MDM9x07
  228. + dev->rx_urb_size = 4*1024;
  229. + else if (idProduct == 0x0306) //MDM9x40
  230. + dev->rx_urb_size = 16*1024;
  231. + else if (idProduct == 0x0512) //SDX20
  232. + dev->rx_urb_size = 32*1024;
  233. + else if (idProduct == 0x0620) //SDX24
  234. + dev->rx_urb_size = 32*1024;
  235. + else if (idProduct == 0x0800) //SDX55
  236. + dev->rx_urb_size = 32*1024;
  237. + else
  238. + dev->rx_urb_size = 32*1024;
  239. + }
  240. +#endif
  241. }
  242. err:
  243. rtnl_unlock();
  244. */
  245. profile->qmap_mode = n/5; //0x11\n0x22\n0x33\n
  246. if (profile->qmap_mode > 1) {
  247. //PDN-X map to qmimux-X
  248. profile->muxid = (buf[5*(profile->pdp - 1) + 2] - '0')*16 + (buf[5*(profile->pdp - 1) + 3] - '0');
  249. sprintf(qmap_netcard, "qmimux%d", profile->pdp - 1);
  250. profile->qmapnet_adapter = strdup(qmap_netcard);
  251. } else if (profile->qmap_mode == 1) {
  252. profile->muxid = (buf[5*0 + 2] - '0')*16 + (buf[5*0 + 3] - '0');
  253. sprintf(qmap_netcard, "qmimux%d", 0);
  254. profile->qmapnet_adapter = strdup(qmap_netcard);
  255. }
  256. }
  257. }
  258. _out:
  259. if (profile->qmap_mode) {
  260. if (profile->qmap_size == 0) {
  261. profile->qmap_size = 16*1024;
  262. snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_size", profile->usbnet_adapter);
  263. if (!access(pl->filename, R_OK)) {
  264. size_t n;
  265. char buf[32];
  266. n = ql_fread(pl->filename, buf, sizeof(buf));
  267. if (n > 0) {
  268. profile->qmap_size = atoi(buf);
  269. }
  270. }
  271. }
  272. if (profile->qmap_version == 0) {
  273. profile->qmap_version = WDA_DL_DATA_AGG_QMAP_ENABLED;
  274. }
  275. dbg_time("qmap_mode = %d, qmap_version = %d, qmap_size = %d, muxid = 0x%02x, qmap_netcard = %s",
  276. profile->qmap_mode, profile->qmap_version, profile->qmap_size, profile->muxid, profile->qmapnet_adapter);
  277. }
  278. ql_set_driver_bridge_mode(profile);
  279. free(pl);
  280. return 0;
  281. }
  282. static int ql_mbim_qmap_mode_detect(PROFILE_T *profile) {
  283. char buf[128];
  284. int n;
  285. char qmap_netcard[128];
  286. struct {
  287. char filename[255 * 2];
  288. char linkname[255 * 2];
  289. } *pl;
  290. pl = (typeof(pl)) malloc(sizeof(*pl));
  291. if (profile->qmapnet_adapter) {
  292. free(profile->qmapnet_adapter);;
  293. profile->qmapnet_adapter = NULL;
  294. }
  295. snprintf(pl->linkname, sizeof(pl->linkname), "/sys/class/net/%s/device/driver", profile->usbnet_adapter);
  296. n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
  297. pl->filename[n] = '\0';
  298. while (pl->filename[n] != '/')
  299. n--;
  300. strset(profile->driver_name, &pl->filename[n+1]);
  301. ql_get_driver_rmnet_info(profile, &profile->rmnet_info);
  302. if (profile->rmnet_info.size) {
  303. profile->qmap_mode = profile->rmnet_info.qmap_mode;
  304. if (profile->qmap_mode) {
  305. int offset_id = profile->pdp - 1;
  306. if (profile->qmap_mode == 1)
  307. offset_id = 0;
  308. profile->muxid = profile->rmnet_info.mux_id[offset_id];
  309. profile->qmapnet_adapter = strdup( profile->rmnet_info.ifname[offset_id]);
  310. profile->qmap_size = profile->rmnet_info.rx_urb_size;
  311. profile->qmap_version = profile->rmnet_info.qmap_version;
  312. }
  313. goto _out;
  314. }
  315. snprintf(pl->filename, sizeof(pl->filename), "/sys/module/%s/parameters/qmap_mode", profile->driver_name);
  316. if (access(pl->filename, R_OK)) {
  317. if (errno != ENOENT) {
  318. dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
  319. goto _out;
  320. }
  321. } else {
  322. n = ql_fread(pl->filename, buf, sizeof(buf));
  323. if (n > 0) {
  324. profile->qmap_mode = atoi(buf);
  325. if (profile->qmap_mode > 1) {
  326. profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
  327. sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter, profile->pdp);
  328. profile->qmapnet_adapter = strdup(qmap_netcard);
  329. }
  330. }
  331. }
  332. _out:
  333. if (profile->qmap_mode) {
  334. dbg_time("mbim_qmap_mode = %d, vlan_id = 0x%02x, qmap_netcard = %s",
  335. profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
  336. }
  337. free(pl);
  338. return 0;
  339. }
  340. int ql_qmap_mode_detect(PROFILE_T *profile) {
  341. if (profile->software_interface == SOFTWARE_MBIM) {
  342. return ql_mbim_qmap_mode_detect(profile);
  343. } else if (profile->software_interface == SOFTWARE_QMI) {
  344. return ql_qmi_qmap_mode_detect(profile);
  345. }
  346. return 0;
  347. }