diff options
| author | 2008-07-29 10:13:37 -0700 | |
|---|---|---|
| committer | 2008-07-29 10:13:37 -0700 | |
| commit | 3dc130f3049e250b2d5c0b48af1995fda2fad3d4 (patch) | |
| tree | 9d801459ef68e83a0d4ca038c0589d8e4c8aa2b2 /src/usbmux.c | |
| parent | 6039e5bbfc36aa5210295c38f251ed178ce5adbb (diff) | |
| download | libimobiledevice-3dc130f3049e250b2d5c0b48af1995fda2fad3d4.tar.gz libimobiledevice-3dc130f3049e250b2d5c0b48af1995fda2fad3d4.tar.bz2 | |
Autotooled the project with very basic versioning support.
Diffstat (limited to 'src/usbmux.c')
| -rw-r--r-- | src/usbmux.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/usbmux.c b/src/usbmux.c new file mode 100644 index 0000000..8c5fc34 --- /dev/null +++ b/src/usbmux.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | |||
| 2 | #include <sys/types.h> | ||
| 3 | #include <arpa/inet.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | #include <stdlib.h> | ||
| 6 | #include <string.h> | ||
| 7 | |||
| 8 | #include "usbmux.h" | ||
| 9 | |||
| 10 | extern int debug; | ||
| 11 | |||
| 12 | usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) { | ||
| 13 | usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); | ||
| 14 | conn->type = htonl(6); | ||
| 15 | conn->length = 28; | ||
| 16 | conn->sport = htons(s_port); | ||
| 17 | conn->dport = htons(d_port); | ||
| 18 | conn->scnt = 0; | ||
| 19 | conn->ocnt = 0; | ||
| 20 | conn->offset = 0x50; | ||
| 21 | conn->window = htons(0x0200); | ||
| 22 | conn->nullnull = 0x0000; | ||
| 23 | conn->length16 = 28; | ||
| 24 | return conn; | ||
| 25 | } | ||
| 26 | |||
| 27 | usbmux_version_header *version_header() { | ||
| 28 | usbmux_version_header *version = (usbmux_version_header*)malloc(sizeof(usbmux_version_header)); | ||
| 29 | version->type = 0; | ||
| 30 | version->length = htonl(20); | ||
| 31 | version->major = htonl(1); | ||
| 32 | version->minor = 0; | ||
| 33 | version->allnull = 0; | ||
| 34 | return version; | ||
| 35 | } | ||
| 36 | |||
| 37 | /* mux_connect(phone, s_port, d_port) | ||
| 38 | * This is a higher-level USBMuxTCP-type function. | ||
| 39 | * phone: the iPhone to initialize a connection on. | ||
| 40 | * s_port: the source port | ||
| 41 | * d_port: the destination port -- 0xf27e for lockdownd. | ||
| 42 | * Initializes a connection on phone, with source port s_port and destination port d_port | ||
| 43 | * | ||
| 44 | * Returns a mux TCP header for the connection which is used for tracking and data transfer. | ||
| 45 | */ | ||
| 46 | |||
| 47 | usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) { | ||
| 48 | if (!phone || !s_port || !d_port) return NULL; | ||
| 49 | int bytes = 0; | ||
| 50 | // Initialize connection stuff | ||
| 51 | usbmux_tcp_header *new_connection; | ||
| 52 | new_connection = new_mux_packet(s_port, d_port); | ||
| 53 | usbmux_tcp_header *response; | ||
| 54 | response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); | ||
| 55 | // blargg | ||
| 56 | if (new_connection) { | ||
| 57 | new_connection->tcp_flags = 0x02; | ||
| 58 | new_connection->length = htonl(new_connection->length); | ||
| 59 | new_connection->length16 = htons(new_connection->length16); | ||
| 60 | |||
| 61 | if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) { | ||
| 62 | bytes = recv_from_phone(phone, (char*)response, sizeof(*response)); | ||
| 63 | if (response->tcp_flags != 0x12) return NULL; | ||
| 64 | else { | ||
| 65 | new_connection->tcp_flags = 0x10; | ||
| 66 | new_connection->scnt = 1; | ||
| 67 | new_connection->ocnt = 1; | ||
| 68 | return new_connection; | ||
| 69 | } | ||
| 70 | } else { | ||
| 71 | return NULL; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | // if we get to this point it's probably bad | ||
| 76 | return NULL; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* mux_close_connection(phone, connection) | ||
| 80 | * This is a higher-level USBmuxTCP-type function. | ||
| 81 | * phone: the iPhone to close a connection with. | ||
| 82 | * connection: the connection to close. | ||
| 83 | * | ||
| 84 | * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!! | ||
| 85 | */ | ||
| 86 | void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) { | ||
| 87 | if (!phone || !connection) return; | ||
| 88 | |||
| 89 | connection->tcp_flags = 0x04; | ||
| 90 | connection->scnt = htonl(connection->scnt); | ||
| 91 | connection->ocnt = htonl(connection->ocnt); | ||
| 92 | int bytes = 0; | ||
| 93 | |||
| 94 | bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800); | ||
| 95 | bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800); | ||
| 96 | |||
| 97 | free(connection); | ||
| 98 | } | ||
| 99 | |||
| 100 | /* mux_send(phone, connection, data, datalen) | ||
| 101 | * This is a higher-level USBMuxTCP-like function. | ||
| 102 | * phone: the iPhone to send to. | ||
| 103 | * connection: the connection we're sending data on. | ||
| 104 | * data: a pointer to the data to send. | ||
| 105 | * datalen: how much data we're sending. | ||
| 106 | * | ||
| 107 | * Returns number of bytes sent, minus the header (28), or -1 on error. | ||
| 108 | */ | ||
| 109 | int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { | ||
| 110 | if (!phone || !connection || !data || datalen == 0) return -1; | ||
| 111 | // connection->scnt and connection->ocnt should already be in host notation... | ||
| 112 | // we don't need to change them juuuust yet. | ||
| 113 | int bytes = 0; | ||
| 114 | if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen); | ||
| 115 | char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding | ||
| 116 | // Set the length and pre-emptively htonl/htons it | ||
| 117 | connection->length = htonl(sizeof(*connection) + datalen); | ||
| 118 | connection->length16 = htons(sizeof(*connection) + datalen); | ||
| 119 | |||
| 120 | // Put scnt and ocnt into big-endian notation | ||
| 121 | connection->scnt = htonl(connection->scnt); | ||
| 122 | connection->ocnt = htonl(connection->ocnt); | ||
| 123 | // Concatenation of stuff in the buffer. | ||
| 124 | memcpy(buffer, connection, sizeof(*connection)); | ||
| 125 | memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen); | ||
| 126 | |||
| 127 | // We have a buffer full of data, we should now send it to the phone. | ||
| 128 | if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer); | ||
| 129 | |||
| 130 | |||
| 131 | bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen); | ||
| 132 | |||
| 133 | // Now that we've sent it off, we can clean up after our sloppy selves. | ||
| 134 | free(buffer); | ||
| 135 | |||
| 136 | // Re-calculate scnt and ocnt | ||
| 137 | connection->scnt = ntohl(connection->scnt) + datalen; | ||
| 138 | connection->ocnt = ntohl(connection->ocnt); | ||
| 139 | |||
| 140 | // Revert lengths | ||
| 141 | connection->length = ntohl(connection->length); | ||
| 142 | connection->length16 = ntohs(connection->length16); | ||
| 143 | |||
| 144 | // Now return the bytes. | ||
| 145 | if (bytes < sizeof(*connection)+datalen) { | ||
| 146 | return -1; // blah | ||
| 147 | } else { | ||
| 148 | return bytes - 28; // actual length sent. :/ | ||
| 149 | } | ||
| 150 | |||
| 151 | return bytes; // or something | ||
| 152 | } | ||
| 153 | |||
| 154 | /* mux_recv(phone, connection, data, datalen) | ||
| 155 | * This is a higher-level USBMuxTCP-like function | ||
| 156 | * phone: the phone to receive data from. | ||
| 157 | * connection: the connection to receive data on. | ||
| 158 | * data: where to put the data we receive. | ||
| 159 | * datalen: how much data to read. | ||
| 160 | * | ||
| 161 | * Returns: how many bytes were read, or -1 if something bad happens. | ||
| 162 | */ | ||
| 163 | |||
| 164 | int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { | ||
| 165 | char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen); | ||
| 166 | int bytes = 0, my_datalen = 0; | ||
| 167 | if (debug) printf("mux_recv: datalen == %i\n", datalen); | ||
| 168 | bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen); | ||
| 169 | if (debug) printf("mux_recv: bytes == %i\n", bytes); | ||
| 170 | if (bytes < datalen) { | ||
| 171 | if (bytes < 28) { | ||
| 172 | // if they didn't do that annoying thing, something else mighta happened. | ||
| 173 | if (debug) printf("mux_recv: bytes too low anyway!\n"); | ||
| 174 | free(buffer); | ||
| 175 | return -1; | ||
| 176 | } else if (bytes == 28) { // no data... | ||
| 177 | free(buffer); | ||
| 178 | return 0; | ||
| 179 | } else { // bytes > 28 | ||
| 180 | my_datalen = ntohl(buffer[4]) - 28; | ||
| 181 | connection->ocnt += my_datalen; | ||
| 182 | memcpy(data, buffer+28, bytes - 28); | ||
| 183 | free(buffer); | ||
| 184 | if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); | ||
| 185 | return bytes - 28; | ||
| 186 | } | ||
| 187 | } else {// all's good, they didn't do anything bonky. | ||
| 188 | my_datalen = ntohl(buffer[4]) - 28; | ||
| 189 | connection->ocnt += my_datalen; | ||
| 190 | memcpy(data, buffer+28, datalen); | ||
| 191 | free(buffer); | ||
| 192 | if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); | ||
| 193 | return bytes - 28; | ||
| 194 | } | ||
| 195 | |||
| 196 | return bytes; | ||
| 197 | } | ||
| 198 | |||
