OSDN Git Service

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