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