dynamically allocate buffer
[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 <sys/types.h>
16 #include <sys/stat.h>
17
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdint.h>
23
24 #include <libubox/uloop.h>
25
26 #include "mbim.h"
27
28 size_t mbim_bufsize = 0;
29 uint8_t *mbim_buffer = NULL;
30 static struct uloop_fd mbim_fd;
31 static uint32_t expected;
32 int no_close;
33
34 static void mbim_msg_tout_cb(struct uloop_timeout *t)
35 {
36         fprintf(stderr, "ERROR: mbim message timeout\n");
37         mbim_end();
38 }
39
40 static struct uloop_timeout tout = {
41         .cb = mbim_msg_tout_cb,
42 };
43
44 int
45 mbim_send(void)
46 {
47         struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
48         int ret = 0;
49
50         if (le32toh(hdr->length) > mbim_bufsize) {
51                 fprintf(stderr, "message too big %d\n", le32toh(hdr->length));
52                 return -1;
53         }
54
55         if (verbose) {
56                 fprintf(stderr, "sending (%d): ", le32toh(hdr->length));
57                 for (ret = 0; ret < le32toh(hdr->length); ret++)
58                         printf("%02x ", ((uint8_t *) mbim_buffer)[ret]);
59                 printf("\n");
60                 printf("  header_type: %04X\n", le32toh(hdr->type));
61                 printf("  header_length: %04X\n", le32toh(hdr->length));
62                 printf("  header_transaction: %04X\n", le32toh(hdr->transaction_id));
63         }
64
65         ret = write(mbim_fd.fd, mbim_buffer, le32toh(hdr->length));
66         if (!ret) {
67                 perror("writing data failed: ");
68         } else {
69                 expected = le32toh(hdr->type) | 0x80000000;
70                 uloop_timeout_set(&tout, 15000);
71         }
72         return ret;
73 }
74
75 static void
76 mbim_recv(struct uloop_fd *u, unsigned int events)
77 {
78         ssize_t cnt = read(u->fd, mbim_buffer, mbim_bufsize);
79         struct mbim_message_header *hdr = (struct mbim_message_header *) mbim_buffer;
80         struct command_done_message *msg = (struct command_done_message *) (hdr + 1);
81         int i;
82
83         if (cnt < 0)
84                 return;
85
86         if (cnt < sizeof(struct mbim_message_header)) {
87                 perror("failed to read() data: ");
88                 return;
89         }
90         if (verbose) {
91                 printf("reading (%zu): ", cnt);
92                 for (i = 0; i < cnt; i++)
93                         printf("%02x ", mbim_buffer[i]);
94                 printf("\n");
95                 printf("  header_type: %04X\n", le32toh(hdr->type));
96                 printf("  header_length: %04X\n", le32toh(hdr->length));
97                 printf("  header_transaction: %04X\n", le32toh(hdr->transaction_id));
98         }
99
100         if (le32toh(hdr->type) == expected)
101                 uloop_timeout_cancel(&tout);
102
103         switch(le32toh(hdr->type)) {
104         case MBIM_MESSAGE_TYPE_OPEN_DONE:
105                 if (current_handler->request() < 0)
106                         mbim_send_close_msg();
107                 break;
108         case MBIM_MESSAGE_TYPE_COMMAND_DONE:
109                 if (verbose) {
110                         printf("  command_id: %04X\n", le32toh(msg->command_id));
111                         printf("  status_code: %04X\n", le32toh(msg->status_code));
112                 }
113                 if (msg->status_code && !msg->buffer_length)
114                         return_code = -le32toh(msg->status_code);
115                 else
116                         return_code = current_handler->response(msg->buffer, le32toh(msg->buffer_length));
117                 if (return_code < 0)
118                         no_close = 0;
119                 mbim_send_close_msg();
120                 break;
121         case MBIM_MESSAGE_TYPE_CLOSE_DONE:
122                 mbim_end();
123                 break;
124         case MBIM_MESSAGE_TYPE_FUNCTION_ERROR:
125                 no_close = 0;
126                 mbim_send_close_msg();
127                 return_code = -1;
128                 break;
129         }
130 }
131
132 void
133 mbim_open(const char *path)
134 {
135         mbim_fd.cb = mbim_recv;
136         mbim_fd.fd = open(path, O_RDWR);
137         if (mbim_fd.fd < 1) {
138                 perror("open failed: ");
139                 exit(-1);
140         }
141         mbim_bufsize = MBIM_BUFFER_SIZE;
142         mbim_buffer = malloc(mbim_bufsize);
143         uloop_fd_add(&mbim_fd, ULOOP_READ);
144 }
145
146 void
147 mbim_end(void)
148 {
149         if (mbim_buffer) {
150                 free(mbim_buffer);
151                 mbim_bufsize = 0;
152                 mbim_buffer = NULL;
153         }
154         uloop_end();
155 }