summaryrefslogtreecommitdiffstats
path: root/src/bt_packet_logger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bt_packet_logger.c')
-rw-r--r--src/bt_packet_logger.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/bt_packet_logger.c b/src/bt_packet_logger.c
new file mode 100644
index 0000000..937747c
--- /dev/null
+++ b/src/bt_packet_logger.c
@@ -0,0 +1,231 @@
1/*
2 * bt_packet_logger.c
3 * com.apple.bluetooth.BTPacketLogger service implementation.
4 *
5 * Copyright (c) 2021 Geoffrey Kruse, 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#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25#include <string.h>
26#include <stdlib.h>
27
28#include "bt_packet_logger.h"
29#include "lockdown.h"
30#include "common/debug.h"
31
32struct bt_packet_logger_worker_thread {
33 bt_packet_logger_client_t client;
34 bt_packet_logger_receive_cb_t cbfunc;
35 void *user_data;
36 uint8_t rxbuff[BT_MAX_PACKET_SIZE];
37};
38
39#define SZ_READ_TIMEOUT 100
40#define PAYLOAD_READ_TIMEOUT 500
41
42/**
43 * Convert a service_error_t value to a bt_packet_logger_error_t value.
44 * Used internally to get correct error codes.
45 *
46 * @param err An service_error_t error code
47 *
48 * @return A matching bt_packet_logger_error_t error code,
49 * BT_PACKET_LOGGER_E_UNKNOWN_ERROR otherwise.
50 */
51static bt_packet_logger_error_t bt_packet_logger_error(service_error_t err)
52{
53 switch (err) {
54 case SERVICE_E_SUCCESS:
55 return BT_PACKET_LOGGER_E_SUCCESS;
56 case SERVICE_E_INVALID_ARG:
57 return BT_PACKET_LOGGER_E_INVALID_ARG;
58 case SERVICE_E_MUX_ERROR:
59 return BT_PACKET_LOGGER_E_MUX_ERROR;
60 case SERVICE_E_SSL_ERROR:
61 return BT_PACKET_LOGGER_E_SSL_ERROR;
62 case SERVICE_E_NOT_ENOUGH_DATA:
63 return BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA;
64 case SERVICE_E_TIMEOUT:
65 return BT_PACKET_LOGGER_E_TIMEOUT;
66 default:
67 break;
68 }
69 return BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
70}
71
72bt_packet_logger_error_t bt_packet_logger_client_new(idevice_t device, lockdownd_service_descriptor_t service, bt_packet_logger_client_t * client)
73{
74 if (!device || !service || service->port == 0 || !client || *client) {
75 debug_info("Incorrect parameter passed to bt_packet_logger_client_new.");
76 return BT_PACKET_LOGGER_E_INVALID_ARG;
77 }
78
79 debug_info("Creating bt_packet_logger_client, port = %d.", service->port);
80
81 service_client_t parent = NULL;
82 bt_packet_logger_error_t ret = bt_packet_logger_error(service_client_new(device, service, &parent));
83 if (ret != BT_PACKET_LOGGER_E_SUCCESS) {
84 debug_info("Creating base service client failed. Error: %i", ret);
85 return ret;
86 }
87
88 bt_packet_logger_client_t client_loc = (bt_packet_logger_client_t) malloc(sizeof(struct bt_packet_logger_client_private));
89 client_loc->parent = parent;
90 client_loc->worker = THREAD_T_NULL;
91
92 *client = client_loc;
93
94 debug_info("bt_packet_logger_client successfully created.");
95 return 0;
96}
97
98bt_packet_logger_error_t bt_packet_logger_client_start_service(idevice_t device, bt_packet_logger_client_t * client, const char* label)
99{
100 bt_packet_logger_error_t err = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
101 service_client_factory_start_service(device, BT_PACKETLOGGER_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(bt_packet_logger_client_new), &err);
102 return err;
103}
104
105bt_packet_logger_error_t bt_packet_logger_client_free(bt_packet_logger_client_t client)
106{
107 if (!client)
108 return BT_PACKET_LOGGER_E_INVALID_ARG;
109 bt_packet_logger_stop_capture(client);
110 bt_packet_logger_error_t err = bt_packet_logger_error(service_client_free(client->parent));
111 free(client);
112
113 return err;
114}
115
116bt_packet_logger_error_t bt_packet_logger_receive_with_timeout(bt_packet_logger_client_t client, char* data, uint32_t size, uint32_t *received, unsigned int timeout)
117{
118 bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
119 int bytes = 0;
120
121 if (!client || !data || (size == 0)) {
122 return BT_PACKET_LOGGER_E_INVALID_ARG;
123 }
124
125 res = bt_packet_logger_error(service_receive_with_timeout(client->parent, data, size, (uint32_t*)&bytes, timeout));
126 if (res != BT_PACKET_LOGGER_E_SUCCESS && res != BT_PACKET_LOGGER_E_TIMEOUT && res != BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA) {
127 debug_info("Could not read data, error %d", res);
128 }
129 if (received) {
130 *received = (uint32_t)bytes;
131 }
132
133 return res;
134}
135
136void *bt_packet_logger_worker(void *arg)
137{
138 bt_packet_logger_error_t ret = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
139 struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)arg;
140
141 if (!btwt) {
142 return NULL;
143 }
144
145 debug_info("Running");
146
147 while (btwt->client->parent) {
148 uint32_t bytes = 0;
149 uint16_t len;
150
151 ret = bt_packet_logger_receive_with_timeout(btwt->client, (char*)&len, 2, &bytes, SZ_READ_TIMEOUT);
152
153 if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
154 continue;
155 } else if (ret < 0) {
156 debug_info("Connection to bt packet logger interrupted");
157 break;
158 }
159
160 // sanity check received length
161 if(bytes > 0 && len > sizeof(bt_packet_logger_header_t)) {
162 debug_info("Reading %u bytes\n", len);
163 ret = bt_packet_logger_receive_with_timeout(btwt->client, (char *)btwt->rxbuff, len, &bytes, PAYLOAD_READ_TIMEOUT);
164
165 if(len != bytes) {
166 debug_info("Failed Read Expected %u, Received %u\n", len, bytes);
167 continue;
168 }
169
170 if (ret == BT_PACKET_LOGGER_E_TIMEOUT || ret == BT_PACKET_LOGGER_E_NOT_ENOUGH_DATA || ((bytes == 0) && (ret == BT_PACKET_LOGGER_E_SUCCESS))) {
171 continue;
172 } else if (ret < 0) {
173 debug_info("Connection to bt packet logger interrupted");
174 break;
175 }
176
177 btwt->cbfunc(btwt->rxbuff, len, btwt->user_data);
178 }
179 }
180
181 // null check performed above
182 free(btwt);
183
184 debug_info("Exiting");
185
186 return NULL;
187}
188
189bt_packet_logger_error_t bt_packet_logger_start_capture(bt_packet_logger_client_t client, bt_packet_logger_receive_cb_t callback, void* user_data)
190{
191 if (!client || !callback)
192 return BT_PACKET_LOGGER_E_INVALID_ARG;
193
194 bt_packet_logger_error_t res = BT_PACKET_LOGGER_E_UNKNOWN_ERROR;
195
196 if (client->worker) {
197 debug_info("Another syslog capture thread appears to be running already.");
198 return res;
199 }
200
201 /* start worker thread */
202 struct bt_packet_logger_worker_thread *btwt = (struct bt_packet_logger_worker_thread*)malloc(sizeof(struct bt_packet_logger_worker_thread));
203 if (btwt) {
204 btwt->client = client;
205 btwt->cbfunc = callback;
206 btwt->user_data = user_data;
207
208 if (thread_new(&client->worker, bt_packet_logger_worker, btwt) == 0) {
209 res = BT_PACKET_LOGGER_E_SUCCESS;
210 }
211 }
212
213 return res;
214}
215
216
217bt_packet_logger_error_t bt_packet_logger_stop_capture(bt_packet_logger_client_t client)
218{
219 if (client->worker) {
220 /* notify thread to finish */
221 service_client_t parent = client->parent;
222 client->parent = NULL;
223 /* join thread to make it exit */
224 thread_join(client->worker);
225 thread_free(client->worker);
226 client->worker = THREAD_T_NULL;
227 client->parent = parent;
228 }
229
230 return BT_PACKET_LOGGER_E_SUCCESS;
231}