OSDN Git Service

Merge commit 'e71c667e24e77144781835fcbaedddfc841e88c3'
[android-x86/system-bt.git] / stack / l2cap / l2cap_client.c
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
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
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   if (!ret) {
102     LOG_ERROR(LOG_TAG, "%s unable to allocate L2CAP client.", __func__);
103     goto error;
104   }
105
106   ret->callbacks = *callbacks;
107   ret->context = context;
108
109   ret->remote_mtu = L2CAP_MTU_DEFAULT;
110   ret->outbound_fragments = list_new(NULL);
111   if (!ret) {
112     LOG_ERROR(LOG_TAG, "%s unable to allocate outbound L2CAP fragment list.", __func__);
113     goto error;
114   }
115
116   list_append(l2cap_clients, ret);
117
118   return ret;
119
120 error:;
121   osi_free(ret);
122   return NULL;
123 }
124
125 void l2cap_client_free(l2cap_client_t *client) {
126   if (!client)
127     return;
128
129   list_remove(l2cap_clients, client);
130   l2cap_client_disconnect(client);
131   list_free(client->outbound_fragments);
132   osi_free(client);
133 }
134
135 bool l2cap_client_connect(l2cap_client_t *client, const bt_bdaddr_t *remote_bdaddr, uint16_t psm) {
136   assert(client != NULL);
137   assert(remote_bdaddr != NULL);
138   assert(psm != 0);
139   assert(!bdaddr_is_empty(remote_bdaddr));
140   assert(client->local_channel_id == 0);
141   assert(!client->configured_self);
142   assert(!client->configured_peer);
143   assert(!L2C_INVALID_PSM(psm));
144
145   client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t *)remote_bdaddr);
146   if (!client->local_channel_id) {
147     LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
148     return false;
149   }
150
151   L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks);
152   return true;
153 }
154
155 void l2cap_client_disconnect(l2cap_client_t *client) {
156   assert(client != NULL);
157
158   if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
159     LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.", __func__, client->local_channel_id);
160
161   client->local_channel_id = 0;
162   client->remote_mtu = L2CAP_MTU_DEFAULT;
163   client->configured_self = false;
164   client->configured_peer = false;
165   client->is_congested = false;
166
167   for (const list_node_t *node = list_begin(client->outbound_fragments); node != list_end(client->outbound_fragments); node = list_next(node))
168     osi_freebuf(list_node(node));
169
170   list_clear(client->outbound_fragments);
171 }
172
173 bool l2cap_client_is_connected(const l2cap_client_t *client) {
174   assert(client != NULL);
175
176   return client->local_channel_id != 0 && client->configured_self && client->configured_peer;
177 }
178
179 bool l2cap_client_write(l2cap_client_t *client, buffer_t *packet) {
180   assert(client != NULL);
181   assert(packet != NULL);
182   assert(l2cap_client_is_connected(client));
183
184   if (client->is_congested)
185     return false;
186
187   fragment_packet(client, packet);
188   dispatch_fragments(client);
189   return true;
190 }
191
192 static void connect_completed_cb(uint16_t local_channel_id, uint16_t error_code) {
193   assert(local_channel_id != 0);
194
195   l2cap_client_t *client = find(local_channel_id);
196   if (!client) {
197     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.", __func__, local_channel_id);
198     return;
199   }
200
201   if (error_code != L2CAP_CONN_OK) {
202     LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__, error_code);
203     client->callbacks.disconnected(client, client->context);
204     return;
205   }
206
207   // Use default L2CAP parameters.
208   tL2CAP_CFG_INFO desired_parameters = { 0 };
209   if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
210     LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
211     client->callbacks.disconnected(client, client->context);
212   }
213 }
214
215 static void config_request_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *requested_parameters) {
216   tL2CAP_CFG_INFO response = { 0 };
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.", __func__, local_channel_id);
221     return;
222   }
223
224   response.result = L2CAP_CFG_OK;
225
226   if (requested_parameters->mtu_present) {
227     // Make sure the peer chose an MTU at least as large as the minimum L2CAP MTU defined
228     // by the Bluetooth Core spec.
229     if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) {
230       response.mtu = L2CAP_MTU_MINIMUM;
231       response.mtu_present = true;
232       response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
233     } else {
234       client->remote_mtu = requested_parameters->mtu;
235     }
236   }
237
238   if (requested_parameters->fcr_present) {
239     if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) {
240       response.fcr_present = true;
241       response.fcr = requested_parameters->fcr;
242       response.fcr.mode = L2CAP_FCR_BASIC_MODE;
243       response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
244     }
245   }
246
247   if (!L2CA_ConfigRsp(local_channel_id, &response)) {
248     LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.", __func__, local_channel_id);
249     l2cap_client_disconnect(client);
250     return;
251   }
252
253   // If we've configured both endpoints, let the listener know we've connected.
254   client->configured_peer = true;
255   if (l2cap_client_is_connected(client))
256     client->callbacks.connected(client, client->context);
257 }
258
259 static void config_completed_cb(uint16_t local_channel_id, tL2CAP_CFG_INFO *negotiated_parameters) {
260   l2cap_client_t *client = find(local_channel_id);
261
262   if (!client) {
263     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
264     return;
265   }
266
267   switch (negotiated_parameters->result) {
268     // We'll get another configuration response later.
269     case L2CAP_CFG_PENDING:
270       break;
271
272     case L2CAP_CFG_UNACCEPTABLE_PARAMS:
273       // TODO: see if we can renegotiate parameters instead of dropping the connection.
274       LOG_WARN(LOG_TAG, "%s dropping L2CAP connection due to unacceptable config parameters.", __func__);
275       l2cap_client_disconnect(client);
276       break;
277
278     case L2CAP_CFG_OK:
279       // If we've configured both endpoints, let the listener know we've connected.
280       client->configured_self = true;
281       if (l2cap_client_is_connected(client))
282         client->callbacks.connected(client, client->context);
283       break;
284
285     // Failure, no further parameter negotiation possible.
286     default:
287       LOG_WARN(LOG_TAG, "%s L2CAP parameter negotiation failed with error code %d.", __func__, negotiated_parameters->result);
288       l2cap_client_disconnect(client);
289       break;
290   }
291 }
292
293 static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required) {
294   l2cap_client_t *client = find(local_channel_id);
295   if (!client) {
296     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
297     return;
298   }
299
300   if (ack_required)
301     L2CA_DisconnectRsp(local_channel_id);
302
303   // We already sent a disconnect response so this LCID is now invalid.
304   client->local_channel_id = 0;
305   l2cap_client_disconnect(client);
306
307   client->callbacks.disconnected(client, client->context);
308 }
309
310 static void disconnect_completed_cb(uint16_t local_channel_id, UNUSED_ATTR uint16_t error_code) {
311   assert(local_channel_id != 0);
312
313   l2cap_client_t *client = find(local_channel_id);
314   if (!client) {
315     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.", __func__, local_channel_id);
316     return;
317   }
318
319   client->local_channel_id = 0;
320   l2cap_client_disconnect(client);
321
322   client->callbacks.disconnected(client, client->context);
323 }
324
325 static void congestion_cb(uint16_t local_channel_id, bool is_congested) {
326   assert(local_channel_id != 0);
327
328   l2cap_client_t *client = find(local_channel_id);
329   if (!client) {
330     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
331     return;
332   }
333
334   client->is_congested = is_congested;
335
336   if (!is_congested) {
337     // If we just decongested, dispatch whatever we have left over in our queue.
338     // Once that's done, if we're still decongested, notify the listener so it
339     // can start writing again.
340     dispatch_fragments(client);
341     if (!client->is_congested)
342       client->callbacks.write_ready(client, client->context);
343   }
344 }
345
346 static void read_ready_cb(uint16_t local_channel_id, BT_HDR *packet) {
347   assert(local_channel_id != 0);
348
349   l2cap_client_t *client = find(local_channel_id);
350   if (!client) {
351     LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.", __func__, local_channel_id);
352     return;
353   }
354
355   // TODO(sharvil): eliminate copy from BT_HDR.
356   buffer_t *buffer = buffer_new(packet->len);
357   memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len);
358   osi_freebuf(packet);
359
360   client->callbacks.read_ready(client, buffer, client->context);
361   buffer_free(buffer);
362 }
363
364 static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id, UNUSED_ATTR uint16_t packets_completed) {
365   // Do nothing. We update congestion state based on the congestion callback
366   // and we've already removed items from outbound_fragments list so we don't
367   // really care how many packets were successfully dispatched.
368 }
369
370 static void fragment_packet(l2cap_client_t *client, buffer_t *packet) {
371   assert(client != NULL);
372   assert(packet != NULL);
373
374   // TODO(sharvil): eliminate copy into BT_HDR.
375   BT_HDR *bt_packet = osi_getbuf(buffer_length(packet) + L2CAP_MIN_OFFSET);
376   bt_packet->offset = L2CAP_MIN_OFFSET;
377   bt_packet->len = buffer_length(packet);
378   memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet), buffer_length(packet));
379
380   for (;;) {
381     if (bt_packet->len <= client->remote_mtu) {
382       if (bt_packet->len > 0)
383         list_append(client->outbound_fragments, bt_packet);
384       else
385         osi_freebuf(bt_packet);
386       break;
387     }
388
389     BT_HDR *fragment = osi_getbuf(client->remote_mtu + L2CAP_MIN_OFFSET);
390     fragment->offset = L2CAP_MIN_OFFSET;
391     fragment->len = client->remote_mtu;
392     memcpy(fragment->data + fragment->offset, bt_packet->data + bt_packet->offset, client->remote_mtu);
393
394     list_append(client->outbound_fragments, fragment);
395
396     bt_packet->offset += client->remote_mtu;
397     bt_packet->len -= client->remote_mtu;
398   }
399 }
400
401 static void dispatch_fragments(l2cap_client_t *client) {
402   assert(client != NULL);
403   assert(!client->is_congested);
404
405   while (!list_is_empty(client->outbound_fragments)) {
406     BT_HDR *packet = (BT_HDR *)list_front(client->outbound_fragments);
407     list_remove(client->outbound_fragments, packet);
408
409     switch (L2CA_DataWrite(client->local_channel_id, packet)) {
410       case L2CAP_DW_CONGESTED:
411         client->is_congested = true;
412         return;
413
414       case L2CAP_DW_FAILED:
415         LOG_ERROR(LOG_TAG, "%s error writing data to L2CAP connection LCID 0x%04x; disconnecting.", __func__, client->local_channel_id);
416         l2cap_client_disconnect(client);
417         return;
418
419       case L2CAP_DW_SUCCESS:
420         break;
421     }
422   }
423 }
424
425 static l2cap_client_t *find(uint16_t local_channel_id) {
426   assert(local_channel_id != 0);
427
428   for (const list_node_t *node = list_begin(l2cap_clients); node != list_end(l2cap_clients); node = list_next(node)) {
429     l2cap_client_t *client = (l2cap_client_t *)list_node(node);
430     if (client->local_channel_id == local_channel_id)
431       return client;
432   }
433
434   return NULL;
435 }