blob: a3e4398d435fc6fbb9ee7c5b31a161cb06cea499 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 2009-2012 Broadcom Corporation
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/************************************************************************************
20 *
21 * Filename: btif_sock_rfc.c
22 *
23 * Description: Handsfree Profile Bluetooth Interface
24 *
25 ***********************************************************************************/
Sharvil Nanavati847ea132014-04-25 22:38:55 -070026#include <assert.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080027#include <hardware/bluetooth.h>
28#include <hardware/bt_sock.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <errno.h>
32#include <sys/ioctl.h>
33
34#define LOG_TAG "BTIF_SOCK"
35#include "btif_common.h"
36#include "btif_util.h"
37
38#include "bd.h"
39
40#include "bta_api.h"
41#include "btif_sock_thread.h"
Srinu Jella95447392015-02-13 16:09:22 +053042#include "btif_sock.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080043#include "btif_sock_sdp.h"
44#include "btif_sock_util.h"
45
46#include "bt_target.h"
47#include "gki.h"
48#include "hcimsgs.h"
49#include "sdp_api.h"
50#include "btu.h"
51#include "btm_api.h"
52#include "btm_int.h"
53#include "bta_jv_api.h"
54#include "bta_jv_co.h"
55#include "port_api.h"
Sharvil Nanavati847ea132014-04-25 22:38:55 -070056#include "list.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080057
58#include <cutils/log.h>
59#include <hardware/bluetooth.h>
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -070060#define asrt(s) if(!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
The Android Open Source Project5738f832012-12-12 16:00:35 -080061
Srinu Jella1c355d42013-10-21 11:41:15 +053062#define MODEM_SIGNAL_DTRDSR 0x01
63#define MODEM_SIGNAL_RTSCTS 0x02
64#define MODEM_SIGNAL_RI 0x04
65#define MODEM_SIGNAL_DCD 0x08
66
Srinu Jellaedadca02013-07-05 18:20:40 +053067#define UUID_MAX_LENGTH 16
68
69#define IS_UUID(u1,u2) !memcmp(u1,u2,UUID_MAX_LENGTH)
70
The Android Open Source Project5738f832012-12-12 16:00:35 -080071extern void uuid_to_string(bt_uuid_t *p_uuid, char *str);
72static inline void logu(const char* title, const uint8_t * p_uuid)
73{
74 char uuids[128];
75 uuid_to_string((bt_uuid_t*)p_uuid, uuids);
76 ALOGD("%s: %s", title, uuids);
77}
78
79
80
The Android Open Source Project5738f832012-12-12 16:00:35 -080081#define MAX_RFC_SESSION BTA_JV_MAX_RFC_SR_SESSION //3 by default
82typedef struct {
83 int outgoing_congest : 1;
84 int pending_sdp_request : 1;
85 int doing_sdp_request : 1;
86 int server : 1;
87 int connected : 1;
88 int closing : 1;
89} flags_t;
90
91typedef struct {
92 flags_t f;
93 uint32_t id;
Srinu Jella95447392015-02-13 16:09:22 +053094 BOOLEAN in_use;
The Android Open Source Project5738f832012-12-12 16:00:35 -080095 int security;
96 int scn;
97 bt_bdaddr_t addr;
98 uint8_t service_uuid[16];
99 char service_name[256];
100 int fd, app_fd;
101 int mtu;
102 uint8_t* packet;
103 int sdp_handle;
104 int rfc_handle;
105 int rfc_port_handle;
106 int role;
Sharvil Nanavati847ea132014-04-25 22:38:55 -0700107 list_t *incoming_queue;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800108} rfc_slot_t;
109
110static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
The Android Open Source Project5738f832012-12-12 16:00:35 -0800111static volatile int pth = -1; //poll thread handle
112static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
113static void cleanup_rfc_slot(rfc_slot_t* rs);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800114static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
115static inline BOOLEAN send_app_scn(rfc_slot_t* rs);
116static pthread_mutex_t slot_lock;
117#define is_init_done() (pth != -1)
118static inline void clear_slot_flag(flags_t* f)
119{
120 memset(f, 0, sizeof(*f));
121}
122
123static inline void bd_copy(UINT8* dest, UINT8* src, BOOLEAN swap)
124{
125 if (swap)
126 {
127 int i;
128 for (i =0; i < 6 ;i++)
129 dest[i]= src[5-i];
130 }
131 else memcpy(dest, src, 6);
132}
The Android Open Source Project5738f832012-12-12 16:00:35 -0800133static void init_rfc_slots()
134{
135 int i;
136 memset(rfc_slots, 0, sizeof(rfc_slot_t)*MAX_RFC_CHANNEL);
137 for(i = 0; i < MAX_RFC_CHANNEL; i++)
138 {
139 rfc_slots[i].scn = -1;
140 rfc_slots[i].sdp_handle = 0;
141 rfc_slots[i].fd = rfc_slots[i].app_fd = -1;
Srinu Jella95447392015-02-13 16:09:22 +0530142 rfc_slots[i].id = BASE_RFCOMM_SLOT_ID + i;
Sharvil Nanavati847ea132014-04-25 22:38:55 -0700143 rfc_slots[i].incoming_queue = list_new(GKI_freebuf);
144 assert(rfc_slots[i].incoming_queue != NULL);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800145 }
146 BTA_JvEnable(jv_dm_cback);
147 init_slot_lock(&slot_lock);
148}
149bt_status_t btsock_rfc_init(int poll_thread_handle)
150{
151 pth = poll_thread_handle;
Hemant Gupta9cd26bf2013-09-10 12:01:18 +0530152 btif_data_profile_register(0);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800153 init_rfc_slots();
154 return BT_STATUS_SUCCESS;
155}
156void btsock_rfc_cleanup()
157{
158 int curr_pth = pth;
159 pth = -1;
Hemant Gupta9cd26bf2013-09-10 12:01:18 +0530160 btif_data_profile_register(0);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800161 btsock_thread_exit(curr_pth);
162 lock_slot(&slot_lock);
163 int i;
164 for(i = 0; i < MAX_RFC_CHANNEL; i++)
165 {
Srinu Jella95447392015-02-13 16:09:22 +0530166 if(rfc_slots[i].in_use) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800167 cleanup_rfc_slot(&rfc_slots[i]);
Sharvil Nanavati847ea132014-04-25 22:38:55 -0700168 list_free(rfc_slots[i].incoming_queue);
169 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800170 }
171 unlock_slot(&slot_lock);
172}
173static inline rfc_slot_t* find_free_slot()
174{
175 int i;
176 for(i = 0; i < MAX_RFC_CHANNEL; i++)
177 {
178 if(rfc_slots[i].fd == -1)
179 {
180 return &rfc_slots[i];
181 }
182 }
183 return NULL;
184}
185static inline rfc_slot_t* find_rfc_slot_by_id(uint32_t id)
186{
187 int i;
188 if(id)
189 {
190 for(i = 0; i < MAX_RFC_CHANNEL; i++)
191 {
Srinu Jella95447392015-02-13 16:09:22 +0530192 if(rfc_slots[i].in_use && (rfc_slots[i].id == id))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800193 {
194 return &rfc_slots[i];
195 }
196 }
197 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700198 APPL_TRACE_WARNING("invalid rfc slot id: %d", id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800199 return NULL;
200}
201static inline rfc_slot_t* find_rfc_slot_by_pending_sdp()
202{
203 uint32_t min_id = (uint32_t)-1;
204 int slot = -1;
205 int i;
206 for(i = 0; i < MAX_RFC_CHANNEL; i++)
207 {
Srinu Jella95447392015-02-13 16:09:22 +0530208 if(rfc_slots[i].in_use && rfc_slots[i].f.pending_sdp_request)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800209 {
210 if(rfc_slots[i].id < min_id)
211 {
212 min_id = rfc_slots[i].id;
213 slot = i;
214 }
215 }
216 }
217 if(0<= slot && slot < MAX_RFC_CHANNEL)
218 return &rfc_slots[slot];
219 return NULL;
220}
221static inline rfc_slot_t* find_rfc_slot_requesting_sdp()
222{
223 int i;
224 for(i = 0; i < MAX_RFC_CHANNEL; i++)
225 {
Srinu Jella95447392015-02-13 16:09:22 +0530226 if(rfc_slots[i].in_use && rfc_slots[i].f.doing_sdp_request)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800227 return &rfc_slots[i];
228 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700229 APPL_TRACE_DEBUG("can not find any slot is requesting sdp");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800230 return NULL;
231}
232
233static inline rfc_slot_t* find_rfc_slot_by_fd(int fd)
234{
235 int i;
236 if(fd >= 0)
237 {
238 for(i = 0; i < MAX_RFC_CHANNEL; i++)
239 {
240 if(rfc_slots[i].fd == fd)
241 {
Srinu Jella95447392015-02-13 16:09:22 +0530242 if(rfc_slots[i].in_use)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800243 return &rfc_slots[i];
244 else
245 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700246 APPL_TRACE_ERROR("invalid rfc slot id, cannot be 0");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800247 break;
248 }
249 }
250 }
251 }
252 return NULL;
253}
Srinu Jella1c355d42013-10-21 11:41:15 +0530254
255static inline rfc_slot_t* find_rfc_slot_by_scn(int scn)
256{
257 int i;
258 if(scn > 0)
259 {
260 /* traverse it from the last entry, as incase of
261 * server two entries will exist with the same scn
262 * and the later entry is valid
263 */
264 for(i = MAX_RFC_CHANNEL-1; i >= 0; i--)
265 {
266 if(rfc_slots[i].scn == scn)
267 {
Srinu Jella95447392015-02-13 16:09:22 +0530268 if(rfc_slots[i].in_use)
Srinu Jella1c355d42013-10-21 11:41:15 +0530269 return &rfc_slots[i];
270 }
271 }
272 }
273 return NULL;
274}
275
The Android Open Source Project5738f832012-12-12 16:00:35 -0800276static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t *addr, const char* name, const uint8_t* uuid, int channel, int flags, BOOLEAN server)
277{
278 int security = 0;
279 if(flags & BTSOCK_FLAG_ENCRYPT)
280 security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
Srinu Jellaedadca02013-07-05 18:20:40 +0530281 if(flags & BTSOCK_FLAG_AUTH) {
282 /* Convert SAP Authentication to High Authentication */
283 if(IS_UUID(UUID_SAP, uuid)) {
284 security |= BTM_SEC_IN_AUTH_HIGH;
285 }
286 else {
287 security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
288 }
289 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800290 rfc_slot_t* rs = find_free_slot();
291 if(rs)
292 {
293 int fds[2] = {-1, -1};
294 if(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds))
295 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700296 APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800297 return NULL;
298 }
299 rs->fd = fds[0];
300 rs->app_fd = fds[1];
301 rs->security = security;
302 rs->scn = channel;
303 if(uuid)
304 memcpy(rs->service_uuid, uuid, sizeof(rs->service_uuid));
305 else memset(rs->service_uuid, 0, sizeof(rs->service_uuid));
306 if(name && *name)
307 strncpy(rs->service_name, name, sizeof(rs->service_name) -1);
308 if(addr)
309 rs->addr = *addr;
Srinu Jella95447392015-02-13 16:09:22 +0530310 rs->in_use = TRUE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800311 rs->f.server = server;
312 }
313 return rs;
314}
315// rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, p_open->rem_bda,p_opne->handle, p_open->new_listen_handle);
316static inline rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const bt_bdaddr_t* addr,
317 int open_handle, int new_listen_handle)
318{
319 rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, FALSE);
Srinu Jellaa7bd2a12014-01-24 15:33:22 +0530320 if( accept_rs)
321 {
322 clear_slot_flag(&accept_rs->f);
323 accept_rs->f.server = FALSE;
324 accept_rs->f.connected = TRUE;
325 accept_rs->security = srv_rs->security;
326 accept_rs->mtu = srv_rs->mtu;
327 accept_rs->role = srv_rs->role;
328 accept_rs->rfc_handle = open_handle;
329 accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
330 //now update listen rfc_handle of server slot
331 srv_rs->rfc_handle = new_listen_handle;
332 srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
Matthew Xieafa6e1a2014-06-28 11:35:29 -0700333 BTIF_TRACE_DEBUG("create_srv_accept__rfc_slot(open_handle: 0x%x, new_listen_handle:"
Srinu Jellaa7bd2a12014-01-24 15:33:22 +0530334 "0x%x) accept_rs->rfc_handle:0x%x, srv_rs_listen->rfc_handle:0x%x"
335 ,open_handle, new_listen_handle, accept_rs->rfc_port_handle, srv_rs->rfc_port_handle);
336 asrt(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle);
337 //now swap the slot id
338 uint32_t new_listen_id = accept_rs->id;
339 accept_rs->id = srv_rs->id;
340 srv_rs->id = new_listen_id;
341
342 return accept_rs;
343 }
344 else
345 {
Matthew Xieafa6e1a2014-06-28 11:35:29 -0700346 APPL_TRACE_ERROR(" accept_rs is NULL %s", __FUNCTION__);
Srinu Jellaa7bd2a12014-01-24 15:33:22 +0530347 return NULL;
348 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800349}
350bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel,
351 int* sock_fd, int flags)
352{
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800353
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700354 APPL_TRACE_DEBUG("btsock_rfc_listen, service_name:%s", service_name);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800355 if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30)))
356 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700357 APPL_TRACE_ERROR("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800358 return BT_STATUS_PARM_INVALID;
359 }
360 *sock_fd = -1;
361 if(!is_init_done())
362 return BT_STATUS_NOT_READY;
Hemant Gupta9cd26bf2013-09-10 12:01:18 +0530363
364 btif_data_profile_register(1);
365
Ashwini Munigalae6cbebf2013-10-01 19:25:28 +0530366 if(channel == RESERVED_SCN_FTP)
367 {
368 service_uuid = UUID_FTP;
369 }
370 else if(is_uuid_empty(service_uuid))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800371 service_uuid = UUID_SPP; //use serial port profile to listen to specified channel
372 else
373 {
Ashwini Munigalae6cbebf2013-10-01 19:25:28 +0530374 if (!strncmp(service_name, "OBEX File Transfer", strlen("OBEX File Transfer"))) {
375 channel = RESERVED_SCN_FTP;
376 APPL_TRACE_DEBUG("Registering FTP SDP for: %s", service_name);
377 } else {
378 //Check the service_uuid. overwrite the channel # if reserved
379 int reserved_channel = get_reserved_rfc_channel(service_uuid);
380 if(reserved_channel > 0)
381 {
382 channel = reserved_channel;
383 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800384 }
385 }
386 int status = BT_STATUS_FAIL;
387 lock_slot(&slot_lock);
388 rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE);
389 if(rs)
390 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700391 APPL_TRACE_DEBUG("BTA_JvCreateRecordByUser:%s", service_name);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000392 BTA_JvCreateRecordByUser((void *)(intptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800393 *sock_fd = rs->app_fd;
394 rs->app_fd = -1; //the fd ownership is transferred to app
Matthew Xieec2777e2014-09-02 23:39:43 -0700395 if (btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id)) {
396 status = BT_STATUS_SUCCESS;
397 }
398 else
399 {
400 cleanup_rfc_slot(rs);
401 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800402 }
403 unlock_slot(&slot_lock);
404 return status;
405}
Srinu Jella1c355d42013-10-21 11:41:15 +0530406
407bt_status_t btsock_rfc_get_sockopt(int channel, btsock_option_type_t option_name,
408 void *option_value, int *option_len)
409{
410 int status = BT_STATUS_FAIL;
411
412 APPL_TRACE_DEBUG("btsock_rfc_get_sockopt channel is %d ", channel);
413 if((channel < 1) || (channel > 30) || (option_value == NULL) || (option_len == NULL))
414 {
415 APPL_TRACE_ERROR("invalid rfc channel:%d or option_value:%p, option_len:%p",
416 channel, option_value, option_len);
417 return BT_STATUS_PARM_INVALID;
418 }
419 rfc_slot_t* rs = find_rfc_slot_by_scn(channel);
420 if((rs) && ((option_name == BTSOCK_OPT_GET_MODEM_BITS)))
421 {
422 if(PORT_SUCCESS == PORT_GetModemStatus(rs->rfc_port_handle, (UINT8 *)option_value))
423 {
424 *option_len = sizeof(UINT8);
425 status = BT_STATUS_SUCCESS;
426 }
427 }
Srinu Jella3b92b072015-02-06 15:27:31 +0530428 else if((rs) && ((option_name == BTSOCK_OPT_GET_CONG_STATUS)))
429 {
430 if(rs->f.outgoing_congest)
431 {
432 *((UINT8 *)option_value) = 1;
433 }
434 else
435 {
436 *((UINT8 *)option_value) = 0;
437 }
438 *option_len = sizeof(UINT8);
439
440 status = BT_STATUS_SUCCESS;
441 }
Srinu Jella1c355d42013-10-21 11:41:15 +0530442 return status;
443}
444
445bt_status_t btsock_rfc_set_sockopt(int channel, btsock_option_type_t option_name,
446 void *option_value, int option_len)
447{
448 int status = BT_STATUS_FAIL;
449
450 APPL_TRACE_DEBUG("btsock_rfc_get_sockopt channel is %d ", channel);
451 if((channel < 1) || (channel > 30) || (option_value == NULL) || (option_len <= 0)
452 || (option_len > (int)sizeof(UINT8)))
453 {
454 APPL_TRACE_ERROR("invalid rfc channel:%d or option_value:%p, option_len:%d",
455 channel, option_value, option_len);
456 return BT_STATUS_PARM_INVALID;
457 }
458 rfc_slot_t* rs = find_rfc_slot_by_scn(channel);
459 if((rs) && ((option_name == BTSOCK_OPT_SET_MODEM_BITS)))
460 {
461 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DTRDSR)
462 {
463 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_DTRDSR))
464 return status;
465 }
466 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RTSCTS)
467 {
468 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_CTSRTS))
469 return status;
470 }
471 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RI)
472 {
473 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_RI))
474 return status;
475 }
476 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DCD)
477 {
478 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_SET_DCD))
479 return status;
480 }
481 status = BT_STATUS_SUCCESS;
482 }
483 else if((rs) && ((option_name == BTSOCK_OPT_CLR_MODEM_BITS)))
484 {
485 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DTRDSR)
486 {
487 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_DTRDSR))
488 return status;
489 }
490 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RTSCTS)
491 {
492 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_CTSRTS))
493 return status;
494 }
495 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_RI)
496 {
497 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_RI))
498 return status;
499 }
500 if((*((UINT8 *)option_value)) & MODEM_SIGNAL_DCD)
501 {
502 if(PORT_SUCCESS != PORT_Control(rs->rfc_port_handle, PORT_CLR_DCD))
503 return status;
504 }
505 status = BT_STATUS_SUCCESS;
506 }
507
508 return status;
509}
510
The Android Open Source Project5738f832012-12-12 16:00:35 -0800511bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid,
512 int channel, int* sock_fd, int flags)
513{
514 if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30)))
515 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700516 APPL_TRACE_ERROR("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800517 service_uuid);
518 return BT_STATUS_PARM_INVALID;
519 }
520 *sock_fd = -1;
521 if(!is_init_done())
522 return BT_STATUS_NOT_READY;
523 int status = BT_STATUS_FAIL;
Sai Aitharajub3dcacc2014-11-05 15:25:35 +0530524 if(!service_uuid)
525 {
526 APPL_TRACE_ERROR("Service uuid is NULL");
527 return status;
528 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800529 lock_slot(&slot_lock);
530 rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE);
531 if(rs)
532 {
533 if(is_uuid_empty(service_uuid))
534 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700535 APPL_TRACE_DEBUG("connecting to rfcomm channel:%d without service discovery", channel);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800536 if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address,
Kévin PETIT22c6e502014-02-12 17:24:01 +0000537 rfcomm_cback, (void*)(intptr_t)rs->id) == BTA_JV_SUCCESS)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800538 {
539 if(send_app_scn(rs))
540 {
541 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM,
542 SOCK_THREAD_FD_RD, rs->id);
543 *sock_fd = rs->app_fd;
544 rs->app_fd = -1; //the fd ownership is transferred to app
545 status = BT_STATUS_SUCCESS;
546 }
547 else cleanup_rfc_slot(rs);
548 }
549 else cleanup_rfc_slot(rs);
550 }
551 else
552 {
553 tSDP_UUID sdp_uuid;
554 sdp_uuid.len = 16;
555 memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
556 logu("service_uuid", service_uuid);
557 *sock_fd = rs->app_fd;
558 rs->app_fd = -1; //the fd ownership is transferred to app
559 status = BT_STATUS_SUCCESS;
560 rfc_slot_t* rs_doing_sdp = find_rfc_slot_requesting_sdp();
561 if(rs_doing_sdp == NULL)
562 {
Kévin PETIT22c6e502014-02-12 17:24:01 +0000563 BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)(intptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800564 rs->f.pending_sdp_request = FALSE;
565 rs->f.doing_sdp_request = TRUE;
566 }
567 else
568 {
569 rs->f.pending_sdp_request = TRUE;
570 rs->f.doing_sdp_request = FALSE;
571 }
572 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
573 }
574 }
575 unlock_slot(&slot_lock);
576 return status;
577}
578
579static int create_server_sdp_record(rfc_slot_t* rs)
580{
581 int scn = rs->scn;
582 if(rs->scn > 0)
583 {
584 if(BTM_TryAllocateSCN(rs->scn) == FALSE)
585 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700586 APPL_TRACE_ERROR("rfc channel:%d already in use", scn);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800587 return FALSE;
588 }
589 }
590 else if((rs->scn = BTM_AllocateSCN()) == 0)
591 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700592 APPL_TRACE_ERROR("run out of rfc channels");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800593 return FALSE;
594 }
595 if((rs->sdp_handle = add_rfc_sdp_rec(rs->service_name, rs->service_uuid, rs->scn)) <= 0)
596 {
597 return FALSE;
598 }
599 return TRUE;
600}
601const char * jv_evt[] = {
602 "BTA_JV_ENABLE_EVT",
603 "BTA_JV_SET_DISCOVER_EVT",
604 "BTA_JV_LOCAL_ADDR_EVT",
605 "BTA_JV_LOCAL_NAME_EVT",
606 "BTA_JV_REMOTE_NAME_EVT",
607 "BTA_JV_SET_ENCRYPTION_EVT",
608 "BTA_JV_GET_SCN_EVT",
609 "BTA_JV_GET_PSM_EVT",
610 "BTA_JV_DISCOVERY_COMP_EVT",
611 "BTA_JV_SERVICES_LEN_EVT",
612 "BTA_JV_SERVICE_SEL_EVT",
613 "BTA_JV_CREATE_RECORD_EVT",
614 "BTA_JV_UPDATE_RECORD_EVT",
615 "BTA_JV_ADD_ATTR_EVT",
616 "BTA_JV_DELETE_ATTR_EVT",
617 "BTA_JV_CANCEL_DISCVRY_EVT",
618
619 "BTA_JV_L2CAP_OPEN_EVT",
620 "BTA_JV_L2CAP_CLOSE_EVT",
621 "BTA_JV_L2CAP_START_EVT",
622 "BTA_JV_L2CAP_CL_INIT_EVT",
623 "BTA_JV_L2CAP_DATA_IND_EVT",
624 "BTA_JV_L2CAP_CONG_EVT",
625 "BTA_JV_L2CAP_READ_EVT",
626 "BTA_JV_L2CAP_RECEIVE_EVT",
627 "BTA_JV_L2CAP_WRITE_EVT",
628
629 "BTA_JV_RFCOMM_OPEN_EVT",
630 "BTA_JV_RFCOMM_CLOSE_EVT",
631 "BTA_JV_RFCOMM_START_EVT",
632 "BTA_JV_RFCOMM_CL_INIT_EVT",
633 "BTA_JV_RFCOMM_DATA_IND_EVT",
634 "BTA_JV_RFCOMM_CONG_EVT",
635 "BTA_JV_RFCOMM_READ_EVT",
636 "BTA_JV_RFCOMM_WRITE_EVT",
637 "BTA_JV_RFCOMM_SRV_OPEN_EVT", // 33 /* open status of Server RFCOMM connection */
638 "BTA_JV_MAX_EVT"
639};
640static inline void free_rfc_slot_scn(rfc_slot_t* rs)
641{
642 if(rs->scn > 0)
643 {
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800644 if(rs->f.server && !rs->f.closing && rs->rfc_handle)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800645 {
Kévin PETIT22c6e502014-02-12 17:24:01 +0000646 BTA_JvRfcommStopServer(rs->rfc_handle, (void*)(uintptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800647 rs->rfc_handle = 0;
648 }
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800649 if(rs->f.server)
650 BTM_FreeSCN(rs->scn);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800651 rs->scn = 0;
652 }
653}
654static void cleanup_rfc_slot(rfc_slot_t* rs)
655{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700656 APPL_TRACE_DEBUG("cleanup slot:%d, fd:%d, scn:%d, sdp_handle:0x%x", rs->id, rs->fd, rs->scn, rs->sdp_handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800657 if(rs->fd != -1)
658 {
659 shutdown(rs->fd, 2);
660 close(rs->fd);
661 rs->fd = -1;
662 }
Hemant Gupta9cd26bf2013-09-10 12:01:18 +0530663
The Android Open Source Project5738f832012-12-12 16:00:35 -0800664 if(rs->app_fd != -1)
665 {
666 close(rs->app_fd);
667 rs->app_fd = -1;
668 }
669 if(rs->sdp_handle > 0)
670 {
671 del_rfc_sdp_rec(rs->sdp_handle);
672 rs->sdp_handle = 0;
673 }
674 if(rs->rfc_handle && !rs->f.closing && !rs->f.server)
675 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700676 APPL_TRACE_DEBUG("closing rfcomm connection, rfc_handle:0x%x", rs->rfc_handle);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000677 BTA_JvRfcommClose(rs->rfc_handle, (void*)(uintptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800678 rs->rfc_handle = 0;
679 }
680 free_rfc_slot_scn(rs);
Sharvil Nanavati847ea132014-04-25 22:38:55 -0700681 list_clear(rs->incoming_queue);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800682
683 rs->rfc_port_handle = 0;
684 //cleanup the flag
685 memset(&rs->f, 0, sizeof(rs->f));
Srinu Jella95447392015-02-13 16:09:22 +0530686 rs->in_use = FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800687}
688static inline BOOLEAN send_app_scn(rfc_slot_t* rs)
689{
690 if(sock_send_all(rs->fd, (const uint8_t*)&rs->scn, sizeof(rs->scn)) == sizeof(rs->scn))
691 {
692 return TRUE;
693 }
694
695 return FALSE;
696}
697static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd)
698{
699/*
700 typedef struct {
701 short size;
702 bt_bdaddr_t bd_addr;
703 int channel;
704 int status;
705} __attribute__((packed)) sock_connect_signal_t;
706*/
707 sock_connect_signal_t cs;
708 cs.size = sizeof(cs);
709 cs.bd_addr = *addr;
710 cs.channel = channel;
711 cs.status = status;
712 if(send_fd != -1)
713 {
714 if(sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs))
715 return TRUE;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700716 else APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800717 }
718 else if(sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs))
719 {
720 return TRUE;
721 }
722 return FALSE;
723}
724static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id)
725{
726 lock_slot(&slot_lock);
727 rfc_slot_t* rs = find_rfc_slot_by_id(id);
728 if(rs)
729 {
730 if (p_init->status != BTA_JV_SUCCESS)
731 cleanup_rfc_slot(rs);
732 else
733 {
734 rs->rfc_handle = p_init->handle;
735 }
736 }
737 unlock_slot(&slot_lock);
738}
739static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id)
740{
741 lock_slot(&slot_lock);
742 rfc_slot_t* rs = find_rfc_slot_by_id(id);
743 if(rs)
744 {
745 if (p_start->status != BTA_JV_SUCCESS)
746 cleanup_rfc_slot(rs);
747 else
748 {
749 rs->rfc_handle = p_start->handle;
750
751 if(!send_app_scn(rs))
752 {
753 //closed
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700754 APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800755 cleanup_rfc_slot(rs);
756 }
757 }
758 }
759 unlock_slot(&slot_lock);
760}
761static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id)
762{
763 uint32_t new_listen_slot_id = 0;
764 lock_slot(&slot_lock);
765 rfc_slot_t* srv_rs = find_rfc_slot_by_id(id);
766 if(srv_rs)
767 {
768 rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda,
769 p_open->handle, p_open->new_listen_handle);
770 if(accept_rs)
771 {
772 //start monitor the socket
773 btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
774 btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700775 APPL_TRACE_DEBUG("sending connect signal & app fd:%dto app server to accept() the connection",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800776 accept_rs->app_fd);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700777 APPL_TRACE_DEBUG("server fd:%d, scn:%d", srv_rs->fd, srv_rs->scn);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800778 send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd);
779 accept_rs->app_fd = -1; //the fd is closed after sent to app
780 new_listen_slot_id = srv_rs->id;
781 }
782 }
783 unlock_slot(&slot_lock);
784 return new_listen_slot_id;
785}
786static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id)
787{
788 lock_slot(&slot_lock);
789 rfc_slot_t* rs = find_rfc_slot_by_id(id);
790 if(rs && p_open->status == BTA_JV_SUCCESS)
791 {
792 rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
793 bd_copy(rs->addr.address, p_open->rem_bda, 0);
794 //notify app rfc is connected
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700795 APPL_TRACE_DEBUG("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800796 rs->id, rs->fd, rs->scn, rs->f.server);
797 if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1))
798 {
799 //start monitoring the socketpair to get call back when app writing data
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700800 APPL_TRACE_DEBUG("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800801 rs->id, rs->scn, rs->f.server);
802 rs->f.connected = TRUE;
803 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700804 else APPL_TRACE_ERROR("send_app_connect_signal failed");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800805 }
806 else if(rs)
807 cleanup_rfc_slot(rs);
808 unlock_slot(&slot_lock);
809}
810static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id)
811{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800812 UNUSED(p_close);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800813 lock_slot(&slot_lock);
814 rfc_slot_t* rs = find_rfc_slot_by_id(id);
815 if(rs)
816 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700817 APPL_TRACE_DEBUG("on_rfc_close, slot id:%d, fd:%d, rfc scn:%d, server:%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800818 rs->id, rs->fd, rs->scn, rs->f.server);
819 free_rfc_slot_scn(rs);
Ganesh Ganapathi Batta2f338f22013-03-24 03:11:59 +0100820 // rfc_handle already closed when receiving rfcomm close event from stack.
The Android Open Source Project5738f832012-12-12 16:00:35 -0800821 rs->f.connected = FALSE;
822 cleanup_rfc_slot(rs);
823 }
824 unlock_slot(&slot_lock);
825}
826static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE *p, uint32_t id)
827{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800828 UNUSED(p);
829
The Android Open Source Project5738f832012-12-12 16:00:35 -0800830 lock_slot(&slot_lock);
831 rfc_slot_t* rs = find_rfc_slot_by_id(id);
832 if(rs && !rs->f.outgoing_congest)
833 {
834 //mointer the fd for any outgoing data
835 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
836 }
837 unlock_slot(&slot_lock);
838}
839static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id)
840{
841 lock_slot(&slot_lock);
842 rfc_slot_t* rs = find_rfc_slot_by_id(id);
843 if(rs)
844 {
845 rs->f.outgoing_congest = p->cong ? 1 : 0;
846 //mointer the fd for any outgoing data
847 if(!rs->f.outgoing_congest)
848 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
849 }
850 unlock_slot(&slot_lock);
851}
852
853static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
854{
855 int rc;
856 void* new_user_data = NULL;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700857 APPL_TRACE_DEBUG("event=%s", jv_evt[event]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800858
859 switch (event)
860 {
861 case BTA_JV_RFCOMM_START_EVT:
Kévin PETIT22c6e502014-02-12 17:24:01 +0000862 on_srv_rfc_listen_started(&p_data->rfc_start, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800863 break;
864
865 case BTA_JV_RFCOMM_CL_INIT_EVT:
Kévin PETIT22c6e502014-02-12 17:24:01 +0000866 on_cl_rfc_init(&p_data->rfc_cl_init, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800867 break;
868
869 case BTA_JV_RFCOMM_OPEN_EVT:
Ganesh Ganapathi Batta2f338f22013-03-24 03:11:59 +0100870 BTA_JvSetPmProfile(p_data->rfc_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000871 on_cli_rfc_connect(&p_data->rfc_open, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800872 break;
873 case BTA_JV_RFCOMM_SRV_OPEN_EVT:
Ganesh Ganapathi Batta2f338f22013-03-24 03:11:59 +0100874 BTA_JvSetPmProfile(p_data->rfc_srv_open.handle,BTA_JV_PM_ALL,BTA_JV_CONN_OPEN);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000875 new_user_data = (void*)(intptr_t)on_srv_rfc_connect(&p_data->rfc_srv_open, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800876 break;
877
878 case BTA_JV_RFCOMM_CLOSE_EVT:
Matthew Xieafa6e1a2014-06-28 11:35:29 -0700879 APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: user_data:%d", (uintptr_t)user_data);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000880 on_rfc_close(&p_data->rfc_close, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800881 break;
882
883 case BTA_JV_RFCOMM_READ_EVT:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700884 APPL_TRACE_DEBUG("BTA_JV_RFCOMM_READ_EVT not used");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800885 break;
886
887 case BTA_JV_RFCOMM_WRITE_EVT:
Kévin PETIT22c6e502014-02-12 17:24:01 +0000888 on_rfc_write_done(&p_data->rfc_write, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800889 break;
890
891 case BTA_JV_RFCOMM_DATA_IND_EVT:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700892 APPL_TRACE_DEBUG("BTA_JV_RFCOMM_DATA_IND_EVT not used");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800893 break;
894
895 case BTA_JV_RFCOMM_CONG_EVT:
896 //on_rfc_cong(&p_data->rfc_cong);
Kévin PETIT22c6e502014-02-12 17:24:01 +0000897 on_rfc_outgoing_congest(&p_data->rfc_cong, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800898 break;
899 default:
Matthew Xieafa6e1a2014-06-28 11:35:29 -0700900 APPL_TRACE_ERROR("unhandled event %d, slot id:%d", event, (uintptr_t)user_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800901 break;
902 }
903 return new_user_data;
904}
905
906static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
907{
Kévin PETIT22c6e502014-02-12 17:24:01 +0000908 uint32_t id = (uintptr_t)user_data;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700909 APPL_TRACE_DEBUG("jv_dm_cback: event:%d, slot id:%d", event, id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800910 switch(event)
911 {
912 case BTA_JV_CREATE_RECORD_EVT:
913 {
914 lock_slot(&slot_lock);
915 rfc_slot_t* rs = find_rfc_slot_by_id(id);
916 if(rs && create_server_sdp_record(rs))
917 {
918 //now start the rfcomm server after sdp & channel # assigned
919 BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback,
Kévin PETIT22c6e502014-02-12 17:24:01 +0000920 (void*)(uintptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800921 }
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800922 else if(rs)
923 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700924 APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p", rs);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800925 cleanup_rfc_slot(rs);
926 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800927 unlock_slot(&slot_lock);
928 break;
929 }
930 case BTA_JV_DISCOVERY_COMP_EVT:
931 {
932 rfc_slot_t* rs = NULL;
933 lock_slot(&slot_lock);
934 if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn)
935 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700936 APPL_TRACE_DEBUG("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, status:%d, scn:%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800937 id, p_data->disc_comp.status, p_data->disc_comp.scn);
938
939 rs = find_rfc_slot_by_id(id);
940 if(rs && rs->f.doing_sdp_request)
941 {
942 if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address,
Kévin PETIT22c6e502014-02-12 17:24:01 +0000943 rfcomm_cback, (void*)(uintptr_t)rs->id) == BTA_JV_SUCCESS)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800944 {
945 rs->scn = p_data->disc_comp.scn;
946 rs->f.doing_sdp_request = FALSE;
947 if(!send_app_scn(rs))
948 cleanup_rfc_slot(rs);
949 }
950 else cleanup_rfc_slot(rs);
951 }
952 else if(rs)
953 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700954 APPL_TRACE_ERROR("DISCOVERY_COMP_EVT no pending sdp request, slot id:%d, \
The Android Open Source Project5738f832012-12-12 16:00:35 -0800955 flag sdp pending:%d, flag sdp doing:%d",
956 id, rs->f.pending_sdp_request, rs->f.doing_sdp_request);
957 }
958 }
959 else
960 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700961 APPL_TRACE_ERROR("DISCOVERY_COMP_EVT slot id:%d, failed to find channle, \
The Android Open Source Project5738f832012-12-12 16:00:35 -0800962 status:%d, scn:%d", id, p_data->disc_comp.status,
963 p_data->disc_comp.scn);
964 rs = find_rfc_slot_by_id(id);
965 if(rs)
966 cleanup_rfc_slot(rs);
967 }
968 rs = find_rfc_slot_by_pending_sdp();
969 if(rs)
970 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700971 APPL_TRACE_DEBUG("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800972 tSDP_UUID sdp_uuid;
973 sdp_uuid.len = 16;
974 memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128));
Kévin PETIT22c6e502014-02-12 17:24:01 +0000975 BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)(uintptr_t)rs->id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800976 rs->f.pending_sdp_request = FALSE;
977 rs->f.doing_sdp_request = TRUE;
978 }
979 unlock_slot(&slot_lock);
980 break;
981 }
982 default:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700983 APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800984 break;
985 }
986
987}
988#define SENT_ALL 2
989#define SENT_PARTIAL 1
990#define SENT_NONE 0
991#define SENT_FAILED (-1)
992static int send_data_to_app(int fd, BT_HDR *p_buf)
993{
994 if(p_buf->len == 0)
995 return SENT_ALL;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700996 int sent = TEMP_FAILURE_RETRY(send(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len, MSG_DONTWAIT));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800997 if(sent == p_buf->len)
998 return SENT_ALL;
999
1000 if(sent > 0 && sent < p_buf->len)
1001 {
1002 //sent partial
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001003 APPL_TRACE_ERROR("send partial, sent:%d, p_buf->len:%d", sent, p_buf->len);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001004 p_buf->offset += sent;
1005 p_buf->len -= sent;
1006 return SENT_PARTIAL;
1007
1008 }
1009 if(sent < 0 &&
1010 (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
1011 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001012 APPL_TRACE_ERROR("send none, EAGAIN or EWOULDBLOCK, errno:%d", errno);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001013 return SENT_NONE;
1014 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001015 APPL_TRACE_ERROR("unknown send() error, sent:%d, p_buf->len:%d, errno:%d", sent, p_buf->len, errno);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001016 return SENT_FAILED;
1017}
1018static BOOLEAN flush_incoming_que_on_wr_signal(rfc_slot_t* rs)
1019{
Sharvil Nanavati847ea132014-04-25 22:38:55 -07001020 while(!list_is_empty(rs->incoming_queue))
The Android Open Source Project5738f832012-12-12 16:00:35 -08001021 {
Sharvil Nanavati847ea132014-04-25 22:38:55 -07001022 BT_HDR *p_buf = list_front(rs->incoming_queue);
Sai Aitharajub0064492014-11-12 18:15:28 +05301023 if (p_buf)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001024 {
Sai Aitharajub0064492014-11-12 18:15:28 +05301025 int sent = send_data_to_app(rs->fd, p_buf);
1026 switch(sent)
1027 {
1028 case SENT_NONE:
1029 case SENT_PARTIAL:
1030 //monitor the fd to get callback when app is ready to receive data
1031 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
1032 return TRUE;
1033 case SENT_ALL:
1034 list_remove(rs->incoming_queue, p_buf);
1035 break;
1036 case SENT_FAILED:
1037 list_remove(rs->incoming_queue, p_buf);
1038 return FALSE;
1039 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001040 }
1041 }
1042
1043 //app is ready to receive data, tell stack to start the data flow
1044 //fix me: need a jv flow control api to serialize the call in stack
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001045 APPL_TRACE_DEBUG("enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d",
zzy181adbe2013-08-09 17:52:52 -07001046 rs->rfc_handle, rs->rfc_port_handle, rs->id);
1047 extern int PORT_FlowControl_MaxCredit(UINT16 handle, BOOLEAN enable);
1048 PORT_FlowControl_MaxCredit(rs->rfc_port_handle, TRUE);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001049 return TRUE;
1050}
1051void btsock_rfc_signaled(int fd, int flags, uint32_t user_id)
1052{
1053 lock_slot(&slot_lock);
1054 rfc_slot_t* rs = find_rfc_slot_by_id(user_id);
1055 if(rs)
1056 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001057 APPL_TRACE_DEBUG("rfc slot id:%d, fd:%d, flags:%x", rs->id, fd, flags);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001058 BOOLEAN need_close = FALSE;
1059 if(flags & SOCK_THREAD_FD_RD)
1060 {
1061 //data available from app, tell stack we have outgoing data
1062 if(!rs->f.server)
1063 {
1064 if(rs->f.connected)
Matthew Xie9ac641d2013-01-15 15:54:03 -08001065 {
1066 int size = 0;
1067 //make sure there's data pending in case the peer closed the socket
1068 if(!(flags & SOCK_THREAD_FD_EXCEPTION) ||
Sharvil Nanavati405b5c92016-06-17 14:15:46 -07001069 (TEMP_FAILURE_RETRY(ioctl(rs->fd, FIONREAD, &size)) == 0 && size))
git-zhenye.broadcom.com359895e2014-06-12 16:52:46 -07001070 {
1071 int rfc_handle = rs->rfc_handle;
1072 UINT32 rs_id = rs->id;
1073 //unlock before BTA_JvRfcommWrite to avoid deadlock on concurrnet multi rfcomm connectoins
1074 unlock_slot(&slot_lock);
1075 BTA_JvRfcommWrite(rfc_handle, rs_id);
1076 return;
1077 }
Matthew Xie9ac641d2013-01-15 15:54:03 -08001078 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001079 else
1080 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001081 APPL_TRACE_ERROR("SOCK_THREAD_FD_RD signaled when rfc is not connected, \
The Android Open Source Project5738f832012-12-12 16:00:35 -08001082 slot id:%d, channel:%d", rs->id, rs->scn);
1083 need_close = TRUE;
1084 }
1085 }
1086 }
1087 if(flags & SOCK_THREAD_FD_WR)
1088 {
1089 //app is ready to receive more data, tell stack to enable the data flow
1090 if(!rs->f.connected || !flush_incoming_que_on_wr_signal(rs))
1091 {
1092 need_close = TRUE;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001093 APPL_TRACE_ERROR("SOCK_THREAD_FD_WR signaled when rfc is not connected \
The Android Open Source Project5738f832012-12-12 16:00:35 -08001094 or app closed fd, slot id:%d, channel:%d", rs->id, rs->scn);
1095 }
1096
1097 }
1098 if(need_close || (flags & SOCK_THREAD_FD_EXCEPTION))
1099 {
Matthew Xie9ac641d2013-01-15 15:54:03 -08001100 int size = 0;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -07001101 if(need_close || TEMP_FAILURE_RETRY(ioctl(rs->fd, FIONREAD, &size)) != 0 || size == 0 )
Matthew Xie9ac641d2013-01-15 15:54:03 -08001102 {
1103 //cleanup when no data pending
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001104 APPL_TRACE_DEBUG("SOCK_THREAD_FD_EXCEPTION, cleanup, flags:%x, need_close:%d, pending size:%d",
Matthew Xie9ac641d2013-01-15 15:54:03 -08001105 flags, need_close, size);
1106 cleanup_rfc_slot(rs);
1107 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001108 else
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001109 APPL_TRACE_DEBUG("SOCK_THREAD_FD_EXCEPTION, cleanup pending, flags:%x, need_close:%d, pending size:%d",
Matthew Xie9ac641d2013-01-15 15:54:03 -08001110 flags, need_close, size);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001111 }
1112 }
1113 unlock_slot(&slot_lock);
1114}
Ganesh Ganapathi Batta2f338f22013-03-24 03:11:59 +01001115
The Android Open Source Project5738f832012-12-12 16:00:35 -08001116int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
1117{
Kévin PETIT22c6e502014-02-12 17:24:01 +00001118 uint32_t id = (uintptr_t)user_data;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001119 int ret = 0;
1120 lock_slot(&slot_lock);
1121 rfc_slot_t* rs = find_rfc_slot_by_id(id);
1122 if(rs)
1123 {
Sharvil Nanavati847ea132014-04-25 22:38:55 -07001124 if(!list_is_empty(rs->incoming_queue))
1125 list_append(rs->incoming_queue, p_buf);
zzy031d2392013-10-08 16:54:08 -07001126 else
The Android Open Source Project5738f832012-12-12 16:00:35 -08001127 {
zzy031d2392013-10-08 16:54:08 -07001128 int sent = send_data_to_app(rs->fd, p_buf);
1129 switch(sent)
1130 {
1131 case SENT_NONE:
1132 case SENT_PARTIAL:
1133 //add it to the end of the queue
Sharvil Nanavati847ea132014-04-25 22:38:55 -07001134 list_append(rs->incoming_queue, p_buf);
zzy031d2392013-10-08 16:54:08 -07001135 //monitor the fd to get callback when app is ready to receive data
1136 btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
1137 break;
1138 case SENT_ALL:
1139 GKI_freebuf(p_buf);
1140 ret = 1;//enable the data flow
1141 break;
1142 case SENT_FAILED:
1143 GKI_freebuf(p_buf);
1144 cleanup_rfc_slot(rs);
1145 break;
1146 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001147 }
1148 }
1149 unlock_slot(&slot_lock);
1150 return ret;//return 0 to disable data flow
1151}
1152int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
1153{
Kévin PETIT22c6e502014-02-12 17:24:01 +00001154 uint32_t id = (uintptr_t)user_data;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001155 int ret = FALSE;
1156 *size = 0;
1157 lock_slot(&slot_lock);
1158 rfc_slot_t* rs = find_rfc_slot_by_id(id);
1159 if(rs)
1160 {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -07001161 if(TEMP_FAILURE_RETRY(ioctl(rs->fd, FIONREAD, size)) == 0)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001162 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001163 APPL_TRACE_DEBUG("ioctl read avaiable size:%d, fd:%d", *size, rs->fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001164 ret = TRUE;
1165 }
1166 else
1167 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001168 APPL_TRACE_ERROR("ioctl FIONREAD error, errno:%d, fd:%d", errno, rs->fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001169 cleanup_rfc_slot(rs);
1170 }
1171 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001172 else APPL_TRACE_ERROR("bta_co_rfc_data_outgoing_size, invalid slot id:%d", id);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001173 unlock_slot(&slot_lock);
1174 return ret;
1175}
1176int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size)
1177{
Kévin PETIT22c6e502014-02-12 17:24:01 +00001178 uint32_t id = (uintptr_t)user_data;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001179 int ret = FALSE;
1180 lock_slot(&slot_lock);
1181 rfc_slot_t* rs = find_rfc_slot_by_id(id);
1182 if(rs)
1183 {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -07001184 int received = TEMP_FAILURE_RETRY(recv(rs->fd, buf, size, 0));
The Android Open Source Project5738f832012-12-12 16:00:35 -08001185 if(received == size)
1186 ret = TRUE;
1187 else
1188 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001189 APPL_TRACE_ERROR("recv error, errno:%d, fd:%d, size:%d, received:%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -08001190 errno, rs->fd, size, received);
1191 cleanup_rfc_slot(rs);
1192 }
1193 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -07001194 else APPL_TRACE_ERROR("bta_co_rfc_data_outgoing, invalid slot id:%d", id);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001195 unlock_slot(&slot_lock);
1196 return ret;
1197}
The Android Open Source Project5738f832012-12-12 16:00:35 -08001198