The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 1 | /****************************************************************************** |
| 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 Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 26 | #include <assert.h> |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 27 | #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" |
| 42 | #include "btif_sock_sdp.h" |
| 43 | #include "btif_sock_util.h" |
| 44 | |
| 45 | #include "bt_target.h" |
| 46 | #include "gki.h" |
| 47 | #include "hcimsgs.h" |
| 48 | #include "sdp_api.h" |
| 49 | #include "btu.h" |
| 50 | #include "btm_api.h" |
| 51 | #include "btm_int.h" |
| 52 | #include "bta_jv_api.h" |
| 53 | #include "bta_jv_co.h" |
| 54 | #include "port_api.h" |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 55 | #include "list.h" |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 56 | |
| 57 | #include <cutils/log.h> |
| 58 | #include <hardware/bluetooth.h> |
| 59 | #define asrt(s) if(!(s)) APPL_TRACE_ERROR3("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) |
| 60 | |
| 61 | extern void uuid_to_string(bt_uuid_t *p_uuid, char *str); |
| 62 | static inline void logu(const char* title, const uint8_t * p_uuid) |
| 63 | { |
| 64 | char uuids[128]; |
| 65 | uuid_to_string((bt_uuid_t*)p_uuid, uuids); |
| 66 | ALOGD("%s: %s", title, uuids); |
| 67 | } |
| 68 | |
| 69 | |
| 70 | |
| 71 | #define MAX_RFC_CHANNEL 30 |
| 72 | #define MAX_RFC_SESSION BTA_JV_MAX_RFC_SR_SESSION //3 by default |
| 73 | typedef struct { |
| 74 | int outgoing_congest : 1; |
| 75 | int pending_sdp_request : 1; |
| 76 | int doing_sdp_request : 1; |
| 77 | int server : 1; |
| 78 | int connected : 1; |
| 79 | int closing : 1; |
| 80 | } flags_t; |
| 81 | |
| 82 | typedef struct { |
| 83 | flags_t f; |
| 84 | uint32_t id; |
| 85 | int security; |
| 86 | int scn; |
| 87 | bt_bdaddr_t addr; |
| 88 | uint8_t service_uuid[16]; |
| 89 | char service_name[256]; |
| 90 | int fd, app_fd; |
| 91 | int mtu; |
| 92 | uint8_t* packet; |
| 93 | int sdp_handle; |
| 94 | int rfc_handle; |
| 95 | int rfc_port_handle; |
| 96 | int role; |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 97 | list_t *incoming_queue; |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 98 | } rfc_slot_t; |
| 99 | |
| 100 | static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL]; |
| 101 | static uint32_t rfc_slot_id; |
| 102 | static volatile int pth = -1; //poll thread handle |
| 103 | static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data); |
| 104 | static void cleanup_rfc_slot(rfc_slot_t* rs); |
| 105 | static inline void close_rfc_connection(int rfc_handle, int server); |
| 106 | static bt_status_t dm_get_remote_service_record(bt_bdaddr_t *remote_addr, |
| 107 | bt_uuid_t *uuid); |
| 108 | static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data); |
| 109 | static inline BOOLEAN send_app_scn(rfc_slot_t* rs); |
| 110 | static pthread_mutex_t slot_lock; |
| 111 | #define is_init_done() (pth != -1) |
| 112 | static inline void clear_slot_flag(flags_t* f) |
| 113 | { |
| 114 | memset(f, 0, sizeof(*f)); |
| 115 | } |
| 116 | |
| 117 | static inline void bd_copy(UINT8* dest, UINT8* src, BOOLEAN swap) |
| 118 | { |
| 119 | if (swap) |
| 120 | { |
| 121 | int i; |
| 122 | for (i =0; i < 6 ;i++) |
| 123 | dest[i]= src[5-i]; |
| 124 | } |
| 125 | else memcpy(dest, src, 6); |
| 126 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 127 | static void init_rfc_slots() |
| 128 | { |
| 129 | int i; |
| 130 | memset(rfc_slots, 0, sizeof(rfc_slot_t)*MAX_RFC_CHANNEL); |
| 131 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 132 | { |
| 133 | rfc_slots[i].scn = -1; |
| 134 | rfc_slots[i].sdp_handle = 0; |
| 135 | rfc_slots[i].fd = rfc_slots[i].app_fd = -1; |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 136 | rfc_slots[i].incoming_queue = list_new(GKI_freebuf); |
| 137 | assert(rfc_slots[i].incoming_queue != NULL); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 138 | } |
| 139 | BTA_JvEnable(jv_dm_cback); |
| 140 | init_slot_lock(&slot_lock); |
| 141 | } |
| 142 | bt_status_t btsock_rfc_init(int poll_thread_handle) |
| 143 | { |
| 144 | pth = poll_thread_handle; |
| 145 | init_rfc_slots(); |
| 146 | return BT_STATUS_SUCCESS; |
| 147 | } |
| 148 | void btsock_rfc_cleanup() |
| 149 | { |
| 150 | int curr_pth = pth; |
| 151 | pth = -1; |
| 152 | btsock_thread_exit(curr_pth); |
| 153 | lock_slot(&slot_lock); |
| 154 | int i; |
| 155 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 156 | { |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 157 | if(rfc_slots[i].id) { |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 158 | cleanup_rfc_slot(&rfc_slots[i]); |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 159 | list_free(rfc_slots[i].incoming_queue); |
| 160 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 161 | } |
| 162 | unlock_slot(&slot_lock); |
| 163 | } |
| 164 | static inline rfc_slot_t* find_free_slot() |
| 165 | { |
| 166 | int i; |
| 167 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 168 | { |
| 169 | if(rfc_slots[i].fd == -1) |
| 170 | { |
| 171 | return &rfc_slots[i]; |
| 172 | } |
| 173 | } |
| 174 | return NULL; |
| 175 | } |
| 176 | static inline rfc_slot_t* find_rfc_slot_by_id(uint32_t id) |
| 177 | { |
| 178 | int i; |
| 179 | if(id) |
| 180 | { |
| 181 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 182 | { |
| 183 | if(rfc_slots[i].id == id) |
| 184 | { |
| 185 | return &rfc_slots[i]; |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | APPL_TRACE_WARNING1("invalid rfc slot id: %d", id); |
| 190 | return NULL; |
| 191 | } |
| 192 | static inline rfc_slot_t* find_rfc_slot_by_pending_sdp() |
| 193 | { |
| 194 | uint32_t min_id = (uint32_t)-1; |
| 195 | int slot = -1; |
| 196 | int i; |
| 197 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 198 | { |
| 199 | if(rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request) |
| 200 | { |
| 201 | if(rfc_slots[i].id < min_id) |
| 202 | { |
| 203 | min_id = rfc_slots[i].id; |
| 204 | slot = i; |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | if(0<= slot && slot < MAX_RFC_CHANNEL) |
| 209 | return &rfc_slots[slot]; |
| 210 | return NULL; |
| 211 | } |
| 212 | static inline rfc_slot_t* find_rfc_slot_requesting_sdp() |
| 213 | { |
| 214 | int i; |
| 215 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 216 | { |
| 217 | if(rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request) |
| 218 | return &rfc_slots[i]; |
| 219 | } |
| 220 | APPL_TRACE_DEBUG0("can not find any slot is requesting sdp"); |
| 221 | return NULL; |
| 222 | } |
| 223 | |
| 224 | static inline rfc_slot_t* find_rfc_slot_by_fd(int fd) |
| 225 | { |
| 226 | int i; |
| 227 | if(fd >= 0) |
| 228 | { |
| 229 | for(i = 0; i < MAX_RFC_CHANNEL; i++) |
| 230 | { |
| 231 | if(rfc_slots[i].fd == fd) |
| 232 | { |
| 233 | if(rfc_slots[i].id) |
| 234 | return &rfc_slots[i]; |
| 235 | else |
| 236 | { |
| 237 | APPL_TRACE_ERROR0("invalid rfc slot id, cannot be 0"); |
| 238 | break; |
| 239 | } |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | return NULL; |
| 244 | } |
| 245 | static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t *addr, const char* name, const uint8_t* uuid, int channel, int flags, BOOLEAN server) |
| 246 | { |
| 247 | int security = 0; |
| 248 | if(flags & BTSOCK_FLAG_ENCRYPT) |
| 249 | security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT; |
| 250 | if(flags & BTSOCK_FLAG_AUTH) |
| 251 | security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE; |
| 252 | |
| 253 | rfc_slot_t* rs = find_free_slot(); |
| 254 | if(rs) |
| 255 | { |
| 256 | int fds[2] = {-1, -1}; |
| 257 | if(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) |
| 258 | { |
| 259 | APPL_TRACE_ERROR1("socketpair failed, errno:%d", errno); |
| 260 | return NULL; |
| 261 | } |
| 262 | rs->fd = fds[0]; |
| 263 | rs->app_fd = fds[1]; |
| 264 | rs->security = security; |
| 265 | rs->scn = channel; |
| 266 | if(uuid) |
| 267 | memcpy(rs->service_uuid, uuid, sizeof(rs->service_uuid)); |
| 268 | else memset(rs->service_uuid, 0, sizeof(rs->service_uuid)); |
| 269 | if(name && *name) |
| 270 | strncpy(rs->service_name, name, sizeof(rs->service_name) -1); |
| 271 | if(addr) |
| 272 | rs->addr = *addr; |
| 273 | ++rfc_slot_id; |
| 274 | if(rfc_slot_id == 0) |
| 275 | rfc_slot_id = 1; //skip 0 when wrapped |
| 276 | rs->id = rfc_slot_id; |
| 277 | rs->f.server = server; |
| 278 | } |
| 279 | return rs; |
| 280 | } |
| 281 | // rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, p_open->rem_bda,p_opne->handle, p_open->new_listen_handle); |
| 282 | static inline rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const bt_bdaddr_t* addr, |
| 283 | int open_handle, int new_listen_handle) |
| 284 | { |
| 285 | rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, FALSE); |
| 286 | clear_slot_flag(&accept_rs->f); |
| 287 | accept_rs->f.server = FALSE; |
| 288 | accept_rs->f.connected = TRUE; |
| 289 | accept_rs->security = srv_rs->security; |
| 290 | accept_rs->mtu = srv_rs->mtu; |
| 291 | accept_rs->role = srv_rs->role; |
| 292 | accept_rs->rfc_handle = open_handle; |
| 293 | accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle); |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 294 | //now update listen rfc_handle of server slot |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 295 | srv_rs->rfc_handle = new_listen_handle; |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 296 | srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle); |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 297 | BTIF_TRACE_DEBUG4("create_srv_accept__rfc_slot(open_handle: 0x%x, new_listen_handle:" |
| 298 | "0x%x) accept_rs->rfc_handle:0x%x, srv_rs_listen->rfc_handle:0x%x" |
| 299 | ,open_handle, new_listen_handle, accept_rs->rfc_port_handle, srv_rs->rfc_port_handle); |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 300 | asrt(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle); |
| 301 | //now swap the slot id |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 302 | uint32_t new_listen_id = accept_rs->id; |
| 303 | accept_rs->id = srv_rs->id; |
| 304 | srv_rs->id = new_listen_id; |
| 305 | return accept_rs; |
| 306 | } |
| 307 | bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel, |
| 308 | int* sock_fd, int flags) |
| 309 | { |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 310 | |
| 311 | APPL_TRACE_DEBUG1("btsock_rfc_listen, service_name:%s", service_name); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 312 | if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30))) |
| 313 | { |
| 314 | APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid); |
| 315 | return BT_STATUS_PARM_INVALID; |
| 316 | } |
| 317 | *sock_fd = -1; |
| 318 | if(!is_init_done()) |
| 319 | return BT_STATUS_NOT_READY; |
| 320 | if(is_uuid_empty(service_uuid)) |
| 321 | service_uuid = UUID_SPP; //use serial port profile to listen to specified channel |
| 322 | else |
| 323 | { |
| 324 | //Check the service_uuid. overwrite the channel # if reserved |
| 325 | int reserved_channel = get_reserved_rfc_channel(service_uuid); |
| 326 | if(reserved_channel > 0) |
| 327 | { |
| 328 | channel = reserved_channel; |
| 329 | } |
| 330 | } |
| 331 | int status = BT_STATUS_FAIL; |
| 332 | lock_slot(&slot_lock); |
| 333 | rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE); |
| 334 | if(rs) |
| 335 | { |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 336 | APPL_TRACE_DEBUG1("BTA_JvCreateRecordByUser:%s", service_name); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 337 | BTA_JvCreateRecordByUser((void *)rs->id); |
| 338 | *sock_fd = rs->app_fd; |
| 339 | rs->app_fd = -1; //the fd ownership is transferred to app |
| 340 | status = BT_STATUS_SUCCESS; |
| 341 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id); |
| 342 | } |
| 343 | unlock_slot(&slot_lock); |
| 344 | return status; |
| 345 | } |
| 346 | bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid, |
| 347 | int channel, int* sock_fd, int flags) |
| 348 | { |
| 349 | if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30))) |
| 350 | { |
| 351 | APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, |
| 352 | service_uuid); |
| 353 | return BT_STATUS_PARM_INVALID; |
| 354 | } |
| 355 | *sock_fd = -1; |
| 356 | if(!is_init_done()) |
| 357 | return BT_STATUS_NOT_READY; |
| 358 | int status = BT_STATUS_FAIL; |
| 359 | lock_slot(&slot_lock); |
| 360 | rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE); |
| 361 | if(rs) |
| 362 | { |
| 363 | if(is_uuid_empty(service_uuid)) |
| 364 | { |
| 365 | APPL_TRACE_DEBUG1("connecting to rfcomm channel:%d without service discovery", channel); |
| 366 | if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address, |
| 367 | rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS) |
| 368 | { |
| 369 | if(send_app_scn(rs)) |
| 370 | { |
| 371 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, |
| 372 | SOCK_THREAD_FD_RD, rs->id); |
| 373 | *sock_fd = rs->app_fd; |
| 374 | rs->app_fd = -1; //the fd ownership is transferred to app |
| 375 | status = BT_STATUS_SUCCESS; |
| 376 | } |
| 377 | else cleanup_rfc_slot(rs); |
| 378 | } |
| 379 | else cleanup_rfc_slot(rs); |
| 380 | } |
| 381 | else |
| 382 | { |
| 383 | tSDP_UUID sdp_uuid; |
| 384 | sdp_uuid.len = 16; |
| 385 | memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); |
| 386 | logu("service_uuid", service_uuid); |
| 387 | *sock_fd = rs->app_fd; |
| 388 | rs->app_fd = -1; //the fd ownership is transferred to app |
| 389 | status = BT_STATUS_SUCCESS; |
| 390 | rfc_slot_t* rs_doing_sdp = find_rfc_slot_requesting_sdp(); |
| 391 | if(rs_doing_sdp == NULL) |
| 392 | { |
| 393 | BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)rs->id); |
| 394 | rs->f.pending_sdp_request = FALSE; |
| 395 | rs->f.doing_sdp_request = TRUE; |
| 396 | } |
| 397 | else |
| 398 | { |
| 399 | rs->f.pending_sdp_request = TRUE; |
| 400 | rs->f.doing_sdp_request = FALSE; |
| 401 | } |
| 402 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); |
| 403 | } |
| 404 | } |
| 405 | unlock_slot(&slot_lock); |
| 406 | return status; |
| 407 | } |
| 408 | |
| 409 | static int create_server_sdp_record(rfc_slot_t* rs) |
| 410 | { |
| 411 | int scn = rs->scn; |
| 412 | if(rs->scn > 0) |
| 413 | { |
| 414 | if(BTM_TryAllocateSCN(rs->scn) == FALSE) |
| 415 | { |
| 416 | APPL_TRACE_ERROR1("rfc channel:%d already in use", scn); |
| 417 | return FALSE; |
| 418 | } |
| 419 | } |
| 420 | else if((rs->scn = BTM_AllocateSCN()) == 0) |
| 421 | { |
| 422 | APPL_TRACE_ERROR0("run out of rfc channels"); |
| 423 | return FALSE; |
| 424 | } |
| 425 | if((rs->sdp_handle = add_rfc_sdp_rec(rs->service_name, rs->service_uuid, rs->scn)) <= 0) |
| 426 | { |
| 427 | return FALSE; |
| 428 | } |
| 429 | return TRUE; |
| 430 | } |
| 431 | const char * jv_evt[] = { |
| 432 | "BTA_JV_ENABLE_EVT", |
| 433 | "BTA_JV_SET_DISCOVER_EVT", |
| 434 | "BTA_JV_LOCAL_ADDR_EVT", |
| 435 | "BTA_JV_LOCAL_NAME_EVT", |
| 436 | "BTA_JV_REMOTE_NAME_EVT", |
| 437 | "BTA_JV_SET_ENCRYPTION_EVT", |
| 438 | "BTA_JV_GET_SCN_EVT", |
| 439 | "BTA_JV_GET_PSM_EVT", |
| 440 | "BTA_JV_DISCOVERY_COMP_EVT", |
| 441 | "BTA_JV_SERVICES_LEN_EVT", |
| 442 | "BTA_JV_SERVICE_SEL_EVT", |
| 443 | "BTA_JV_CREATE_RECORD_EVT", |
| 444 | "BTA_JV_UPDATE_RECORD_EVT", |
| 445 | "BTA_JV_ADD_ATTR_EVT", |
| 446 | "BTA_JV_DELETE_ATTR_EVT", |
| 447 | "BTA_JV_CANCEL_DISCVRY_EVT", |
| 448 | |
| 449 | "BTA_JV_L2CAP_OPEN_EVT", |
| 450 | "BTA_JV_L2CAP_CLOSE_EVT", |
| 451 | "BTA_JV_L2CAP_START_EVT", |
| 452 | "BTA_JV_L2CAP_CL_INIT_EVT", |
| 453 | "BTA_JV_L2CAP_DATA_IND_EVT", |
| 454 | "BTA_JV_L2CAP_CONG_EVT", |
| 455 | "BTA_JV_L2CAP_READ_EVT", |
| 456 | "BTA_JV_L2CAP_RECEIVE_EVT", |
| 457 | "BTA_JV_L2CAP_WRITE_EVT", |
| 458 | |
| 459 | "BTA_JV_RFCOMM_OPEN_EVT", |
| 460 | "BTA_JV_RFCOMM_CLOSE_EVT", |
| 461 | "BTA_JV_RFCOMM_START_EVT", |
| 462 | "BTA_JV_RFCOMM_CL_INIT_EVT", |
| 463 | "BTA_JV_RFCOMM_DATA_IND_EVT", |
| 464 | "BTA_JV_RFCOMM_CONG_EVT", |
| 465 | "BTA_JV_RFCOMM_READ_EVT", |
| 466 | "BTA_JV_RFCOMM_WRITE_EVT", |
| 467 | "BTA_JV_RFCOMM_SRV_OPEN_EVT", // 33 /* open status of Server RFCOMM connection */ |
| 468 | "BTA_JV_MAX_EVT" |
| 469 | }; |
| 470 | static inline void free_rfc_slot_scn(rfc_slot_t* rs) |
| 471 | { |
| 472 | if(rs->scn > 0) |
| 473 | { |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 474 | if(rs->f.server && !rs->f.closing && rs->rfc_handle) |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 475 | { |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 476 | BTA_JvRfcommStopServer(rs->rfc_handle, (void*)rs->id); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 477 | rs->rfc_handle = 0; |
| 478 | } |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 479 | if(rs->f.server) |
| 480 | BTM_FreeSCN(rs->scn); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 481 | rs->scn = 0; |
| 482 | } |
| 483 | } |
| 484 | static void cleanup_rfc_slot(rfc_slot_t* rs) |
| 485 | { |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 486 | APPL_TRACE_DEBUG4("cleanup slot:%d, fd:%d, scn:%d, sdp_handle:0x%x", rs->id, rs->fd, rs->scn, rs->sdp_handle); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 487 | if(rs->fd != -1) |
| 488 | { |
| 489 | shutdown(rs->fd, 2); |
| 490 | close(rs->fd); |
| 491 | rs->fd = -1; |
| 492 | } |
| 493 | if(rs->app_fd != -1) |
| 494 | { |
| 495 | close(rs->app_fd); |
| 496 | rs->app_fd = -1; |
| 497 | } |
| 498 | if(rs->sdp_handle > 0) |
| 499 | { |
| 500 | del_rfc_sdp_rec(rs->sdp_handle); |
| 501 | rs->sdp_handle = 0; |
| 502 | } |
| 503 | if(rs->rfc_handle && !rs->f.closing && !rs->f.server) |
| 504 | { |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 505 | APPL_TRACE_DEBUG1("closing rfcomm connection, rfc_handle:0x%x", rs->rfc_handle); |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 506 | BTA_JvRfcommClose(rs->rfc_handle, (void*)rs->id); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 507 | rs->rfc_handle = 0; |
| 508 | } |
| 509 | free_rfc_slot_scn(rs); |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 510 | list_clear(rs->incoming_queue); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 511 | |
| 512 | rs->rfc_port_handle = 0; |
| 513 | //cleanup the flag |
| 514 | memset(&rs->f, 0, sizeof(rs->f)); |
| 515 | rs->id = 0; |
| 516 | } |
| 517 | static inline BOOLEAN send_app_scn(rfc_slot_t* rs) |
| 518 | { |
| 519 | if(sock_send_all(rs->fd, (const uint8_t*)&rs->scn, sizeof(rs->scn)) == sizeof(rs->scn)) |
| 520 | { |
| 521 | return TRUE; |
| 522 | } |
| 523 | |
| 524 | return FALSE; |
| 525 | } |
| 526 | static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd) |
| 527 | { |
| 528 | /* |
| 529 | typedef struct { |
| 530 | short size; |
| 531 | bt_bdaddr_t bd_addr; |
| 532 | int channel; |
| 533 | int status; |
| 534 | } __attribute__((packed)) sock_connect_signal_t; |
| 535 | */ |
| 536 | sock_connect_signal_t cs; |
| 537 | cs.size = sizeof(cs); |
| 538 | cs.bd_addr = *addr; |
| 539 | cs.channel = channel; |
| 540 | cs.status = status; |
| 541 | if(send_fd != -1) |
| 542 | { |
| 543 | if(sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs)) |
| 544 | return TRUE; |
| 545 | else APPL_TRACE_ERROR2("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd); |
| 546 | } |
| 547 | else if(sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) |
| 548 | { |
| 549 | return TRUE; |
| 550 | } |
| 551 | return FALSE; |
| 552 | } |
| 553 | static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id) |
| 554 | { |
| 555 | lock_slot(&slot_lock); |
| 556 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 557 | if(rs) |
| 558 | { |
| 559 | if (p_init->status != BTA_JV_SUCCESS) |
| 560 | cleanup_rfc_slot(rs); |
| 561 | else |
| 562 | { |
| 563 | rs->rfc_handle = p_init->handle; |
| 564 | } |
| 565 | } |
| 566 | unlock_slot(&slot_lock); |
| 567 | } |
| 568 | static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id) |
| 569 | { |
| 570 | lock_slot(&slot_lock); |
| 571 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 572 | if(rs) |
| 573 | { |
| 574 | if (p_start->status != BTA_JV_SUCCESS) |
| 575 | cleanup_rfc_slot(rs); |
| 576 | else |
| 577 | { |
| 578 | rs->rfc_handle = p_start->handle; |
| 579 | |
| 580 | if(!send_app_scn(rs)) |
| 581 | { |
| 582 | //closed |
| 583 | APPL_TRACE_DEBUG1("send_app_scn() failed, close rs->id:%d", rs->id); |
| 584 | cleanup_rfc_slot(rs); |
| 585 | } |
| 586 | } |
| 587 | } |
| 588 | unlock_slot(&slot_lock); |
| 589 | } |
| 590 | static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id) |
| 591 | { |
| 592 | uint32_t new_listen_slot_id = 0; |
| 593 | lock_slot(&slot_lock); |
| 594 | rfc_slot_t* srv_rs = find_rfc_slot_by_id(id); |
| 595 | if(srv_rs) |
| 596 | { |
| 597 | rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda, |
| 598 | p_open->handle, p_open->new_listen_handle); |
| 599 | if(accept_rs) |
| 600 | { |
| 601 | //start monitor the socket |
| 602 | btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id); |
| 603 | btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id); |
| 604 | APPL_TRACE_DEBUG1("sending connect signal & app fd:%dto app server to accept() the connection", |
| 605 | accept_rs->app_fd); |
| 606 | APPL_TRACE_DEBUG2("server fd:%d, scn:%d", srv_rs->fd, srv_rs->scn); |
| 607 | send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd); |
| 608 | accept_rs->app_fd = -1; //the fd is closed after sent to app |
| 609 | new_listen_slot_id = srv_rs->id; |
| 610 | } |
| 611 | } |
| 612 | unlock_slot(&slot_lock); |
| 613 | return new_listen_slot_id; |
| 614 | } |
| 615 | static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id) |
| 616 | { |
| 617 | lock_slot(&slot_lock); |
| 618 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 619 | if(rs && p_open->status == BTA_JV_SUCCESS) |
| 620 | { |
| 621 | rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle); |
| 622 | bd_copy(rs->addr.address, p_open->rem_bda, 0); |
| 623 | //notify app rfc is connected |
| 624 | APPL_TRACE_DEBUG4("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d", |
| 625 | rs->id, rs->fd, rs->scn, rs->f.server); |
| 626 | if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1)) |
| 627 | { |
| 628 | //start monitoring the socketpair to get call back when app writing data |
| 629 | APPL_TRACE_DEBUG3("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d", |
| 630 | rs->id, rs->scn, rs->f.server); |
| 631 | rs->f.connected = TRUE; |
| 632 | } |
| 633 | else APPL_TRACE_ERROR0("send_app_connect_signal failed"); |
| 634 | } |
| 635 | else if(rs) |
| 636 | cleanup_rfc_slot(rs); |
| 637 | unlock_slot(&slot_lock); |
| 638 | } |
| 639 | static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id) |
| 640 | { |
Mike J. Chen | 5cd8bff | 2014-01-31 18:16:59 -0800 | [diff] [blame] | 641 | UNUSED(p_close); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 642 | lock_slot(&slot_lock); |
| 643 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 644 | if(rs) |
| 645 | { |
| 646 | APPL_TRACE_DEBUG4("on_rfc_close, slot id:%d, fd:%d, rfc scn:%d, server:%d", |
| 647 | rs->id, rs->fd, rs->scn, rs->f.server); |
| 648 | free_rfc_slot_scn(rs); |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 649 | // rfc_handle already closed when receiving rfcomm close event from stack. |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 650 | rs->f.connected = FALSE; |
| 651 | cleanup_rfc_slot(rs); |
| 652 | } |
| 653 | unlock_slot(&slot_lock); |
| 654 | } |
| 655 | static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE *p, uint32_t id) |
| 656 | { |
Mike J. Chen | 5cd8bff | 2014-01-31 18:16:59 -0800 | [diff] [blame] | 657 | UNUSED(p); |
| 658 | |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 659 | lock_slot(&slot_lock); |
| 660 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 661 | if(rs && !rs->f.outgoing_congest) |
| 662 | { |
| 663 | //mointer the fd for any outgoing data |
| 664 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); |
| 665 | } |
| 666 | unlock_slot(&slot_lock); |
| 667 | } |
| 668 | static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id) |
| 669 | { |
| 670 | lock_slot(&slot_lock); |
| 671 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 672 | if(rs) |
| 673 | { |
| 674 | rs->f.outgoing_congest = p->cong ? 1 : 0; |
| 675 | //mointer the fd for any outgoing data |
| 676 | if(!rs->f.outgoing_congest) |
| 677 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); |
| 678 | } |
| 679 | unlock_slot(&slot_lock); |
| 680 | } |
| 681 | |
| 682 | static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) |
| 683 | { |
| 684 | int rc; |
| 685 | void* new_user_data = NULL; |
| 686 | APPL_TRACE_DEBUG1("event=%s", jv_evt[event]); |
| 687 | |
| 688 | switch (event) |
| 689 | { |
| 690 | case BTA_JV_RFCOMM_START_EVT: |
| 691 | on_srv_rfc_listen_started(&p_data->rfc_start, (uint32_t)user_data); |
| 692 | break; |
| 693 | |
| 694 | case BTA_JV_RFCOMM_CL_INIT_EVT: |
| 695 | on_cl_rfc_init(&p_data->rfc_cl_init, (uint32_t)user_data); |
| 696 | break; |
| 697 | |
| 698 | case BTA_JV_RFCOMM_OPEN_EVT: |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 699 | BTA_JvSetPmProfile(p_data->rfc_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 700 | on_cli_rfc_connect(&p_data->rfc_open, (uint32_t)user_data); |
| 701 | break; |
| 702 | case BTA_JV_RFCOMM_SRV_OPEN_EVT: |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 703 | BTA_JvSetPmProfile(p_data->rfc_srv_open.handle,BTA_JV_PM_ALL,BTA_JV_CONN_OPEN); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 704 | new_user_data = (void*)on_srv_rfc_connect(&p_data->rfc_srv_open, (uint32_t)user_data); |
| 705 | break; |
| 706 | |
| 707 | case BTA_JV_RFCOMM_CLOSE_EVT: |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 708 | APPL_TRACE_DEBUG1("BTA_JV_RFCOMM_CLOSE_EVT: user_data:%d", (uint32_t)user_data); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 709 | on_rfc_close(&p_data->rfc_close, (uint32_t)user_data); |
| 710 | break; |
| 711 | |
| 712 | case BTA_JV_RFCOMM_READ_EVT: |
| 713 | APPL_TRACE_DEBUG0("BTA_JV_RFCOMM_READ_EVT not used"); |
| 714 | break; |
| 715 | |
| 716 | case BTA_JV_RFCOMM_WRITE_EVT: |
| 717 | on_rfc_write_done(&p_data->rfc_write, (uint32_t)user_data); |
| 718 | break; |
| 719 | |
| 720 | case BTA_JV_RFCOMM_DATA_IND_EVT: |
| 721 | APPL_TRACE_DEBUG0("BTA_JV_RFCOMM_DATA_IND_EVT not used"); |
| 722 | break; |
| 723 | |
| 724 | case BTA_JV_RFCOMM_CONG_EVT: |
| 725 | //on_rfc_cong(&p_data->rfc_cong); |
| 726 | on_rfc_outgoing_congest(&p_data->rfc_cong, (uint32_t)user_data); |
| 727 | break; |
| 728 | default: |
| 729 | APPL_TRACE_ERROR2("unhandled event %d, slot id:%d", event, (uint32_t)user_data); |
| 730 | break; |
| 731 | } |
| 732 | return new_user_data; |
| 733 | } |
| 734 | |
| 735 | static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) |
| 736 | { |
| 737 | uint32_t id = (uint32_t)user_data; |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 738 | APPL_TRACE_DEBUG2("jv_dm_cback: event:%d, slot id:%d", event, id); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 739 | switch(event) |
| 740 | { |
| 741 | case BTA_JV_CREATE_RECORD_EVT: |
| 742 | { |
| 743 | lock_slot(&slot_lock); |
| 744 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 745 | if(rs && create_server_sdp_record(rs)) |
| 746 | { |
| 747 | //now start the rfcomm server after sdp & channel # assigned |
| 748 | BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback, |
| 749 | (void*)rs->id); |
| 750 | } |
The Android Open Source Project | 689d66b | 2012-12-12 17:18:15 -0800 | [diff] [blame] | 751 | else if(rs) |
| 752 | { |
| 753 | APPL_TRACE_ERROR1("jv_dm_cback: cannot start server, slot found:%p", rs); |
| 754 | cleanup_rfc_slot(rs); |
| 755 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 756 | unlock_slot(&slot_lock); |
| 757 | break; |
| 758 | } |
| 759 | case BTA_JV_DISCOVERY_COMP_EVT: |
| 760 | { |
| 761 | rfc_slot_t* rs = NULL; |
| 762 | lock_slot(&slot_lock); |
| 763 | if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) |
| 764 | { |
| 765 | APPL_TRACE_DEBUG3("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, status:%d, scn:%d", |
| 766 | id, p_data->disc_comp.status, p_data->disc_comp.scn); |
| 767 | |
| 768 | rs = find_rfc_slot_by_id(id); |
| 769 | if(rs && rs->f.doing_sdp_request) |
| 770 | { |
| 771 | if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address, |
| 772 | rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS) |
| 773 | { |
| 774 | rs->scn = p_data->disc_comp.scn; |
| 775 | rs->f.doing_sdp_request = FALSE; |
| 776 | if(!send_app_scn(rs)) |
| 777 | cleanup_rfc_slot(rs); |
| 778 | } |
| 779 | else cleanup_rfc_slot(rs); |
| 780 | } |
| 781 | else if(rs) |
| 782 | { |
| 783 | APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT no pending sdp request, slot id:%d, \ |
| 784 | flag sdp pending:%d, flag sdp doing:%d", |
| 785 | id, rs->f.pending_sdp_request, rs->f.doing_sdp_request); |
| 786 | } |
| 787 | } |
| 788 | else |
| 789 | { |
| 790 | APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT slot id:%d, failed to find channle, \ |
| 791 | status:%d, scn:%d", id, p_data->disc_comp.status, |
| 792 | p_data->disc_comp.scn); |
| 793 | rs = find_rfc_slot_by_id(id); |
| 794 | if(rs) |
| 795 | cleanup_rfc_slot(rs); |
| 796 | } |
| 797 | rs = find_rfc_slot_by_pending_sdp(); |
| 798 | if(rs) |
| 799 | { |
| 800 | APPL_TRACE_DEBUG0("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request"); |
| 801 | tSDP_UUID sdp_uuid; |
| 802 | sdp_uuid.len = 16; |
| 803 | memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128)); |
| 804 | BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)rs->id); |
| 805 | rs->f.pending_sdp_request = FALSE; |
| 806 | rs->f.doing_sdp_request = TRUE; |
| 807 | } |
| 808 | unlock_slot(&slot_lock); |
| 809 | break; |
| 810 | } |
| 811 | default: |
| 812 | APPL_TRACE_DEBUG2("unhandled event:%d, slot id:%d", event, id); |
| 813 | break; |
| 814 | } |
| 815 | |
| 816 | } |
| 817 | #define SENT_ALL 2 |
| 818 | #define SENT_PARTIAL 1 |
| 819 | #define SENT_NONE 0 |
| 820 | #define SENT_FAILED (-1) |
| 821 | static int send_data_to_app(int fd, BT_HDR *p_buf) |
| 822 | { |
| 823 | if(p_buf->len == 0) |
| 824 | return SENT_ALL; |
| 825 | int sent = send(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len, MSG_DONTWAIT); |
| 826 | if(sent == p_buf->len) |
| 827 | return SENT_ALL; |
| 828 | |
| 829 | if(sent > 0 && sent < p_buf->len) |
| 830 | { |
| 831 | //sent partial |
| 832 | APPL_TRACE_ERROR2("send partial, sent:%d, p_buf->len:%d", sent, p_buf->len); |
| 833 | p_buf->offset += sent; |
| 834 | p_buf->len -= sent; |
| 835 | return SENT_PARTIAL; |
| 836 | |
| 837 | } |
| 838 | if(sent < 0 && |
| 839 | (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) |
| 840 | { |
| 841 | APPL_TRACE_ERROR1("send none, EAGAIN or EWOULDBLOCK, errno:%d", errno); |
| 842 | return SENT_NONE; |
| 843 | } |
| 844 | APPL_TRACE_ERROR3("unknown send() error, sent:%d, p_buf->len:%d, errno:%d", sent, p_buf->len, errno); |
| 845 | return SENT_FAILED; |
| 846 | } |
| 847 | static BOOLEAN flush_incoming_que_on_wr_signal(rfc_slot_t* rs) |
| 848 | { |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 849 | while(!list_is_empty(rs->incoming_queue)) |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 850 | { |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 851 | BT_HDR *p_buf = list_front(rs->incoming_queue); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 852 | int sent = send_data_to_app(rs->fd, p_buf); |
| 853 | switch(sent) |
| 854 | { |
| 855 | case SENT_NONE: |
| 856 | case SENT_PARTIAL: |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 857 | //monitor the fd to get callback when app is ready to receive data |
| 858 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id); |
| 859 | return TRUE; |
| 860 | case SENT_ALL: |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 861 | case SENT_FAILED: |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 862 | list_remove(rs->incoming_queue, p_buf); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 863 | return FALSE; |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | //app is ready to receive data, tell stack to start the data flow |
| 868 | //fix me: need a jv flow control api to serialize the call in stack |
zzy | 181adbe | 2013-08-09 17:52:52 -0700 | [diff] [blame] | 869 | APPL_TRACE_DEBUG3("enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d", |
| 870 | rs->rfc_handle, rs->rfc_port_handle, rs->id); |
| 871 | extern int PORT_FlowControl_MaxCredit(UINT16 handle, BOOLEAN enable); |
| 872 | PORT_FlowControl_MaxCredit(rs->rfc_port_handle, TRUE); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 873 | return TRUE; |
| 874 | } |
| 875 | void btsock_rfc_signaled(int fd, int flags, uint32_t user_id) |
| 876 | { |
| 877 | lock_slot(&slot_lock); |
| 878 | rfc_slot_t* rs = find_rfc_slot_by_id(user_id); |
| 879 | if(rs) |
| 880 | { |
| 881 | APPL_TRACE_DEBUG3("rfc slot id:%d, fd:%d, flags:%x", rs->id, fd, flags); |
| 882 | BOOLEAN need_close = FALSE; |
| 883 | if(flags & SOCK_THREAD_FD_RD) |
| 884 | { |
| 885 | //data available from app, tell stack we have outgoing data |
| 886 | if(!rs->f.server) |
| 887 | { |
| 888 | if(rs->f.connected) |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 889 | { |
| 890 | int size = 0; |
| 891 | //make sure there's data pending in case the peer closed the socket |
| 892 | if(!(flags & SOCK_THREAD_FD_EXCEPTION) || |
| 893 | (ioctl(rs->fd, FIONREAD, &size) == 0 && size)) |
| 894 | BTA_JvRfcommWrite(rs->rfc_handle, (UINT32)rs->id); |
| 895 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 896 | else |
| 897 | { |
| 898 | APPL_TRACE_ERROR2("SOCK_THREAD_FD_RD signaled when rfc is not connected, \ |
| 899 | slot id:%d, channel:%d", rs->id, rs->scn); |
| 900 | need_close = TRUE; |
| 901 | } |
| 902 | } |
| 903 | } |
| 904 | if(flags & SOCK_THREAD_FD_WR) |
| 905 | { |
| 906 | //app is ready to receive more data, tell stack to enable the data flow |
| 907 | if(!rs->f.connected || !flush_incoming_que_on_wr_signal(rs)) |
| 908 | { |
| 909 | need_close = TRUE; |
| 910 | APPL_TRACE_ERROR2("SOCK_THREAD_FD_WR signaled when rfc is not connected \ |
| 911 | or app closed fd, slot id:%d, channel:%d", rs->id, rs->scn); |
| 912 | } |
| 913 | |
| 914 | } |
| 915 | if(need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) |
| 916 | { |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 917 | int size = 0; |
| 918 | if(need_close || ioctl(rs->fd, FIONREAD, &size) != 0 || size == 0 ) |
| 919 | { |
| 920 | //cleanup when no data pending |
| 921 | APPL_TRACE_DEBUG3("SOCK_THREAD_FD_EXCEPTION, cleanup, flags:%x, need_close:%d, pending size:%d", |
| 922 | flags, need_close, size); |
| 923 | cleanup_rfc_slot(rs); |
| 924 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 925 | else |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 926 | APPL_TRACE_DEBUG3("SOCK_THREAD_FD_EXCEPTION, cleanup pending, flags:%x, need_close:%d, pending size:%d", |
| 927 | flags, need_close, size); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 928 | } |
| 929 | } |
| 930 | unlock_slot(&slot_lock); |
| 931 | } |
Ganesh Ganapathi Batta | 2f338f2 | 2013-03-24 03:11:59 +0100 | [diff] [blame] | 932 | |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 933 | int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) |
| 934 | { |
| 935 | uint32_t id = (uint32_t)user_data; |
| 936 | int ret = 0; |
| 937 | lock_slot(&slot_lock); |
| 938 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 939 | if(rs) |
| 940 | { |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 941 | if(!list_is_empty(rs->incoming_queue)) |
| 942 | list_append(rs->incoming_queue, p_buf); |
zzy | 031d239 | 2013-10-08 16:54:08 -0700 | [diff] [blame] | 943 | else |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 944 | { |
zzy | 031d239 | 2013-10-08 16:54:08 -0700 | [diff] [blame] | 945 | int sent = send_data_to_app(rs->fd, p_buf); |
| 946 | switch(sent) |
| 947 | { |
| 948 | case SENT_NONE: |
| 949 | case SENT_PARTIAL: |
| 950 | //add it to the end of the queue |
Sharvil Nanavati | d9e5b34 | 2014-04-25 22:38:55 -0700 | [diff] [blame^] | 951 | list_append(rs->incoming_queue, p_buf); |
zzy | 031d239 | 2013-10-08 16:54:08 -0700 | [diff] [blame] | 952 | //monitor the fd to get callback when app is ready to receive data |
| 953 | btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id); |
| 954 | break; |
| 955 | case SENT_ALL: |
| 956 | GKI_freebuf(p_buf); |
| 957 | ret = 1;//enable the data flow |
| 958 | break; |
| 959 | case SENT_FAILED: |
| 960 | GKI_freebuf(p_buf); |
| 961 | cleanup_rfc_slot(rs); |
| 962 | break; |
| 963 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 964 | } |
| 965 | } |
| 966 | unlock_slot(&slot_lock); |
| 967 | return ret;//return 0 to disable data flow |
| 968 | } |
| 969 | int bta_co_rfc_data_outgoing_size(void *user_data, int *size) |
| 970 | { |
| 971 | uint32_t id = (uint32_t)user_data; |
| 972 | int ret = FALSE; |
| 973 | *size = 0; |
| 974 | lock_slot(&slot_lock); |
| 975 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 976 | if(rs) |
| 977 | { |
| 978 | if(ioctl(rs->fd, FIONREAD, size) == 0) |
| 979 | { |
| 980 | APPL_TRACE_DEBUG2("ioctl read avaiable size:%d, fd:%d", *size, rs->fd); |
| 981 | ret = TRUE; |
| 982 | } |
| 983 | else |
| 984 | { |
| 985 | APPL_TRACE_ERROR2("ioctl FIONREAD error, errno:%d, fd:%d", errno, rs->fd); |
| 986 | cleanup_rfc_slot(rs); |
| 987 | } |
| 988 | } |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 989 | else APPL_TRACE_ERROR1("bta_co_rfc_data_outgoing_size, invalid slot id:%d", id); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 990 | unlock_slot(&slot_lock); |
| 991 | return ret; |
| 992 | } |
| 993 | int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size) |
| 994 | { |
| 995 | uint32_t id = (uint32_t)user_data; |
| 996 | int ret = FALSE; |
| 997 | lock_slot(&slot_lock); |
| 998 | rfc_slot_t* rs = find_rfc_slot_by_id(id); |
| 999 | if(rs) |
| 1000 | { |
| 1001 | int received = recv(rs->fd, buf, size, 0); |
| 1002 | if(received == size) |
| 1003 | ret = TRUE; |
| 1004 | else |
| 1005 | { |
| 1006 | APPL_TRACE_ERROR4("recv error, errno:%d, fd:%d, size:%d, received:%d", |
| 1007 | errno, rs->fd, size, received); |
| 1008 | cleanup_rfc_slot(rs); |
| 1009 | } |
| 1010 | } |
Matthew Xie | 9ac641d | 2013-01-15 15:54:03 -0800 | [diff] [blame] | 1011 | else APPL_TRACE_ERROR1("bta_co_rfc_data_outgoing, invalid slot id:%d", id); |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 1012 | unlock_slot(&slot_lock); |
| 1013 | return ret; |
| 1014 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 1015 | |