/* * usbmux.c * Interprets the usb multiplexing protocol used by the iPhone. * * Copyright (c) 2008 Zack C. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "usbmux.h" extern int debug; usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 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; } usbmux_version_header *version_header() { 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; } /* mux_connect(phone, s_port, d_port) * This is a higher-level USBMuxTCP-type function. * phone: the iPhone to initialize a connection on. * s_port: the source port * d_port: the destination port -- 0xf27e for lockdownd. * Initializes a connection on phone, with source port s_port and destination port d_port * * Returns a mux TCP header for the connection which is used for tracking and data transfer. */ usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) { if (!phone || !s_port || !d_port) return NULL; int bytes = 0; // Initialize connection stuff usbmux_tcp_header *new_connection; new_connection = new_mux_packet(s_port, d_port); usbmux_tcp_header *response; response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); // blargg if (new_connection) { new_connection->tcp_flags = 0x02; new_connection->length = htonl(new_connection->length); new_connection->length16 = htons(new_connection->length16); if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) { bytes = recv_from_phone(phone, (char*)response, sizeof(*response)); if (response->tcp_flags != 0x12) return NULL; else { new_connection->tcp_flags = 0x10; new_connection->scnt = 1; new_connection->ocnt = 1; return new_connection; } } else { return NULL; } } // if we get to this point it's probably bad return NULL; } /* mux_close_connection(phone, connection) * This is a higher-level USBmuxTCP-type function. * phone: the iPhone to close a connection with. * connection: the connection to close. * * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!! */ void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) { if (!phone || !connection) return; connection->tcp_flags = 0x04; connection->scnt = htonl(connection->scnt); connection->ocnt = htonl(connection->ocnt); int bytes = 0; bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800); bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800); free(connection); } /* mux_send(phone, connection, data, datalen) * This is a higher-level USBMuxTCP-like function. * phone: the iPhone to send to. * connection: the connection we're sending data on. * data: a pointer to the data to send. * datalen: how much data we're sending. * * Returns number of bytes sent, minus the header (28), or -1 on error. */ int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { if (!phone || !connection || !data || datalen == 0) return -1; // connection->scnt and connection->ocnt should already be in host notation... // we don't need to change them juuuust yet. int bytes = 0; if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen); char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding // Set the length and pre-emptively htonl/htons it connection->length = htonl(sizeof(*connection) + datalen); connection->length16 = htons(sizeof(*connection) + datalen); // Put scnt and ocnt into big-endian notation connection->scnt = htonl(connection->scnt); connection->ocnt = htonl(connection->ocnt); // Concatenation of stuff in the buffer. memcpy(buffer, connection, sizeof(*connection)); memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen); // We have a buffer full of data, we should now send it to the phone. if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer); bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen); // Now that we've sent it off, we can clean up after our sloppy selves. free(buffer); // Re-calculate scnt and ocnt connection->scnt = ntohl(connection->scnt) + datalen; connection->ocnt = ntohl(connection->ocnt); // Revert lengths connection->length = ntohl(connection->length); connection->length16 = ntohs(connection->length16); // Now return the bytes. if (bytes < sizeof(*connection)+datalen) { return -1; // blah } else { return bytes - 28; // actual length sent. :/ } return bytes; // or something } /* mux_recv(phone, connection, data, datalen) * This is a higher-level USBMuxTCP-like function * phone: the phone to receive data from. * connection: the connection to receive data on. * data: where to put the data we receive. * datalen: how much data to read. * * Returns: how many bytes were read, or -1 if something bad happens. */ int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen); int bytes = 0, my_datalen = 0; if (debug) printf("mux_recv: datalen == %i\n", datalen); bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen); if (debug) printf("mux_recv: bytes == %i\n", bytes); if (bytes < datalen) { if (bytes < 28) { // if they didn't do that annoying thing, something else mighta happened. if (debug) printf("mux_recv: bytes too low anyway!\n"); free(buffer); return -1; } else if (bytes == 28) { // no data... free(buffer); return 0; } else { // bytes > 28 my_datalen = ntohl(buffer[4]) - 28; connection->ocnt += my_datalen; memcpy(data, buffer+28, bytes - 28); free(buffer); if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); return bytes - 28; } } else {// all's good, they didn't do anything bonky. my_datalen = ntohl(buffer[4]) - 28; connection->ocnt += my_datalen; if (bytes == (datalen+28)) memcpy(data, buffer+28, datalen); else if (bytes == datalen) memcpy(data, buffer+28, datalen-28); free(buffer); if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); return bytes - 28; } return bytes; }