diff options
Diffstat (limited to 'src/usbmux.c')
-rw-r--r-- | src/usbmux.c | 410 |
1 files changed, 0 insertions, 410 deletions
diff --git a/src/usbmux.c b/src/usbmux.c deleted file mode 100644 index 7d74b4b..0000000 --- a/src/usbmux.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * usbmux.c - * Interprets the usb multiplexing protocol used by the iPhone. - * - * Copyright (c) 2008 Zach C. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <sys/types.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "usbmux.h" -#include "utils.h" - -static iphone_umux_client_t *connlist = NULL; -static int clients = 0; - -/** Creates a USBMux packet for the given set of ports. - * - * @param s_port The source port for the connection. - * @param d_port The destination port for the connection. - * - * @return A USBMux packet - */ -usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port) -{ - usbmux_tcp_header *conn = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); - conn->type = htonl(6); - conn->length = 28; - conn->sport = htons(s_port); - conn->dport = htons(d_port); - conn->scnt = 0; - conn->ocnt = 0; - conn->offset = 0x50; - conn->window = htons(0x0200); - conn->nullnull = 0x0000; - conn->length16 = 28; - return conn; -} - -/** Creates a USBMux header containing version information - * - * @return A USBMux header - */ -usbmux_version_header *version_header(void) -{ - usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_version_header)); - version->type = 0; - version->length = htonl(20); - version->major = htonl(1); - version->minor = 0; - version->allnull = 0; - return version; -} - - -// Maintenance functions. - -/** Removes a connection from the list of connections made. - * The list of connections is necessary for buffering. - * - * @param connection The connection to delete from the tracking list. - */ -static void delete_connection(iphone_umux_client_t connection) -{ - iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1)); - int i = 0, j = 0; - for (i = 0; i < clients; i++) { - if (connlist[i] == connection) - continue; - else { - newlist[j] = connlist[i]; - j++; - } - } - free(connlist); - connlist = newlist; - clients--; - if (connection->recv_buffer) - free(connection->recv_buffer); - if (connection->header) - free(connection->header); - connection->r_len = 0; - free(connection); -} - -/** Adds a connection to the list of connections made. - * The connection list is necessary for buffering. - * - * @param connection The connection to add to the global list of connections. - */ - -static void add_connection(iphone_umux_client_t connection) -{ - iphone_umux_client_t *newlist = - (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1)); - newlist[clients] = connection; - connlist = newlist; - clients++; -} - -/** Initializes a connection on phone, with source port s_port and destination port d_port - * - * @param device The iPhone to initialize a connection on. - * @param src_port The source port - * @param dst_port The destination port -- 0xf27e for lockdownd. - * @param client A mux TCP header for the connection which is used for tracking and data transfer. - * @return IPHONE_E_SUCCESS on success, an error code otherwise. - */ -iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port, - iphone_umux_client_t * client) -{ - if (!device || !src_port || !dst_port) - return IPHONE_E_INVALID_ARG; - - int bytes = 0; - // Initialize connection stuff - iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int)); - new_connection->header = new_mux_packet(src_port, dst_port); - - // blargg - if (new_connection && new_connection->header) { - new_connection->header->tcp_flags = 0x02; - new_connection->header->length = htonl(new_connection->header->length); - new_connection->header->length16 = htons(new_connection->header->length16); - - if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) { - usbmux_tcp_header *response; - response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header)); - bytes = recv_from_phone(device, (char *) response, sizeof(*response), 3500); - if (response->tcp_flags != 0x12) { - free(response); - return IPHONE_E_UNKNOWN_ERROR; - } else { - free(response); - - log_debug_msg("mux_connect: connection success\n"); - new_connection->header->tcp_flags = 0x10; - new_connection->header->scnt = 1; - new_connection->header->ocnt = 1; - new_connection->phone = device; - new_connection->recv_buffer = NULL; - new_connection->r_len = 0; - add_connection(new_connection); - *client = new_connection; - return IPHONE_E_SUCCESS; - } - } else { - return IPHONE_E_NOT_ENOUGH_DATA; - } - } - // if we get to this point it's probably bad - return IPHONE_E_UNKNOWN_ERROR; -} - -/** Cleans up the given USBMux connection. - * @note Once a connection is closed it may not be used again. - * - * @param connection The connection to close. - * - * @return IPHONE_E_SUCCESS on success. - */ -iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) -{ - if (!client || !client->phone) - return IPHONE_E_INVALID_ARG; - - client->header->tcp_flags = 0x04; - client->header->length = htonl(0x1C); - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); - client->header->window = 0; - client->header->length16 = htons(0x1C); - int bytes = 0; - - bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("iphone_muxèfree_client(): when writing, libusb gave me the error: %s\n", usb_strerror()); - - bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800); - if (bytes < 0) - log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror()); - - delete_connection(client); - - return IPHONE_E_SUCCESS; -} - - -/** Sends the given data over the selected connection. - * - * @param phone The iPhone to send to. - * @param client The client we're sending data on. - * @param data A pointer to the data to send. - * @param datalen How much data we're sending. - * @param sent_bytes The number of bytes sent, minus the header (28) - * - * @return IPHONE_E_SUCCESS on success. - */ - -iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes) -{ - if (!client->phone || !client || !data || datalen == 0 || !sent_bytes) - return IPHONE_E_INVALID_ARG; - // client->scnt and client->ocnt should already be in host notation... - // we don't need to change them juuuust yet. - *sent_bytes = 0; - log_debug_msg("mux_send(): client wants to send %i bytes\n", datalen); - char *buffer = (char *) malloc(sizeof(usbmux_tcp_header) + datalen + 2); // allow 2 bytes of safety padding - // Set the length and pre-emptively htonl/htons it - client->header->length = htonl(sizeof(usbmux_tcp_header) + datalen); - client->header->length16 = htons(sizeof(usbmux_tcp_header) + datalen); - - // Put scnt and ocnt into big-endian notation - client->header->scnt = htonl(client->header->scnt); - client->header->ocnt = htonl(client->header->ocnt); - // Concatenation of stuff in the buffer. - memcpy(buffer, client->header, sizeof(usbmux_tcp_header)); - memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen); - - // We have a buffer full of data, we should now send it to the phone. - log_debug_msg("actually sending %zi bytes of data at %p\n", sizeof(usbmux_tcp_header) + datalen, buffer); - - - *sent_bytes = send_to_phone(client->phone, buffer, sizeof(usbmux_tcp_header) + datalen); - log_debug_msg("mux_send: sent %i bytes!\n", *sent_bytes); - // Now that we've sent it off, we can clean up after our sloppy selves. - dump_debug_buffer("packet", buffer, *sent_bytes); - if (buffer) - free(buffer); - // Re-calculate scnt and ocnt - client->header->scnt = ntohl(client->header->scnt) + datalen; - client->header->ocnt = ntohl(client->header->ocnt); - - // Revert lengths - client->header->length = ntohl(client->header->length); - client->header->length16 = ntohs(client->header->length16); - - // Now return the bytes. - if (*sent_bytes < sizeof(usbmux_tcp_header) + datalen) { - *sent_bytes = 0; - return IPHONE_E_NOT_ENOUGH_DATA; - } else { - *sent_bytes = *sent_bytes - 28; // actual length sent. :/ - } - - return IPHONE_E_SUCCESS; -} - -/** This is a higher-level USBMuxTCP-like function - * - * @param connection The connection to receive data on. - * @param data Where to put the data we receive. - * @param datalen How much data to read. - * @param recv_bytes Pointer to a uint32_t that will be set - * to the number of bytes received. - * @param timeout How many milliseconds to wait for data. - * - * @return IPHONE_E_SUCCESS on success, or and error value. - */ -iphone_error_t iphone_mux_recv_timeout(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes, int timeout) -{ - - if (!client || !data || datalen == 0 || !recv_bytes) - return IPHONE_E_INVALID_ARG; - /* - * Order of operation: - * 1.) Check if the client has a pre-received buffer. - * 2.) If so, fill data with the buffer, as much as needed. - * a.) Return quickly if the buffer has enough - * b.) If the buffer is only part of the datalen, get the rest of datalen (and if we can't, just return) - * 3.) If not, receive directly from the phone. - * a.) Check incoming packet's ports. If proper, follow proper buffering and receiving operation. - * b.) If not, find the client the ports belong to and fill that client's buffer, then return mux_recv with the same args to try again. - */ - log_debug_msg("mux_recv: datalen == %i\n", datalen); - int bytes = 0, i = 0, complex = 0, offset = 0; - *recv_bytes = 0; - char *buffer = NULL; - usbmux_tcp_header *header = NULL; - - if (client->recv_buffer) { - if (client->r_len >= datalen) { - memcpy(data, client->recv_buffer, datalen); - if (client->r_len == datalen) { - // reset everything - free(client->recv_buffer); - client->r_len = 0; - client->recv_buffer = NULL; - } else { - buffer = (char *) malloc(sizeof(char) * (client->r_len - datalen)); - memcpy(buffer, client->recv_buffer + datalen, (client->r_len - datalen)); - client->r_len -= datalen; - free(client->recv_buffer); - client->recv_buffer = buffer; - } - - // Since we were able to fill the data straight from our buffer, we can just return datalen. See 2a above. - *recv_bytes = datalen; - return IPHONE_E_SUCCESS; - } else { - memcpy(data, client->recv_buffer, client->r_len); - free(client->recv_buffer); // don't need to deal with anymore, but... - client->recv_buffer = NULL; - offset = client->r_len; // see #2b, above - client->r_len = 0; - } - } // End of what to do if we have a pre-buffer. See #1 and #2 above. - - buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;) - - // See #3. - bytes = recv_from_phone(client->phone, buffer, 131072, timeout); - if (bytes < 28) { - free(buffer); - log_debug_msg("mux_recv: Did not even get the header.\n"); - return IPHONE_E_NOT_ENOUGH_DATA; - } - - header = (usbmux_tcp_header *) buffer; - if (header->sport != client->header->dport || header->dport != client->header->sport) { - // Ooooops -- we got someone else's packet. - // We gotta stick it in their buffer. (Take that any old way you want ;) ) - for (i = 0; i < clients; i++) { - if (connlist[i]->header->sport == header->dport && connlist[i]->header->dport == header->sport) { - // we have a winner. - char *nfb = (char *) malloc(sizeof(char) * (connlist[i]->r_len + (bytes - 28))); - if (connlist[i]->recv_buffer && connlist[i]->r_len) { - memcpy(nfb, connlist[i]->recv_buffer, connlist[i]->r_len); - free(connlist[i]->recv_buffer); - } - connlist[i]->r_len += bytes - 28; - //connlist[i]->recv_buffer = (char*)realloc(connlist[i]->recv_buffer, sizeof(char) * client->r_len); // grow their buffer - connlist[i]->recv_buffer = nfb; - nfb = NULL; // A cookie for you if you can guess what "nfb" means. - complex = connlist[i]->r_len - (bytes - 28); - memcpy(connlist[i]->recv_buffer + complex, buffer + 28, bytes - 28); // paste into their buffer - connlist[i]->header->ocnt += bytes - 28; - } - } - // If it wasn't ours, it's been handled by this point... or forgotten. - // Free our buffer and continue. - free(buffer); - buffer = NULL; - return iphone_mux_recv(client, data, datalen, recv_bytes); // recurse back in to try again - } - // The packet was absolutely meant for us if it hits this point. - // The pre-buffer has been taken care of, so, again, if we're at this point we have to read from the phone. - - if ((bytes - 28) > datalen) { - // Copy what we need into the data, buffer the rest because we can. - memcpy(data + offset, buffer + 28, datalen); // data+offset: see #2b, above - complex = client->r_len + ((bytes - 28) - datalen); - client->recv_buffer = (char *) realloc(client->recv_buffer, (sizeof(char) * complex)); - client->r_len = complex; - complex = client->r_len - ((bytes - 28) - datalen); - memcpy(client->recv_buffer + complex, buffer + 28 + datalen, (bytes - 28) - datalen); - free(buffer); - client->header->ocnt += bytes - 28; - *recv_bytes = datalen; - return IPHONE_E_SUCCESS; - } else { - // Fill the data with what we have, and just return. - memcpy(data + offset, buffer + 28, bytes - 28); // data+offset: see #2b, above - client->header->ocnt += bytes - 28; - free(buffer); - *recv_bytes = bytes - 28; - return IPHONE_E_SUCCESS; - } - - // If we get to this point, 'tis probably bad. - log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n"); - return IPHONE_E_UNKNOWN_ERROR; -} - -/** - * This function is just like 'iphone_mux_recv_timeout' but you do not need - * to specify a timeout. It simply calls iphone_mux_recv_timeout with a - * timeout value of 3500 milliseconds. - * - * @param connection The connection to receive data on. - * @param data Where to put the data we receive. - * @param datalen How much data to read. - * @param recv_bytes Pointer to a uint32_t that will be set - * to the number of bytes received. - * - * @return The return value of iphone_mux_recv_timeout. - * - * @see iphone_mux_recv_timeout - */ -iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes) -{ - return iphone_mux_recv_timeout(client, data, datalen, recv_bytes, 3500); -} |