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 } 214
This page was automatically generated by LXR 0.3.1. • OpenWrt