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