umbim: fix invalid mbim message string encoding
[project/umbim.git] / mbim-dev.c
index e5d90f9f270ad1f7f856a80b76b293632bf2e538..2a94d492d76da4a9b14c66e856c707f21b13daec 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * umbim
+ * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/usb/cdc-wdm.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 
 #include "mbim.h"
 
-uint8_t mbim_buffer[MBIM_BUFFER_SIZE];
+
+#ifdef LIBQMI_MBIM_PROXY
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "data/mbim-service-proxy-control.h"
+
+uint8_t proxy_control[16] = { 0x83, 0x8c, 0xf7, 0xfb, 0x8d, 0x0d, 0x4d, 0x7f, 0x87, 0x1e, 0xd7, 0x1d, 0xbe, 0xfb, 0xb3, 0x9b };
+#endif
+
+size_t mbim_bufsize = 0;
+uint8_t *mbim_buffer = NULL;
 static struct uloop_fd mbim_fd;
 static uint32_t expected;
 int no_close;
@@ -19,7 +45,7 @@ int no_close;
 static void mbim_msg_tout_cb(struct uloop_timeout *t)
 {
        fprintf(stderr, "ERROR: mbim message timeout\n");
-       uloop_end();
+       mbim_end();
 }
 
 static struct uloop_timeout tout = {
@@ -30,9 +56,9 @@ int
 mbim_send(void)
 {
        struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
-       int ret = 0;
+       unsigned int ret = 0;
 
-       if (le32toh(hdr->length) > MBIM_BUFFER_SIZE) {
+       if (le32toh(hdr->length) > mbim_bufsize) {
                fprintf(stderr, "message too big %d\n", le32toh(hdr->length));
                return -1;
        }
@@ -60,15 +86,15 @@ mbim_send(void)
 static void
 mbim_recv(struct uloop_fd *u, unsigned int events)
 {
-       ssize_t cnt = read(u->fd, mbim_buffer, MBIM_BUFFER_SIZE);
+       ssize_t cnt = read(u->fd, mbim_buffer, mbim_bufsize);
        struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
-       struct command_message *msg = (struct command_message *) mbim_buffer;
+       struct command_done_message *msg = (struct command_done_message *) (hdr + 1);
        int i;
 
        if (cnt < 0)
                return;
 
-       if (cnt < sizeof(struct mbim_message_header)) {
+       if (cnt < (ssize_t) sizeof(struct mbim_message_header)) {
                perror("failed to read() data: ");
                return;
        }
@@ -91,13 +117,24 @@ mbim_recv(struct uloop_fd *u, unsigned int events)
                        mbim_send_close_msg();
                break;
        case MBIM_MESSAGE_TYPE_COMMAND_DONE:
-               return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
+               if (verbose) {
+                       printf("  command_id: %04X\n", le32toh(msg->command_id));
+                       printf("  status_code: %04X\n", le32toh(msg->status_code));
+               }
+               if (msg->status_code && !msg->buffer_length)
+                       return_code = -le32toh(msg->status_code);
+#ifdef LIBQMI_MBIM_PROXY
+               else if (le32toh(msg->command_id) == MBIM_CMD_PROXY_CONTROL_CONFIGURATION && !memcmp(msg->service_id, proxy_control, 16))
+                       break;
+#endif
+               else
+                       return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
                if (return_code < 0)
                        no_close = 0;
                mbim_send_close_msg();
                break;
        case MBIM_MESSAGE_TYPE_CLOSE_DONE:
-               uloop_end();
+               mbim_end();
                break;
        case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
                no_close = 0;
@@ -110,11 +147,67 @@ mbim_recv(struct uloop_fd *u, unsigned int events)
 void
 mbim_open(const char *path)
 {
+       __u16 max;
+       int rc;
+
        mbim_fd.cb = mbim_recv;
        mbim_fd.fd = open(path, O_RDWR);
        if (mbim_fd.fd < 1) {
                perror("open failed: ");
                exit(-1);
        }
+       rc = ioctl(mbim_fd.fd, IOCTL_WDM_MAX_COMMAND, &max);
+       if (!rc)
+               mbim_bufsize = max;
+       else
+               mbim_bufsize = 512;
+       mbim_buffer = malloc(mbim_bufsize);
+       uloop_fd_add(&mbim_fd, ULOOP_READ);
+}
+
+#ifdef LIBQMI_MBIM_PROXY
+static int
+mbim_send_proxy_msg(const char *path)
+{
+       struct mbim_proxy_control_configuration_s *p =
+               (struct mbim_proxy_control_configuration_s *) mbim_setup_command_msg(proxy_control,
+                       MBIM_MESSAGE_COMMAND_TYPE_SET, MBIM_CMD_PROXY_CONTROL_CONFIGURATION,
+                       sizeof(struct mbim_proxy_control_configuration_s));
+       mbim_encode_string(&p->devicepath, (char *)path);
+       p->timeout = htole32(30); // FIXME: hard coded timeout
+       return mbim_send_command_msg();
+}
+
+void
+mbim_proxy_open(const char *path)
+{
+       struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = "\0mbim-proxy" };
+
+       mbim_fd.cb = mbim_recv;
+       mbim_fd.fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (mbim_fd.fd < 1) {
+               perror("socket failed: ");
+               exit(-1);
+       }
+       if (connect(mbim_fd.fd, (struct sockaddr *)&addr, 13)) {
+               perror("failed to connect to mbim-proxy: ");
+               exit(-1);
+       }
+       mbim_bufsize = 512; // FIXME
+       mbim_buffer = malloc(mbim_bufsize);
        uloop_fd_add(&mbim_fd, ULOOP_READ);
+       no_close = 1;
+       mbim_send_proxy_msg(path);
+}
+#endif
+
+void
+mbim_end(void)
+{
+       if (mbim_buffer) {
+               free(mbim_buffer);
+               mbim_bufsize = 0;
+               mbim_buffer = NULL;
+       }
+       uloop_end();
 }