1 /******************************************************************************
2 *
3 * Copyright 2014 Google, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "bt_l2cap_client"
20
21 #include "stack/include/l2cap_client.h"
22
23 #include <base/logging.h>
24 #include <string.h>
25
26 #include "osi/include/allocator.h"
27 #include "osi/include/buffer.h"
28 #include "osi/include/list.h"
29 #include "osi/include/log.h"
30 #include "osi/include/osi.h"
31 #include "stack/include/l2c_api.h"
32
33 struct l2cap_client_t {
34 l2cap_client_callbacks_t callbacks;
35 void* context;
36
37 uint16_t local_channel_id;
38 uint16_t remote_mtu;
39 bool configured_self;
40 bool configured_peer;
41 bool is_congested;
42 list_t* outbound_fragments;
43 };
44
45 static void connect_completed_cb(uint16_t local_channel_id,
46 uint16_t error_code);
47 static void config_request_cb(uint16_t local_channel_id,
48 tL2CAP_CFG_INFO* requested_parameters);
49 static void config_completed_cb(uint16_t local_channel_id,
50 tL2CAP_CFG_INFO* negotiated_parameters);
51 static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required);
52 static void disconnect_completed_cb(uint16_t local_channel_id,
53 uint16_t error_code);
54 static void congestion_cb(uint16_t local_channel_id, bool is_congested);
55 static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet);
56 static void write_completed_cb(uint16_t local_channel_id,
57 uint16_t packets_completed);
58
59 static void fragment_packet(l2cap_client_t* client, buffer_t* packet);
60 static void dispatch_fragments(l2cap_client_t* client);
61 static l2cap_client_t* find(uint16_t local_channel_id);
62
63 // From the Bluetooth Core specification.
64 static const uint16_t L2CAP_MTU_DEFAULT = 672;
65 static const uint16_t L2CAP_MTU_MINIMUM = 48;
66
67 static const tL2CAP_APPL_INFO l2cap_callbacks = {
68 .pL2CA_ConnectCfm_Cb = connect_completed_cb,
69 .pL2CA_ConfigInd_Cb = config_request_cb,
70 .pL2CA_ConfigCfm_Cb = config_completed_cb,
71 .pL2CA_DisconnectInd_Cb = disconnect_request_cb,
72 .pL2CA_DisconnectCfm_Cb = disconnect_completed_cb,
73 .pL2CA_CongestionStatus_Cb = congestion_cb,
74 .pL2CA_DataInd_Cb = read_ready_cb,
75 .pL2CA_TxComplete_Cb = write_completed_cb,
76 };
77
78 static list_t*
79 l2cap_clients; // A list of l2cap_client_t. Container does not own objects.
80
l2cap_buffer_new(size_t size)81 buffer_t* l2cap_buffer_new(size_t size) {
82 buffer_t* buf = buffer_new(size + L2CAP_MIN_OFFSET);
83 buffer_t* slice = NULL;
84 if (buf) slice = buffer_new_slice(buf, size);
85 buffer_free(buf);
86 return slice;
87 }
88
l2cap_client_new(const l2cap_client_callbacks_t * callbacks,void * context)89 l2cap_client_t* l2cap_client_new(const l2cap_client_callbacks_t* callbacks,
90 void* context) {
91 CHECK(callbacks != NULL);
92 CHECK(callbacks->connected != NULL);
93 CHECK(callbacks->disconnected != NULL);
94 CHECK(callbacks->read_ready != NULL);
95 CHECK(callbacks->write_ready != NULL);
96
97 if (!l2cap_clients) {
98 l2cap_clients = list_new(NULL);
99 if (!l2cap_clients) {
100 LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.",
101 __func__);
102 return NULL;
103 }
104 }
105
106 l2cap_client_t* ret = (l2cap_client_t*)osi_calloc(sizeof(l2cap_client_t));
107
108 ret->callbacks = *callbacks;
109 ret->context = context;
110
111 ret->remote_mtu = L2CAP_MTU_DEFAULT;
112 ret->outbound_fragments = list_new(NULL);
113
114 list_append(l2cap_clients, ret);
115
116 return ret;
117 }
118
l2cap_client_free(l2cap_client_t * client)119 void l2cap_client_free(l2cap_client_t* client) {
120 if (!client) return;
121
122 list_remove(l2cap_clients, client);
123 l2cap_client_disconnect(client);
124 list_free(client->outbound_fragments);
125 osi_free(client);
126 }
127
l2cap_client_connect(l2cap_client_t * client,const RawAddress & remote_bdaddr,uint16_t psm)128 bool l2cap_client_connect(l2cap_client_t* client,
129 const RawAddress& remote_bdaddr, uint16_t psm) {
130 CHECK(client != NULL);
131 CHECK(psm != 0);
132 CHECK(!remote_bdaddr.IsEmpty());
133 CHECK(client->local_channel_id == 0);
134 CHECK(!client->configured_self);
135 CHECK(!client->configured_peer);
136 CHECK(!L2C_INVALID_PSM(psm));
137
138 client->local_channel_id = L2CA_ConnectReq(psm, remote_bdaddr);
139 if (!client->local_channel_id) {
140 LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
141 return false;
142 }
143
144 L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks);
145 return true;
146 }
147
l2cap_client_disconnect(l2cap_client_t * client)148 void l2cap_client_disconnect(l2cap_client_t* client) {
149 CHECK(client != NULL);
150
151 if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
152 LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.",
153 __func__, client->local_channel_id);
154
155 client->local_channel_id = 0;
156 client->remote_mtu = L2CAP_MTU_DEFAULT;
157 client->configured_self = false;
158 client->configured_peer = false;
159 client->is_congested = false;
160
161 for (const list_node_t* node = list_begin(client->outbound_fragments);
162 node != list_end(client->outbound_fragments); node = list_next(node))
163 osi_free(list_node(node));
164
165 list_clear(client->outbound_fragments);
166 }
167
l2cap_client_is_connected(const l2cap_client_t * client)168 bool l2cap_client_is_connected(const l2cap_client_t* client) {
169 CHECK(client != NULL);
170
171 return client->local_channel_id != 0 && client->configured_self &&
172 client->configured_peer;
173 }
174
l2cap_client_write(l2cap_client_t * client,buffer_t * packet)175 bool l2cap_client_write(l2cap_client_t* client, buffer_t* packet) {
176 CHECK(client != NULL);
177 CHECK(packet != NULL);
178 CHECK(l2cap_client_is_connected(client));
179
180 if (client->is_congested) return false;
181
182 fragment_packet(client, packet);
183 dispatch_fragments(client);
184 return true;
185 }
186
connect_completed_cb(uint16_t local_channel_id,uint16_t error_code)187 static void connect_completed_cb(uint16_t local_channel_id,
188 uint16_t error_code) {
189 CHECK(local_channel_id != 0);
190
191 l2cap_client_t* client = find(local_channel_id);
192 if (!client) {
193 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.",
194 __func__, local_channel_id);
195 return;
196 }
197
198 if (error_code != L2CAP_CONN_OK) {
199 LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__,
200 error_code);
201 client->callbacks.disconnected(client, client->context);
202 return;
203 }
204
205 // Use default L2CAP parameters.
206 tL2CAP_CFG_INFO desired_parameters;
207 memset(&desired_parameters, 0, sizeof(desired_parameters));
208 if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
209 LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
210 client->callbacks.disconnected(client, client->context);
211 }
212 }
213
config_request_cb(uint16_t local_channel_id,tL2CAP_CFG_INFO * requested_parameters)214 static void config_request_cb(uint16_t local_channel_id,
215 tL2CAP_CFG_INFO* requested_parameters) {
216 tL2CAP_CFG_INFO response;
217 l2cap_client_t* client = find(local_channel_id);
218
219 if (!client) {
220 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
221 __func__, local_channel_id);
222 return;
223 }
224
225 memset(&response, 0, sizeof(response));
226 response.result = L2CAP_CFG_OK;
227
228 if (requested_parameters->mtu_present) {
229 // Make sure the peer chose an MTU at least as large as the minimum L2CAP
230 // MTU defined by the Bluetooth Core spec.
231 if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) {
232 response.mtu = L2CAP_MTU_MINIMUM;
233 response.mtu_present = true;
234 response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
235 } else {
236 client->remote_mtu = requested_parameters->mtu;
237 }
238 }
239
240 if (requested_parameters->fcr_present) {
241 if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) {
242 response.fcr_present = true;
243 response.fcr = requested_parameters->fcr;
244 response.fcr.mode = L2CAP_FCR_BASIC_MODE;
245 response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
246 }
247 }
248
249 if (!L2CA_ConfigRsp(local_channel_id, &response)) {
250 LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.",
251 __func__, local_channel_id);
252 l2cap_client_disconnect(client);
253 return;
254 }
255
256 // If we've configured both endpoints, let the listener know we've connected.
257 client->configured_peer = true;
258 if (l2cap_client_is_connected(client))
259 client->callbacks.connected(client, client->context);
260 }
261
config_completed_cb(uint16_t local_channel_id,tL2CAP_CFG_INFO * negotiated_parameters)262 static void config_completed_cb(uint16_t local_channel_id,
263 tL2CAP_CFG_INFO* negotiated_parameters) {
264 l2cap_client_t* client = find(local_channel_id);
265
266 if (!client) {
267 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
268 __func__, local_channel_id);
269 return;
270 }
271
272 switch (negotiated_parameters->result) {
273 // We'll get another configuration response later.
274 case L2CAP_CFG_PENDING:
275 break;
276
277 case L2CAP_CFG_UNACCEPTABLE_PARAMS:
278 // TODO: see if we can renegotiate parameters instead of dropping the
279 // connection.
280 LOG_WARN(
281 LOG_TAG,
282 "%s dropping L2CAP connection due to unacceptable config parameters.",
283 __func__);
284 l2cap_client_disconnect(client);
285 break;
286
287 case L2CAP_CFG_OK:
288 // If we've configured both endpoints, let the listener know we've
289 // connected.
290 client->configured_self = true;
291 if (l2cap_client_is_connected(client))
292 client->callbacks.connected(client, client->context);
293 break;
294
295 // Failure, no further parameter negotiation possible.
296 default:
297 LOG_WARN(LOG_TAG,
298 "%s L2CAP parameter negotiation failed with error code %d.",
299 __func__, negotiated_parameters->result);
300 l2cap_client_disconnect(client);
301 break;
302 }
303 }
304
disconnect_request_cb(uint16_t local_channel_id,bool ack_required)305 static void disconnect_request_cb(uint16_t local_channel_id,
306 bool ack_required) {
307 l2cap_client_t* client = find(local_channel_id);
308 if (!client) {
309 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.",
310 __func__, local_channel_id);
311 return;
312 }
313
314 if (ack_required) L2CA_DisconnectRsp(local_channel_id);
315
316 // We already sent a disconnect response so this LCID is now invalid.
317 client->local_channel_id = 0;
318 l2cap_client_disconnect(client);
319
320 client->callbacks.disconnected(client, client->context);
321 }
322
disconnect_completed_cb(uint16_t local_channel_id,UNUSED_ATTR uint16_t error_code)323 static void disconnect_completed_cb(uint16_t local_channel_id,
324 UNUSED_ATTR uint16_t error_code) {
325 CHECK(local_channel_id != 0);
326
327 l2cap_client_t* client = find(local_channel_id);
328 if (!client) {
329 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.",
330 __func__, local_channel_id);
331 return;
332 }
333
334 client->local_channel_id = 0;
335 l2cap_client_disconnect(client);
336
337 client->callbacks.disconnected(client, client->context);
338 }
339
congestion_cb(uint16_t local_channel_id,bool is_congested)340 static void congestion_cb(uint16_t local_channel_id, bool is_congested) {
341 CHECK(local_channel_id != 0);
342
343 l2cap_client_t* client = find(local_channel_id);
344 if (!client) {
345 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
346 __func__, local_channel_id);
347 return;
348 }
349
350 client->is_congested = is_congested;
351
352 if (!is_congested) {
353 // If we just decongested, dispatch whatever we have left over in our queue.
354 // Once that's done, if we're still decongested, notify the listener so it
355 // can start writing again.
356 dispatch_fragments(client);
357 if (!client->is_congested)
358 client->callbacks.write_ready(client, client->context);
359 }
360 }
361
read_ready_cb(uint16_t local_channel_id,BT_HDR * packet)362 static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet) {
363 CHECK(local_channel_id != 0);
364
365 l2cap_client_t* client = find(local_channel_id);
366 if (!client) {
367 LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
368 __func__, local_channel_id);
369 return;
370 }
371
372 // TODO(sharvil): eliminate copy from BT_HDR.
373 buffer_t* buffer = buffer_new(packet->len);
374 memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len);
375 osi_free(packet);
376
377 client->callbacks.read_ready(client, buffer, client->context);
378 buffer_free(buffer);
379 }
380
write_completed_cb(UNUSED_ATTR uint16_t local_channel_id,UNUSED_ATTR uint16_t packets_completed)381 static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id,
382 UNUSED_ATTR uint16_t packets_completed) {
383 // Do nothing. We update congestion state based on the congestion callback
384 // and we've already removed items from outbound_fragments list so we don't
385 // really care how many packets were successfully dispatched.
386 }
387
fragment_packet(l2cap_client_t * client,buffer_t * packet)388 static void fragment_packet(l2cap_client_t* client, buffer_t* packet) {
389 CHECK(client != NULL);
390 CHECK(packet != NULL);
391
392 // TODO(sharvil): eliminate copy into BT_HDR.
393 BT_HDR* bt_packet = static_cast<BT_HDR*>(
394 osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET + sizeof(BT_HDR)));
395 bt_packet->offset = L2CAP_MIN_OFFSET;
396 bt_packet->len = buffer_length(packet);
397 memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet),
398 buffer_length(packet));
399
400 for (;;) {
401 if (bt_packet->len <= client->remote_mtu) {
402 if (bt_packet->len > 0)
403 list_append(client->outbound_fragments, bt_packet);
404 else
405 osi_free(bt_packet);
406 break;
407 }
408
409 BT_HDR* fragment = static_cast<BT_HDR*>(
410 osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET + sizeof(BT_HDR)));
411 fragment->offset = L2CAP_MIN_OFFSET;
412 fragment->len = client->remote_mtu;
413 memcpy(fragment->data + fragment->offset,
414 bt_packet->data + bt_packet->offset, client->remote_mtu);
415
416 list_append(client->outbound_fragments, fragment);
417
418 bt_packet->offset += client->remote_mtu;
419 bt_packet->len -= client->remote_mtu;
420 }
421 }
422
dispatch_fragments(l2cap_client_t * client)423 static void dispatch_fragments(l2cap_client_t* client) {
424 CHECK(client != NULL);
425 CHECK(!client->is_congested);
426
427 while (!list_is_empty(client->outbound_fragments)) {
428 BT_HDR* packet = (BT_HDR*)list_front(client->outbound_fragments);
429 list_remove(client->outbound_fragments, packet);
430
431 switch (L2CA_DataWrite(client->local_channel_id, packet)) {
432 case L2CAP_DW_CONGESTED:
433 client->is_congested = true;
434 return;
435
436 case L2CAP_DW_FAILED:
437 LOG_ERROR(LOG_TAG,
438 "%s error writing data to L2CAP connection LCID 0x%04x; "
439 "disconnecting.",
440 __func__, client->local_channel_id);
441 l2cap_client_disconnect(client);
442 return;
443
444 case L2CAP_DW_SUCCESS:
445 break;
446 }
447 }
448 }
449
find(uint16_t local_channel_id)450 static l2cap_client_t* find(uint16_t local_channel_id) {
451 CHECK(local_channel_id != 0);
452
453 for (const list_node_t* node = list_begin(l2cap_clients);
454 node != list_end(l2cap_clients); node = list_next(node)) {
455 l2cap_client_t* client = (l2cap_client_t*)list_node(node);
456 if (client->local_channel_id == local_channel_id) return client;
457 }
458
459 return NULL;
460 }
461