mbim-dev.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * umbim
  3. * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/usb/cdc-wdm.h>
  15. #include <sys/ioctl.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #include <unistd.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdint.h>
  23. #include <libubox/uloop.h>
  24. #include "mbim.h"
  25. #ifdef LIBQMI_MBIM_PROXY
  26. #include <sys/socket.h>
  27. #include <sys/un.h>
  28. #include "data/mbim-service-proxy-control.h"
  29. uint8_t proxy_control[16] = { 0x83, 0x8c, 0xf7, 0xfb, 0x8d, 0x0d, 0x4d, 0x7f, 0x87, 0x1e, 0xd7, 0x1d, 0xbe, 0xfb, 0xb3, 0x9b };
  30. #endif
  31. size_t mbim_bufsize = 0;
  32. uint8_t *mbim_buffer = NULL;
  33. static struct uloop_fd mbim_fd;
  34. static uint32_t expected;
  35. int no_close;
  36. static void mbim_msg_tout_cb(struct uloop_timeout *t)
  37. {
  38. fprintf(stderr, "ERROR: mbim message timeout\n");
  39. mbim_end();
  40. }
  41. static struct uloop_timeout tout = {
  42. .cb = mbim_msg_tout_cb,
  43. };
  44. int
  45. mbim_send(void)
  46. {
  47. struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
  48. unsigned int ret = 0;
  49. if (le32toh(hdr->length) > mbim_bufsize) {
  50. fprintf(stderr, "message too big %d\n", le32toh(hdr->length));
  51. return -1;
  52. }
  53. if (verbose) {
  54. fprintf(stderr, "sending (%d): ", le32toh(hdr->length));
  55. for (ret = 0; ret < le32toh(hdr->length); ret++)
  56. printf("%02x ", ((uint8_t *) mbim_buffer)[ret]);
  57. printf("\n");
  58. printf(" header_type: %04X\n", le32toh(hdr->type));
  59. printf(" header_length: %04X\n", le32toh(hdr->length));
  60. printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
  61. }
  62. ret = write(mbim_fd.fd, mbim_buffer, le32toh(hdr->length));
  63. if (!ret) {
  64. perror("writing data failed: ");
  65. } else {
  66. expected = le32toh(hdr->type) | 0x80000000;
  67. uloop_timeout_set(&tout, 15000);
  68. }
  69. return ret;
  70. }
  71. static void
  72. mbim_recv(struct uloop_fd *u, unsigned int events)
  73. {
  74. ssize_t cnt = read(u->fd, mbim_buffer, mbim_bufsize);
  75. struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
  76. struct command_done_message *msg = (struct command_done_message *) (hdr + 1);
  77. int i;
  78. if (cnt < 0)
  79. return;
  80. if (cnt < (ssize_t) sizeof(struct mbim_message_header)) {
  81. perror("failed to read() data: ");
  82. return;
  83. }
  84. if (verbose) {
  85. printf("reading (%zu): ", cnt);
  86. for (i = 0; i < cnt; i++)
  87. printf("%02x ", mbim_buffer[i]);
  88. printf("\n");
  89. printf(" header_type: %04X\n", le32toh(hdr->type));
  90. printf(" header_length: %04X\n", le32toh(hdr->length));
  91. printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
  92. }
  93. if (le32toh(hdr->type) == expected)
  94. uloop_timeout_cancel(&tout);
  95. switch(le32toh(hdr->type)) {
  96. case MBIM_MESSAGE_TYPE_OPEN_DONE:
  97. if (current_handler->request() < 0)
  98. mbim_send_close_msg();
  99. break;
  100. case MBIM_MESSAGE_TYPE_COMMAND_DONE:
  101. if (verbose) {
  102. printf(" command_id: %04X\n", le32toh(msg->command_id));
  103. printf(" status_code: %04X\n", le32toh(msg->status_code));
  104. }
  105. if (msg->status_code && !msg->buffer_length)
  106. return_code = -le32toh(msg->status_code);
  107. #ifdef LIBQMI_MBIM_PROXY
  108. else if (le32toh(msg->command_id) == MBIM_CMD_PROXY_CONTROL_CONFIGURATION && !memcmp(msg->service_id, proxy_control, 16))
  109. break;
  110. #endif
  111. else
  112. return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
  113. if (return_code < 0)
  114. no_close = 0;
  115. mbim_send_close_msg();
  116. break;
  117. case MBIM_MESSAGE_TYPE_CLOSE_DONE:
  118. mbim_end();
  119. break;
  120. case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
  121. no_close = 0;
  122. mbim_send_close_msg();
  123. return_code = -1;
  124. break;
  125. }
  126. }
  127. void
  128. mbim_open(const char *path)
  129. {
  130. __u16 max;
  131. int rc;
  132. mbim_fd.cb = mbim_recv;
  133. mbim_fd.fd = open(path, O_RDWR);
  134. if (mbim_fd.fd < 1) {
  135. perror("open failed: ");
  136. exit(-1);
  137. }
  138. rc = ioctl(mbim_fd.fd, IOCTL_WDM_MAX_COMMAND, &max);
  139. if (!rc)
  140. mbim_bufsize = max;
  141. else
  142. mbim_bufsize = 512;
  143. mbim_buffer = malloc(mbim_bufsize);
  144. uloop_fd_add(&mbim_fd, ULOOP_READ);
  145. }
  146. #ifdef LIBQMI_MBIM_PROXY
  147. static int
  148. mbim_send_proxy_msg(const char *path)
  149. {
  150. struct mbim_proxy_control_configuration_s *p =
  151. (struct mbim_proxy_control_configuration_s *) mbim_setup_command_msg(proxy_control,
  152. MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_PROXY_CONTROL_CONFIGURATION,
  153. sizeof(struct mbim_proxy_control_configuration_s));
  154. mbim_encode_string(&p->devicepath, (char *)path);
  155. p->timeout = htole32(30); // FIXME: hard coded timeout
  156. return mbim_send_command_msg();
  157. }
  158. void
  159. mbim_proxy_open(const char *path)
  160. {
  161. struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = "\0mbim-proxy" };
  162. mbim_fd.cb = mbim_recv;
  163. mbim_fd.fd = socket(PF_UNIX, SOCK_STREAM, 0);
  164. if (mbim_fd.fd < 1) {
  165. perror("socket failed: ");
  166. exit(-1);
  167. }
  168. if (connect(mbim_fd.fd, (struct sockaddr *)&addr, 13)) {
  169. perror("failed to connect to mbim-proxy: ");
  170. exit(-1);
  171. }
  172. mbim_bufsize = 512; // FIXME
  173. mbim_buffer = malloc(mbim_bufsize);
  174. uloop_fd_add(&mbim_fd, ULOOP_READ);
  175. no_close = 1;
  176. mbim_send_proxy_msg(path);
  177. }
  178. #endif
  179. void
  180. mbim_end(void)
  181. {
  182. if (mbim_buffer) {
  183. free(mbim_buffer);
  184. mbim_bufsize = 0;
  185. mbim_buffer = NULL;
  186. }
  187. uloop_end();
  188. }