summaryrefslogtreecommitdiffstats
path: root/src/usbmux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usbmux.c')
-rw-r--r--src/usbmux.c381
1 files changed, 0 insertions, 381 deletions
diff --git a/src/usbmux.c b/src/usbmux.c
deleted file mode 100644
index f0499fa..0000000
--- a/src/usbmux.c
+++ /dev/null
@@ -1,381 +0,0 @@
1/*
2 * usbmux.c
3 * Interprets the usb multiplexing protocol used by the iPhone.
4 *
5 * Copyright (c) 2008 Zach C. All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <sys/types.h>
23#include <arpa/inet.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "usbmux.h"
29
30static iphone_umux_client_t *connlist = NULL;
31static int clients = 0;
32
33/** Creates a USBMux packet for the given set of ports.
34 *
35 * @param s_port The source port for the connection.
36 * @param d_port The destination port for the connection.
37 *
38 * @return A USBMux packet
39 */
40usbmux_tcp_header *new_mux_packet(uint16_t s_port, uint16_t d_port)
41{
42 usbmux_tcp_header *conn = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
43 conn->type = htonl(6);
44 conn->length = 28;
45 conn->sport = htons(s_port);
46 conn->dport = htons(d_port);
47 conn->scnt = 0;
48 conn->ocnt = 0;
49 conn->offset = 0x50;
50 conn->window = htons(0x0200);
51 conn->nullnull = 0x0000;
52 conn->length16 = 28;
53 return conn;
54}
55
56/** Creates a USBMux header containing version information
57 *
58 * @return A USBMux header
59 */
60usbmux_version_header *version_header()
61{
62 usbmux_version_header *version = (usbmux_version_header *) malloc(sizeof(usbmux_version_header));
63 version->type = 0;
64 version->length = htonl(20);
65 version->major = htonl(1);
66 version->minor = 0;
67 version->allnull = 0;
68 return version;
69}
70
71
72// Maintenance functions.
73
74/** Removes a connection from the list of connections made.
75 * The list of connections is necessary for buffering.
76 *
77 * @param connection The connection to delete from the tracking list.
78 */
79void delete_connection(iphone_umux_client_t connection)
80{
81 iphone_umux_client_t *newlist = (iphone_umux_client_t *) malloc(sizeof(iphone_umux_client_t) * (clients - 1));
82 int i = 0, j = 0;
83 for (i = 0; i < clients; i++) {
84 if (connlist[i] == connection)
85 continue;
86 else {
87 newlist[j] = connlist[i];
88 j++;
89 }
90 }
91 free(connlist);
92 connlist = newlist;
93 clients--;
94 if (connection->recv_buffer)
95 free(connection->recv_buffer);
96 if (connection->header)
97 free(connection->header);
98 connection->r_len = 0;
99 free(connection);
100}
101
102/** Adds a connection to the list of connections made.
103 * The connection list is necessary for buffering.
104 *
105 * @param connection The connection to add to the global list of connections.
106 */
107
108void add_connection(iphone_umux_client_t connection)
109{
110 iphone_umux_client_t *newlist =
111 (iphone_umux_client_t *) realloc(connlist, sizeof(iphone_umux_client_t) * (clients + 1));
112 newlist[clients] = connection;
113 connlist = newlist;
114 clients++;
115}
116
117/** Initializes a connection on phone, with source port s_port and destination port d_port
118 *
119 * @param device The iPhone to initialize a connection on.
120 * @param src_port The source port
121 * @param dst_port The destination port -- 0xf27e for lockdownd.
122 * @param client A mux TCP header for the connection which is used for tracking and data transfer.
123 * @return IPHONE_E_SUCCESS on success, an error code otherwise.
124 */
125iphone_error_t iphone_mux_new_client(iphone_device_t device, uint16_t src_port, uint16_t dst_port,
126 iphone_umux_client_t * client)
127{
128 if (!device || !src_port || !dst_port)
129 return IPHONE_E_INVALID_ARG;
130
131 int bytes = 0;
132 // Initialize connection stuff
133 iphone_umux_client_t new_connection = (iphone_umux_client_t) malloc(sizeof(struct iphone_umux_client_int));
134 new_connection->header = new_mux_packet(src_port, dst_port);
135
136 // blargg
137 if (new_connection && new_connection->header) {
138 new_connection->header->tcp_flags = 0x02;
139 new_connection->header->length = htonl(new_connection->header->length);
140 new_connection->header->length16 = htons(new_connection->header->length16);
141
142 if (send_to_phone(device, (char *) new_connection->header, sizeof(usbmux_tcp_header)) >= 0) {
143 usbmux_tcp_header *response;
144 response = (usbmux_tcp_header *) malloc(sizeof(usbmux_tcp_header));
145 bytes = recv_from_phone(device, (char *) response, sizeof(*response));
146 if (response->tcp_flags != 0x12) {
147 free(response);
148 return IPHONE_E_UNKNOWN_ERROR;
149 } else {
150 free(response);
151
152 log_debug_msg("mux_connect: connection success\n");
153 new_connection->header->tcp_flags = 0x10;
154 new_connection->header->scnt = 1;
155 new_connection->header->ocnt = 1;
156 new_connection->phone = device;
157 new_connection->recv_buffer = NULL;
158 new_connection->r_len = 0;
159 add_connection(new_connection);
160 *client = new_connection;
161 return IPHONE_E_SUCCESS;
162 }
163 } else {
164 return IPHONE_E_NOT_ENOUGH_DATA;
165 }
166 }
167 // if we get to this point it's probably bad
168 return IPHONE_E_UNKNOWN_ERROR;
169}
170
171/** Cleans up the given USBMux connection.
172 * @note Once a connection is closed it may not be used again.
173 *
174 * @param connection The connection to close.
175 *
176 * @return IPHONE_E_SUCCESS on success.
177 */
178iphone_error_t iphone_mux_free_client(iphone_umux_client_t client)
179{
180 if (!client || !client->phone)
181 return;
182
183 client->header->tcp_flags = 0x04;
184 client->header->scnt = htonl(client->header->scnt);
185 client->header->ocnt = htonl(client->header->ocnt);
186 int bytes = 0;
187
188 bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800);
189 if (bytes < 0)
190 log_debug_msg("iphone_muxèfree_client(): when writing, libusb gave me the error: %s\n", usb_strerror());
191
192 bytes = usb_bulk_read(client->phone->device, BULKIN, (char *) client->header, sizeof(usbmux_tcp_header), 800);
193 if (bytes < 0)
194 log_debug_msg("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror());
195
196 delete_connection(client);
197
198 return IPHONE_E_SUCCESS;
199}
200
201
202/** Sends the given data over the selected connection.
203 *
204 * @param phone The iPhone to send to.
205 * @param client The client we're sending data on.
206 * @param data A pointer to the data to send.
207 * @param datalen How much data we're sending.
208 * @param sent_bytes The number of bytes sent, minus the header (28)
209 *
210 * @return IPHONE_E_SUCCESS on success.
211 */
212
213iphone_error_t iphone_mux_send(iphone_umux_client_t client, const char *data, uint32_t datalen, uint32_t * sent_bytes)
214{
215 if (!client->phone || !client || !data || datalen == 0 || !sent_bytes)
216 return IPHONE_E_INVALID_ARG;
217 // client->scnt and client->ocnt should already be in host notation...
218 // we don't need to change them juuuust yet.
219 *sent_bytes = 0;
220 log_debug_msg("mux_send(): client wants to send %i bytes\n", datalen);
221 char *buffer = (char *) malloc(sizeof(usbmux_tcp_header) + datalen + 2); // allow 2 bytes of safety padding
222 // Set the length and pre-emptively htonl/htons it
223 client->header->length = htonl(sizeof(usbmux_tcp_header) + datalen);
224 client->header->length16 = htons(sizeof(usbmux_tcp_header) + datalen);
225
226 // Put scnt and ocnt into big-endian notation
227 client->header->scnt = htonl(client->header->scnt);
228 client->header->ocnt = htonl(client->header->ocnt);
229 // Concatenation of stuff in the buffer.
230 memcpy(buffer, client->header, sizeof(usbmux_tcp_header));
231 memcpy(buffer + sizeof(usbmux_tcp_header), data, datalen);
232
233 // We have a buffer full of data, we should now send it to the phone.
234 log_debug_msg("actually sending %zi bytes of data at %p\n", sizeof(usbmux_tcp_header) + datalen, buffer);
235
236
237 *sent_bytes = send_to_phone(client->phone, buffer, sizeof(usbmux_tcp_header) + datalen);
238 log_debug_msg("mux_send: sent %i bytes!\n", *sent_bytes);
239 // Now that we've sent it off, we can clean up after our sloppy selves.
240 dump_debug_buffer("packet", buffer, *sent_bytes);
241 if (buffer)
242 free(buffer);
243 // Re-calculate scnt and ocnt
244 client->header->scnt = ntohl(client->header->scnt) + datalen;
245 client->header->ocnt = ntohl(client->header->ocnt);
246
247 // Revert lengths
248 client->header->length = ntohl(client->header->length);
249 client->header->length16 = ntohs(client->header->length16);
250
251 // Now return the bytes.
252 if (*sent_bytes < sizeof(usbmux_tcp_header) + datalen) {
253 *sent_bytes = 0;
254 return IPHONE_E_NOT_ENOUGH_DATA;
255 } else {
256 *sent_bytes = *sent_bytes - 28; // actual length sent. :/
257 }
258
259 return IPHONE_E_SUCCESS;
260}
261
262/** This is a higher-level USBMuxTCP-like function
263 *
264 * @param connection The connection to receive data on.
265 * @param data Where to put the data we receive.
266 * @param datalen How much data to read.
267 *
268 * @return How many bytes were read, or -1 if something bad happens.
269 */
270iphone_error_t iphone_mux_recv(iphone_umux_client_t client, char *data, uint32_t datalen, uint32_t * recv_bytes)
271{
272
273 if (!client || !data || datalen == 0 || !recv_bytes)
274 return IPHONE_E_INVALID_ARG;
275 /*
276 * Order of operation:
277 * 1.) Check if the client has a pre-received buffer.
278 * 2.) If so, fill data with the buffer, as much as needed.
279 * a.) Return quickly if the buffer has enough
280 * b.) If the buffer is only part of the datalen, get the rest of datalen (and if we can't, just return)
281 * 3.) If not, receive directly from the phone.
282 * a.) Check incoming packet's ports. If proper, follow proper buffering and receiving operation.
283 * 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.
284 */
285 log_debug_msg("mux_recv: datalen == %i\n", datalen);
286 int bytes = 0, i = 0, complex = 0, offset = 0;
287 *recv_bytes = 0;
288 char *buffer = NULL;
289 usbmux_tcp_header *header = NULL;
290
291 if (client->recv_buffer) {
292 if (client->r_len >= datalen) {
293 memcpy(data, client->recv_buffer, datalen);
294 if (client->r_len == datalen) {
295 // reset everything
296 free(client->recv_buffer);
297 client->r_len = 0;
298 client->recv_buffer = NULL;
299 } else {
300 buffer = (char *) malloc(sizeof(char) * (client->r_len - datalen));
301 memcpy(buffer, client->recv_buffer + datalen, (client->r_len - datalen));
302 client->r_len -= datalen;
303 free(client->recv_buffer);
304 client->recv_buffer = buffer;
305 }
306
307 // Since we were able to fill the data straight from our buffer, we can just return datalen. See 2a above.
308 return datalen;
309 } else {
310 memcpy(data, client->recv_buffer, client->r_len);
311 free(client->recv_buffer); // don't need to deal with anymore, but...
312 offset = client->r_len; // see #2b, above
313 client->r_len = 0;
314 }
315 } // End of what to do if we have a pre-buffer. See #1 and #2 above.
316
317 buffer = (char *) malloc(sizeof(char) * 131072); // make sure we get enough ;)
318
319 // See #3.
320 bytes = recv_from_phone(client->phone, buffer, 131072);
321 if (bytes < 28) {
322 free(buffer);
323 log_debug_msg("mux_recv: Did not even get the header.\n");
324 return IPHONE_E_NOT_ENOUGH_DATA;
325 }
326
327 header = (usbmux_tcp_header *) buffer;
328 if (header->sport != client->header->dport || header->dport != client->header->sport) {
329 // Ooooops -- we got someone else's packet.
330 // We gotta stick it in their buffer. (Take that any old way you want ;) )
331 for (i = 0; i < clients; i++) {
332 if (connlist[i]->header->sport == header->dport && connlist[i]->header->dport == header->sport) {
333 // we have a winner.
334 char *nfb = (char *) malloc(sizeof(char) * (connlist[i]->r_len + (bytes - 28)));
335 if (connlist[i]->recv_buffer && connlist[i]->r_len) {
336 memcpy(nfb, connlist[i]->recv_buffer, connlist[i]->r_len);
337 free(connlist[i]->recv_buffer);
338 }
339 connlist[i]->r_len += bytes - 28;
340 //connlist[i]->recv_buffer = (char*)realloc(connlist[i]->recv_buffer, sizeof(char) * client->r_len); // grow their buffer
341 connlist[i]->recv_buffer = nfb;
342 nfb = NULL; // A cookie for you if you can guess what "nfb" means.
343 complex = connlist[i]->r_len - (bytes - 28);
344 memcpy(connlist[i]->recv_buffer + complex, buffer + 28, bytes - 28); // paste into their buffer
345 connlist[i]->header->ocnt += bytes - 28;
346 }
347 }
348 // If it wasn't ours, it's been handled by this point... or forgotten.
349 // Free our buffer and continue.
350 free(buffer);
351 buffer = NULL;
352 return iphone_mux_recv(client, data, datalen, recv_bytes); // recurse back in to try again
353 }
354 // The packet was absolutely meant for us if it hits this point.
355 // The pre-buffer has been taken care of, so, again, if we're at this point we have to read from the phone.
356
357 if ((bytes - 28) > datalen) {
358 // Copy what we need into the data, buffer the rest because we can.
359 memcpy(data + offset, buffer + 28, datalen); // data+offset: see #2b, above
360 complex = client->r_len + (bytes - 28) - datalen;
361 client->recv_buffer = (char *) realloc(client->recv_buffer, (sizeof(char) * complex));
362 client->r_len = complex;
363 complex = client->r_len - (bytes - 28) - datalen;
364 memcpy(client->recv_buffer + complex, buffer + 28 + datalen, (bytes - 28) - datalen);
365 free(buffer);
366 client->header->ocnt += bytes - 28;
367 *recv_bytes = datalen;
368 return IPHONE_E_SUCCESS;
369 } else {
370 // Fill the data with what we have, and just return.
371 memcpy(data + offset, buffer + 28, bytes - 28); // data+offset: see #2b, above
372 client->header->ocnt += bytes - 28;
373 free(buffer);
374 *recv_bytes = bytes - 28;
375 return IPHONE_E_SUCCESS;
376 }
377
378 // If we get to this point, 'tis probably bad.
379 log_debug_msg("mux_recv: Heisenbug: bytes and datalen not matching up\n");
380 return IPHONE_E_UNKNOWN_ERROR;
381}