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