umbim: fix invalid mbim message string encoding
[project/umbim.git] / mbim-dev.c
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
15 #include <linux/usb/cdc-wdm.h>
16 #include <sys/ioctl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdint.h>
25
26 #include <libubox/uloop.h>
27
28 #include "mbim.h"
29
30
31 #ifdef LIBQMI_MBIM_PROXY
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include "data/mbim-service-proxy-control.h"
35
36 uint8_t proxy_control[16] = { 0x83, 0x8c, 0xf7, 0xfb, 0x8d, 0x0d, 0x4d, 0x7f, 0x87, 0x1e, 0xd7, 0x1d, 0xbe, 0xfb, 0xb3, 0x9b };
37 #endif
38
39 size_t mbim_bufsize = 0;
40 uint8_t *mbim_buffer = NULL;
41 static struct uloop_fd mbim_fd;
42 static uint32_t expected;
43 int no_close;
44
45 static void mbim_msg_tout_cb(struct uloop_timeout *t)
46 {
47 fprintf(stderr, "ERROR: mbim message timeout\n");
48 mbim_end();
49 }
50
51 static struct uloop_timeout tout = {
52 .cb = mbim_msg_tout_cb,
53 };
54
55 int
56 mbim_send(void)
57 {
58 struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
59 unsigned int ret = 0;
60
61 if (le32toh(hdr->length) > mbim_bufsize) {
62 fprintf(stderr, "message too big %d\n", le32toh(hdr->length));
63 return -1;
64 }
65
66 if (verbose) {
67 fprintf(stderr, "sending (%d): ", le32toh(hdr->length));
68 for (ret = 0; ret < le32toh(hdr->length); ret++)
69 printf("%02x ", ((uint8_t *) mbim_buffer)[ret]);
70 printf("\n");
71 printf(" header_type: %04X\n", le32toh(hdr->type));
72 printf(" header_length: %04X\n", le32toh(hdr->length));
73 printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
74 }
75
76 ret = write(mbim_fd.fd, mbim_buffer, le32toh(hdr->length));
77 if (!ret) {
78 perror("writing data failed: ");
79 } else {
80 expected = le32toh(hdr->type) | 0x80000000;
81 uloop_timeout_set(&tout, 15000);
82 }
83 return ret;
84 }
85
86 static void
87 mbim_recv(struct uloop_fd *u, unsigned int events)
88 {
89 ssize_t cnt = read(u->fd, mbim_buffer, mbim_bufsize);
90 struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
91 struct command_done_message *msg = (struct command_done_message *) (hdr + 1);
92 int i;
93
94 if (cnt < 0)
95 return;
96
97 if (cnt < (ssize_t) sizeof(struct mbim_message_header)) {
98 perror("failed to read() data: ");
99 return;
100 }
101 if (verbose) {
102 printf("reading (%zu): ", cnt);
103 for (i = 0; i < cnt; i++)
104 printf("%02x ", mbim_buffer[i]);
105 printf("\n");
106 printf(" header_type: %04X\n", le32toh(hdr->type));
107 printf(" header_length: %04X\n", le32toh(hdr->length));
108 printf(" header_transaction: %04X\n", le32toh(hdr->transaction_id));
109 }
110
111 if (le32toh(hdr->type) == expected)
112 uloop_timeout_cancel(&tout);
113
114 switch(le32toh(hdr->type)) {
115 case MBIM_MESSAGE_TYPE_OPEN_DONE:
116 if (current_handler->request() < 0)
117 mbim_send_close_msg();
118 break;
119 case MBIM_MESSAGE_TYPE_COMMAND_DONE:
120 if (verbose) {
121 printf(" command_id: %04X\n", le32toh(msg->command_id));
122 printf(" status_code: %04X\n", le32toh(msg->status_code));
123 }
124 if (msg->status_code && !msg->buffer_length)
125 return_code = -le32toh(msg->status_code);
126 #ifdef LIBQMI_MBIM_PROXY
127 else if (le32toh(msg->command_id) == MBIM_CMD_PROXY_CONTROL_CONFIGURATION && !memcmp(msg->service_id, proxy_control, 16))
128 break;
129 #endif
130 else
131 return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
132 if (return_code < 0)
133 no_close = 0;
134 mbim_send_close_msg();
135 break;
136 case MBIM_MESSAGE_TYPE_CLOSE_DONE:
137 mbim_end();
138 break;
139 case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
140 no_close = 0;
141 mbim_send_close_msg();
142 return_code = -1;
143 break;
144 }
145 }
146
147 void
148 mbim_open(const char *path)
149 {
150 __u16 max;
151 int rc;
152
153 mbim_fd.cb = mbim_recv;
154 mbim_fd.fd = open(path, O_RDWR);
155 if (mbim_fd.fd < 1) {
156 perror("open failed: ");
157 exit(-1);
158 }
159 rc = ioctl(mbim_fd.fd, IOCTL_WDM_MAX_COMMAND, &max);
160 if (!rc)
161 mbim_bufsize = max;
162 else
163 mbim_bufsize = 512;
164 mbim_buffer = malloc(mbim_bufsize);
165 uloop_fd_add(&mbim_fd, ULOOP_READ);
166 }
167
168 #ifdef LIBQMI_MBIM_PROXY
169 static int
170 mbim_send_proxy_msg(const char *path)
171 {
172 struct mbim_proxy_control_configuration_s *p =
173 (struct mbim_proxy_control_configuration_s *) mbim_setup_command_msg(proxy_control,
174 MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_PROXY_CONTROL_CONFIGURATION,
175 sizeof(struct mbim_proxy_control_configuration_s));
176 mbim_encode_string(&p->devicepath, (char *)path);
177 p->timeout = htole32(30); // FIXME: hard coded timeout
178 return mbim_send_command_msg();
179 }
180
181 void
182 mbim_proxy_open(const char *path)
183 {
184 struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = "\0mbim-proxy" };
185
186 mbim_fd.cb = mbim_recv;
187 mbim_fd.fd = socket(PF_UNIX, SOCK_STREAM, 0);
188 if (mbim_fd.fd < 1) {
189 perror("socket failed: ");
190 exit(-1);
191 }
192 if (connect(mbim_fd.fd, (struct sockaddr *)&addr, 13)) {
193 perror("failed to connect to mbim-proxy: ");
194 exit(-1);
195 }
196 mbim_bufsize = 512; // FIXME
197 mbim_buffer = malloc(mbim_bufsize);
198 uloop_fd_add(&mbim_fd, ULOOP_READ);
199 no_close = 1;
200 mbim_send_proxy_msg(path);
201 }
202 #endif
203
204 void
205 mbim_end(void)
206 {
207 if (mbim_buffer) {
208 free(mbim_buffer);
209 mbim_bufsize = 0;
210 mbim_buffer = NULL;
211 }
212 uloop_end();
213 }