blob: 44d6e9543e1527bfdb44ef16ceeec9b051103298 [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_pan.c
22 *
23 * Description: PAN Profile Bluetooth Interface
24 *
25 *
26 ***********************************************************************************/
27#include <hardware/bluetooth.h>
28#include <hardware/bt_pan.h>
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -070029#include <assert.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080030#include <signal.h>
31#include <ctype.h>
32#include <sys/select.h>
33#include <sys/poll.h>
34#include <sys/ioctl.h>
35#include <netinet/in.h>
36#include <netdb.h>
37#include <stdio.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <sys/socket.h>
41#include <sys/wait.h>
42#include <net/if.h>
43#include <linux/sockios.h>
44#include <sys/prctl.h>
45#include <linux/if.h>
46#include <linux/if_tun.h>
47#include <linux/if_ether.h>
48
49#define LOG_TAG "BTIF_PAN"
50#include "btif_common.h"
51#include "btif_util.h"
52#include "btm_api.h"
53#include "bd.h"
54
55#include "bta_api.h"
56#include "bta_pan_api.h"
57#include "btif_sock_thread.h"
58#include "btif_sock_util.h"
59#include "btif_pan_internal.h"
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -070060#include "gki.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080061
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -070062#define FORWARD_IGNORE 1
63#define FORWARD_SUCCESS 0
64#define FORWARD_FAILURE (-1)
65#define FORWARD_CONGEST (-2)
The Android Open Source Project5738f832012-12-12 16:00:35 -080066//#define PANU_DISABLED TRUE
67
68#if (PAN_NAP_DISABLED == TRUE) && (PANU_DISABLED == TRUE)
69#define BTPAN_LOCAL_ROLE BTPAN_ROLE_NONE
70#elif PAN_NAP_DISABLED == TRUE
71#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANU
72#elif PANU_DISABLED == TRUE
73#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANNAP
74#else
75#define BTPAN_LOCAL_ROLE (BTPAN_ROLE_PANU | BTPAN_ROLE_PANNAP)
76#endif
77
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -070078#define asrt(s) if(!(s)) BTIF_TRACE_ERROR("btif_pan: ## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
The Android Open Source Project5738f832012-12-12 16:00:35 -080079
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -070080#define MIN(x, y) (((x) < (y)) ? (x) : (y))
81
The Android Open Source Project5738f832012-12-12 16:00:35 -080082btpan_cb_t btpan_cb;
83
84BD_ADDR local_addr;
85static int jni_initialized, stack_initialized;
86static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks);
87static void btpan_jni_cleanup();
88static bt_status_t btpan_connect(const bt_bdaddr_t *bd_addr, int local_role, int remote_role);
89static bt_status_t btpan_disconnect(const bt_bdaddr_t *bd_addr);
90static bt_status_t btpan_enable(int local_role);
91static int btpan_get_local_role(void);
92
93static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id);
94static void btpan_cleanup_conn(btpan_conn_t* conn);
95static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN *p_data);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -070096static void btu_exec_tap_fd_read(void *p_param);
97
The Android Open Source Project5738f832012-12-12 16:00:35 -080098static btpan_interface_t pan_if = {
99 sizeof(pan_if),
100 btpan_jni_init,
101 btpan_enable,
102 btpan_get_local_role,
103 btpan_connect,
104 btpan_disconnect,
105 btpan_jni_cleanup
106};
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700107
The Android Open Source Project5738f832012-12-12 16:00:35 -0800108btpan_interface_t *btif_pan_get_interface()
109{
110 return &pan_if;
111}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700112
113/*******************************************************************************
114 **
115 ** Function btif_pan_init
116 **
117 ** Description initializes the pan interface
118 **
119 ** Returns bt_status_t
120 **
121 *******************************************************************************/
The Android Open Source Project5738f832012-12-12 16:00:35 -0800122void btif_pan_init()
123{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700124 BTIF_TRACE_DEBUG("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized, btpan_cb.enabled);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800125 stack_initialized = TRUE;
126 if (jni_initialized && !btpan_cb.enabled)
127 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700128 BTIF_TRACE_DEBUG("Enabling PAN....");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800129 memset(&btpan_cb, 0, sizeof(btpan_cb));
130 btpan_cb.tap_fd = -1;
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700131 btpan_cb.flow = 1;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800132 int i;
133 for(i = 0; i < MAX_PAN_CONNS; i++)
134 btpan_cleanup_conn(&btpan_cb.conns[i]);
135 BTA_PanEnable(bta_pan_callback);
136 btpan_cb.enabled = 1;
137 btpan_enable(BTPAN_LOCAL_ROLE);
138 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800139}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700140
The Android Open Source Project5738f832012-12-12 16:00:35 -0800141static void pan_disable()
142{
143 if(btpan_cb.enabled)
144 {
145 btpan_cb.enabled = 0;
146 BTA_PanDisable();
147 if(btpan_cb.tap_fd != -1)
148 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800149 btpan_tap_close(btpan_cb.tap_fd);
150 btpan_cb.tap_fd = -1;
151 }
152 }
153}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700154
The Android Open Source Project5738f832012-12-12 16:00:35 -0800155void btif_pan_cleanup()
156{
157 if(stack_initialized)
158 {
159 //bt is shuting down, invalid all bta pan handles
160 int i;
161 for(i = 0; i < MAX_PAN_CONNS; i++)
162 btpan_cleanup_conn(&btpan_cb.conns[i]);
163 pan_disable();
The Android Open Source Project5738f832012-12-12 16:00:35 -0800164 }
165 stack_initialized = FALSE;
166}
167
168static btpan_callbacks_t callback;
169static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks)
170{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700171 BTIF_TRACE_DEBUG("stack_initialized = %d, btpan_cb.enabled:%d", stack_initialized, btpan_cb.enabled);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800172 jni_initialized = TRUE;
173 if(stack_initialized && !btpan_cb.enabled)
174 btif_pan_init();
175 callback = *callbacks;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800176 return BT_STATUS_SUCCESS;
177}
178
179static void btpan_jni_cleanup()
180{
181 pan_disable();
182 jni_initialized = FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800183}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700184
The Android Open Source Project5738f832012-12-12 16:00:35 -0800185static inline int bta_role_to_btpan(int bta_pan_role)
186{
187 int btpan_role = 0;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700188 BTIF_TRACE_DEBUG("bta_pan_role:0x%x", bta_pan_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800189 if(bta_pan_role & PAN_ROLE_NAP_SERVER)
190 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800191 btpan_role |= BTPAN_ROLE_PANNAP;
192 }
193 if(bta_pan_role & PAN_ROLE_CLIENT)
194 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800195 btpan_role |= BTPAN_ROLE_PANU;
196 }
197 return btpan_role;
198}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700199
The Android Open Source Project5738f832012-12-12 16:00:35 -0800200static inline int btpan_role_to_bta(int btpan_role)
201{
202 int bta_pan_role = PAN_ROLE_INACTIVE;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700203 BTIF_TRACE_DEBUG("btpan_role:0x%x", btpan_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800204 if(btpan_role & BTPAN_ROLE_PANNAP)
205 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800206 bta_pan_role |= PAN_ROLE_NAP_SERVER;
207 }
208 if(btpan_role & BTPAN_ROLE_PANU)
209 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800210 bta_pan_role |= PAN_ROLE_CLIENT;
211 }
212 return bta_pan_role;
213}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700214
The Android Open Source Project5738f832012-12-12 16:00:35 -0800215static volatile int btpan_dev_local_role;
216static tBTA_PAN_ROLE_INFO bta_panu_info = {PANU_SERVICE_NAME, 0, PAN_SECURITY};
Nitin Shivpure36f43cc2013-08-29 21:28:59 +0530217static tBTA_PAN_ROLE_INFO bta_pan_nap_info = {PAN_NAP_SERVICE_NAME, 1, PAN_SECURITY};
The Android Open Source Project5738f832012-12-12 16:00:35 -0800218
219static bt_status_t btpan_enable(int local_role)
220{
221 int bta_pan_role;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700222 BTIF_TRACE_DEBUG("local_role:%d", local_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800223 bta_pan_role = btpan_role_to_bta(local_role);
Mike J. Chen3576c562014-04-01 12:54:27 -0700224#if BTA_PAN_INCLUDED == TRUE
The Android Open Source Project5738f832012-12-12 16:00:35 -0800225 BTA_PanSetRole(bta_pan_role, &bta_panu_info, NULL, &bta_pan_nap_info);
226 btpan_dev_local_role = local_role;
227 return BT_STATUS_SUCCESS;
Mike J. Chen3576c562014-04-01 12:54:27 -0700228#else
229 return BT_STATUS_FAIL;
230#endif
The Android Open Source Project5738f832012-12-12 16:00:35 -0800231}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700232
The Android Open Source Project5738f832012-12-12 16:00:35 -0800233static int btpan_get_local_role()
234{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700235 BTIF_TRACE_DEBUG("btpan_dev_local_role:%d", btpan_dev_local_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800236 return btpan_dev_local_role;
237}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700238
The Android Open Source Project5738f832012-12-12 16:00:35 -0800239static bt_status_t btpan_connect(const bt_bdaddr_t *bd_addr, int local_role, int remote_role)
240{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700241 BTIF_TRACE_DEBUG("local_role:%d, remote_role:%d", local_role, remote_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800242 int bta_local_role = btpan_role_to_bta(local_role);
243 int bta_remote_role = btpan_role_to_bta(remote_role);
244 btpan_new_conn(-1, bd_addr->address, bta_local_role, bta_remote_role);
245 BTA_PanOpen((UINT8*)bd_addr->address, bta_local_role, bta_remote_role);
246 return BT_STATUS_SUCCESS;
247}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700248
The Android Open Source Project5738f832012-12-12 16:00:35 -0800249static void btif_in_pan_generic_evt(UINT16 event, char *p_param)
250{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700251 BTIF_TRACE_EVENT("%s: event=%d", __FUNCTION__, event);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800252 switch (event) {
253 case BTIF_PAN_CB_DISCONNECTING:
254 {
255 bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)p_param;
256 btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
257 int btpan_conn_local_role;
258 int btpan_remote_role;
259 asrt(conn != NULL);
260 if (conn) {
261 btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
262 btpan_remote_role = bta_role_to_btpan(conn->remote_role);
263 callback.connection_state_cb(BTPAN_STATE_DISCONNECTING, BT_STATUS_SUCCESS,
264 (const bt_bdaddr_t*)conn->peer, btpan_conn_local_role, btpan_remote_role);
265 }
266 } break;
267 default:
268 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700269 BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __FUNCTION__, event);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800270 }
271 break;
272 }
273}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700274
The Android Open Source Project5738f832012-12-12 16:00:35 -0800275static bt_status_t btpan_disconnect(const bt_bdaddr_t *bd_addr)
276{
The Android Open Source Project5738f832012-12-12 16:00:35 -0800277 btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
278 if(conn && conn->handle >= 0)
279 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800280 /* Inform the application that the disconnect has been initiated successfully */
281 btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
282 (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
Nitin Shivpure42a44fc2014-07-18 17:12:25 +0530283 BTA_PanClose(conn->handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800284 return BT_STATUS_SUCCESS;
285 }
286 return BT_STATUS_FAIL;
287}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700288
289static int pan_pth = -1;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800290void create_tap_read_thread(int tap_fd)
291{
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700292 if(pan_pth < 0)
293 pan_pth = btsock_thread_create(btpan_tap_fd_signaled, NULL);
294 if(pan_pth >= 0)
295 btsock_thread_add_fd(pan_pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800296}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700297
The Android Open Source Project5738f832012-12-12 16:00:35 -0800298void destroy_tap_read_thread(void)
299{
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700300 if(pan_pth >= 0)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800301 {
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700302 btsock_thread_exit(pan_pth);
303 pan_pth = -1;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800304 }
305}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700306
The Android Open Source Project5738f832012-12-12 16:00:35 -0800307static int tap_if_up(const char *devname, BD_ADDR addr)
308{
309 struct ifreq ifr;
310 int sk, err;
311
312 sk = socket(AF_INET, SOCK_DGRAM, 0);
313
314 //set mac addr
315 memset(&ifr, 0, sizeof(ifr));
316 strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700317 err = TEMP_FAILURE_RETRY(ioctl(sk, SIOCGIFHWADDR, &ifr));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800318 if(err < 0)
319 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700320 BTIF_TRACE_ERROR("Could not get network hardware for interface:%s, errno:%s", devname, strerror(errno));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800321 close(sk);
322 return -1;
323 }
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800324 /* debug("found mac address for interface:%s = %02x:%02x:%02x:%02x:%02x:%02x", devname, */
325 /* ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], */
326 /* ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800327 strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
328 memcpy(ifr.ifr_hwaddr.sa_data, addr, 6);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800329 /* debug("setting bt address for interface:%s = %02x:%02x:%02x:%02x:%02x:%02x", devname, */
330 /* ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], */
331 /* ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800332
Loic Poulain01364c72014-04-08 08:46:01 +0200333 /* The IEEE has specified that the most significant bit of the most significant byte is used to
334 * determine a multicast address. If its a 1, that means multicast, 0 means unicast.
335 * Kernel returns an error if we try to set a multicast address for the tun-tap ethernet interface.
336 * Mask this bit to avoid any issue with auto generated address.
337 */
338 if (ifr.ifr_hwaddr.sa_data[0] & 0x01) {
Matthew Xieafa6e1a2014-06-28 11:35:29 -0700339 BTIF_TRACE_WARNING("Not a unicast MAC address, force multicast bit flipping");
Loic Poulain01364c72014-04-08 08:46:01 +0200340 ifr.ifr_hwaddr.sa_data[0] &= ~0x01;
341 }
342
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700343 err = TEMP_FAILURE_RETRY(ioctl(sk, SIOCSIFHWADDR, (caddr_t)&ifr));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800344
345 if (err < 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700346 BTIF_TRACE_ERROR("Could not set bt address for interface:%s, errno:%s", devname, strerror(errno));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800347 close(sk);
348 return -1;
349 }
350
351 //bring it up
352 memset(&ifr, 0, sizeof(ifr));
353 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
354
355 ifr.ifr_flags |= IFF_UP;
356 ifr.ifr_flags |= IFF_MULTICAST;
357
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700358 err = TEMP_FAILURE_RETRY(ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800359
360
361 if (err < 0) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700362 BTIF_TRACE_ERROR("Could not bring up network interface:%s, errno:%d", devname, errno);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800363 close(sk);
364 return -1;
365 }
366 close(sk);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700367 BTIF_TRACE_DEBUG("network interface: %s is up", devname);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800368 return 0;
369}
370
371static int tap_if_down(const char *devname)
372{
373 struct ifreq ifr;
374 int sk, err;
375
376 sk = socket(AF_INET, SOCK_DGRAM, 0);
377
378 memset(&ifr, 0, sizeof(ifr));
379 strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
380
381 ifr.ifr_flags &= ~IFF_UP;
382
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700383 err = TEMP_FAILURE_RETRY(ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800384
385 close(sk);
386
387 return 0;
388}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700389
390void btpan_set_flow_control(BOOLEAN enable) {
391 if (btpan_cb.tap_fd == -1)
392 return;
393
394 btpan_cb.flow = enable;
395 if (enable) {
396 btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
397 bta_dmexecutecallback(btu_exec_tap_fd_read, (void *)btpan_cb.tap_fd);
398 }
399}
400
The Android Open Source Project5738f832012-12-12 16:00:35 -0800401int btpan_tap_open()
402{
The Android Open Source Project5738f832012-12-12 16:00:35 -0800403 struct ifreq ifr;
404 int fd, err;
405 const char *clonedev = "/dev/tun";
406
407 /* open the clone device */
408
409 //system("insmod /system/lib/modules/tun.ko");
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700410 if( (fd = TEMP_FAILURE_RETRY(open(clonedev, O_RDWR))) < 0 ) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800411
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700412 BTIF_TRACE_DEBUG("could not open %s, err:%d", clonedev, errno);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800413 return fd;
414 }
415
416 memset(&ifr, 0, sizeof(ifr));
417 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
418
419 strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
420
421 /* try to create the device */
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700422 if( (err = TEMP_FAILURE_RETRY(ioctl(fd, TUNSETIFF, (void *) &ifr))) < 0 )//|| tap_setup_ip(TAP_IF_NAME) == FALSE)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800423 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700424 BTIF_TRACE_DEBUG("ioctl error:%d, errno:%s", err, strerror(errno));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800425 close(fd);
426 return err;
427 }
428 BTM_GetLocalDeviceAddr (local_addr);
429 if(tap_if_up(TAP_IF_NAME, local_addr) == 0)
430 {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700431 int flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL, 0));
432 TEMP_FAILURE_RETRY(fcntl(fd, F_SETFL, flags | O_NONBLOCK));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800433 return fd;
434 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700435 BTIF_TRACE_ERROR("can not bring up tap interface:%s", TAP_IF_NAME);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800436 close(fd);
437 return -1;
438}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700439
The Android Open Source Project5738f832012-12-12 16:00:35 -0800440int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst, UINT16 proto, const char* buf,
441 UINT16 len, BOOLEAN ext, BOOLEAN forward)
442{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800443 UNUSED(ext);
444 UNUSED(forward);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800445 if(tap_fd != -1)
446 {
447 tETH_HDR eth_hdr;
448 //if(is_empty_eth_addr(dst))
449 // memcpy(&eth_hdr.h_dest, local_addr, ETH_ADDR_LEN);
450 //else
451 memcpy(&eth_hdr.h_dest, dst, ETH_ADDR_LEN);
452 memcpy(&eth_hdr.h_src, src, ETH_ADDR_LEN);
453 eth_hdr.h_proto = htons(proto);
Hemant Guptae2187302014-10-15 19:59:23 +0530454 char packet[TAP_MAX_PKT_WRITE_LEN + sizeof(tETH_HDR)];
The Android Open Source Project5738f832012-12-12 16:00:35 -0800455 memcpy(packet, &eth_hdr, sizeof(tETH_HDR));
Hemant Guptae2187302014-10-15 19:59:23 +0530456 if (len > TAP_MAX_PKT_WRITE_LEN)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800457 {
458 ALOGE("btpan_tap_send eth packet size:%d is exceeded limit!", len);
459 return -1;
460 }
461 memcpy(packet + sizeof(tETH_HDR), buf, len);
462
463 /* Send data to network interface */
464 //btnet_send(btpan_cb.conn[i].sock.sock, &buffer, (len + sizeof(tETH_HDR)));
465 //dump_bin("packet to network", packet, len + sizeof(tETH_HDR));
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700466 int ret = TEMP_FAILURE_RETRY(write(tap_fd, packet, len + sizeof(tETH_HDR)));
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700467 BTIF_TRACE_DEBUG("ret:%d", ret);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800468 return ret;
469 }
470 return -1;
471
472}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700473
The Android Open Source Project5738f832012-12-12 16:00:35 -0800474int btpan_tap_close(int fd)
475{
The Android Open Source Project5738f832012-12-12 16:00:35 -0800476 tap_if_down(TAP_IF_NAME);
477 close(fd);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700478 if(pan_pth >= 0)
479 btsock_thread_wakeup(pan_pth);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800480 return 0;
481}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700482
The Android Open Source Project5738f832012-12-12 16:00:35 -0800483btpan_conn_t * btpan_find_conn_handle(UINT16 handle)
484{
485 int i;
486 for(i = 0; i < MAX_PAN_CONNS; i++)
487 if(btpan_cb.conns[i].handle == handle)
488 return &btpan_cb.conns[i];
489 return NULL;
490}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700491
The Android Open Source Project5738f832012-12-12 16:00:35 -0800492btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr)
493{
494 int i;
495 for(i = 0; i < MAX_PAN_CONNS; i++)
496 if(memcmp(btpan_cb.conns[i].peer, addr, sizeof(BD_ADDR)) == 0)
497 return &btpan_cb.conns[i];
498 return NULL;
499}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700500
Nitin Shivpure42a44fc2014-07-18 17:12:25 +0530501static void btpan_close_conn(btpan_conn_t* conn)
502{
503 BTIF_TRACE_DEBUG("btpan_close_conn: %p",conn);
504
505 if (conn && conn->state == PAN_STATE_OPEN)
506 {
507 BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN");
508
509 conn->state = PAN_STATE_CLOSE;
510 btpan_cb.open_count--;
511
512 if (btpan_cb.open_count == 0)
513 {
514 destroy_tap_read_thread();
515 if (btpan_cb.tap_fd != -1)
516 {
517 btpan_tap_close(btpan_cb.tap_fd);
518 btpan_cb.tap_fd = -1;
519 }
520 }
521 }
522}
523
The Android Open Source Project5738f832012-12-12 16:00:35 -0800524static void btpan_cleanup_conn(btpan_conn_t* conn)
525{
526 if(conn)
527 {
528 conn->handle = -1;
529 conn->state = -1;
530 memset(&conn->peer, 0, sizeof(conn->peer));
531 memset(&conn->eth_addr, 0, sizeof(conn->eth_addr));
532 conn->local_role = conn->remote_role = 0;
533 }
534}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700535
The Android Open Source Project5738f832012-12-12 16:00:35 -0800536btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role, int remote_role )
537{
538 int i;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800539 for(i = 0; i < MAX_PAN_CONNS; i++)
540 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700541 BTIF_TRACE_DEBUG("conns[%d]:%d", i, btpan_cb.conns[i].handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800542 if(btpan_cb.conns[i].handle == -1)
543 {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700544 BTIF_TRACE_DEBUG("handle:%d, local_role:%d, remote_role:%d", handle, local_role, remote_role);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800545
546 btpan_cb.conns[i].handle = handle;
547 bdcpy(btpan_cb.conns[i].peer, addr);
548 btpan_cb.conns[i].local_role = local_role;
549 btpan_cb.conns[i].remote_role = remote_role;
550 return &btpan_cb.conns[i];
551 }
552 }
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700553 BTIF_TRACE_DEBUG("MAX_PAN_CONNS:%d exceeded, return NULL as failed", MAX_PAN_CONNS);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800554 return NULL;
555}
556
557void btpan_close_handle(btpan_conn_t *p)
558{
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700559 BTIF_TRACE_DEBUG("btpan_close_handle : close handle %d", p->handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800560 p->handle = -1;
561 p->local_role = -1;
562 p->remote_role = -1;
563 memset(&p->peer, 0, 6);
564}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700565
Sharvil Nanavatida271ee2014-05-30 21:04:03 -0700566static inline bool should_forward(tETH_HDR* hdr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800567{
Sharvil Nanavatida271ee2014-05-30 21:04:03 -0700568 uint16_t proto = ntohs(hdr->h_proto);
569 if(proto == ETH_P_IP || proto == ETH_P_ARP || proto == ETH_P_IPV6)
570 return true;
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700571 BTIF_TRACE_DEBUG("unknown proto:%x", proto);
Sharvil Nanavatida271ee2014-05-30 21:04:03 -0700572 return false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800573}
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700574
575static int forward_bnep(tETH_HDR* eth_hdr, BT_HDR *hdr) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800576 int broadcast = eth_hdr->h_dest[0] & 1;
577 int i;
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700578
579 // Find the right connection to send this frame over.
580 for (i = 0; i < MAX_PAN_CONNS; i++) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800581 UINT16 handle = btpan_cb.conns[i].handle;
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700582 if (handle != (UINT16)-1 &&
The Android Open Source Project5738f832012-12-12 16:00:35 -0800583 (broadcast || memcmp(btpan_cb.conns[i].eth_addr, eth_hdr->h_dest, sizeof(BD_ADDR)) == 0
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700584 || memcmp(btpan_cb.conns[i].peer, eth_hdr->h_dest, sizeof(BD_ADDR)) == 0)) {
585 int result = PAN_WriteBuf(handle, eth_hdr->h_dest, eth_hdr->h_src, ntohs(eth_hdr->h_proto), hdr, 0);
586 switch (result) {
587 case PAN_Q_SIZE_EXCEEDED:
588 return FORWARD_CONGEST;
589 case PAN_SUCCESS:
590 return FORWARD_SUCCESS;
591 default:
592 return FORWARD_FAILURE;
593 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800594 }
595 }
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700596 GKI_freebuf(hdr);
597 return FORWARD_IGNORE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800598}
599
600static void bta_pan_callback_transfer(UINT16 event, char *p_param)
601{
602 tBTA_PAN *p_data = (tBTA_PAN *)p_param;
603 switch(event)
604 {
605 case BTA_PAN_ENABLE_EVT:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700606 BTIF_TRACE_DEBUG("BTA_PAN_ENABLE_EVT");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800607 break;
608 case BTA_PAN_SET_ROLE_EVT:
609 {
610 int btpan_role = bta_role_to_btpan(p_data->set_role.role);
611 bt_status_t status = p_data->set_role.status == BTA_PAN_SUCCESS ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
612 btpan_control_state_t state = btpan_role == 0 ? BTPAN_STATE_DISABLED : BTPAN_STATE_ENABLED;
613 callback.control_state_cb(state, btpan_role, status, TAP_IF_NAME);
614 break;
615 }
616 case BTA_PAN_OPENING_EVT:
617 {
618 btpan_conn_t* conn;
619 bdstr_t bds;
620 bd2str((bt_bdaddr_t*)p_data->opening.bd_addr, &bds);
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700621 BTIF_TRACE_DEBUG("BTA_PAN_OPENING_EVT handle %d, addr: %s", p_data->opening.handle, bds);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800622 conn = btpan_find_conn_addr(p_data->opening.bd_addr);
623
624 asrt(conn != NULL);
625 if (conn)
626 {
627 conn->handle = p_data->opening.handle;
628 int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
629 int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
630 callback.connection_state_cb(BTPAN_STATE_CONNECTING, BT_STATUS_SUCCESS,
631 (const bt_bdaddr_t*)p_data->opening.bd_addr, btpan_conn_local_role, btpan_remote_role);
632 }
633 else
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700634 BTIF_TRACE_ERROR("connection not found");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800635 break;
636 }
637 case BTA_PAN_OPEN_EVT:
638 {
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800639 /* debug("BTA_PAN_OPEN_EVT, open status:%d, bd_addr = [%02X:%02X:%02X:%02X:%02X:%02X]", */
640 /* p_data->open.status, */
641 /* p_data->open.bd_addr[0], p_data->open.bd_addr[1], p_data->open.bd_addr[2], */
642 /* p_data->open.bd_addr[3], p_data->open.bd_addr[4], p_data->open.bd_addr[5]); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800643 btpan_connection_state_t state;
644 bt_status_t status;
Nitin Shivpuree85eb5a2013-10-03 19:06:12 +0530645 btpan_conn_t *conn = btpan_find_conn_handle(p_data->open.handle);
646
647 ALOGV("%s pan connection open status: %d", __func__, p_data->open.status);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800648 if(p_data->open.status == BTA_PAN_SUCCESS)
649 {
650 state = BTPAN_STATE_CONNECTED;
651 status = BT_STATUS_SUCCESS;
652 }
653 else
654 {
655 state = BTPAN_STATE_DISCONNECTED;
656 status = BT_STATUS_FAIL;
Nitin Shivpuree85eb5a2013-10-03 19:06:12 +0530657 btpan_cleanup_conn(conn);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800658 }
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800659 /* debug("BTA_PAN_OPEN_EVT handle:%d, conn:%p", p_data->open.handle, conn); */
660 /* debug("conn bta local_role:%d, bta remote role:%d", conn->local_role, conn->remote_role); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800661 int btpan_conn_local_role = bta_role_to_btpan(p_data->open.local_role);
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800662 /* debug("bta local_role:%d, bta remote role:%d", p_data->open.local_role, p_data->open.peer_role); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800663 int btpan_remote_role = bta_role_to_btpan(p_data->open.peer_role);
664 callback.connection_state_cb(state, status, (const bt_bdaddr_t*)p_data->open.bd_addr,
665 btpan_conn_local_role, btpan_remote_role);
666 break;
667 }
668 case BTA_PAN_CLOSE_EVT:
669 {
670 btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
671
672 ALOGI("%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
Nitin Shivpure42a44fc2014-07-18 17:12:25 +0530673 btpan_close_conn(conn);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800674
675 if(conn && conn->handle >= 0)
676 {
The Android Open Source Project689d66b2012-12-12 17:18:15 -0800677 /* debug("BTA_PAN_CLOSE_EVT, conn local_role:%d, remote_role:%d", conn->local_role, conn->remote_role); */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800678 int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
679 int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
680 callback.connection_state_cb(BTPAN_STATE_DISCONNECTED, 0, (const bt_bdaddr_t*)conn->peer,
681 btpan_conn_local_role, btpan_remote_role);
682 btpan_cleanup_conn(conn);
683 }
684 else
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700685 BTIF_TRACE_ERROR("pan handle not found (%d)", p_data->close.handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800686 break;
687 }
688 default:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700689 BTIF_TRACE_WARNING("Unknown pan event %d", event);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800690 break;
691 }
692}
693
694static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN *p_data)
695{
696 btif_transfer_context(bta_pan_callback_transfer, event, (char*)p_data, sizeof(tBTA_PAN), NULL);
697}
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800698
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700699#define IS_EXCEPTION(e) ((e) & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))
700static void btu_exec_tap_fd_read(void *p_param) {
701 struct pollfd ufd;
702 int fd = (int)p_param;
703
704 if (fd == -1 || fd != btpan_cb.tap_fd)
705 return;
706
Zhenye Zhu95ca3c42014-08-26 14:26:56 -0700707 // Don't occupy BTU context too long, avoid GKI buffer overruns and
708 // give other profiles a chance to run by limiting the amount of memory
709 // PAN can use from the shared pool buffer.
710 for(int i = 0; i < PAN_POOL_MAX && btif_is_enabled() && btpan_cb.flow; i++) {
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700711 BT_HDR *buffer = (BT_HDR *)GKI_getpoolbuf(PAN_POOL_ID);
712 if (!buffer) {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700713 BTIF_TRACE_WARNING("%s unable to allocate buffer for packet.", __func__);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700714 break;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800715 }
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700716 buffer->offset = PAN_MINIMUM_OFFSET;
717 buffer->len = GKI_get_buf_size(buffer) - sizeof(BT_HDR) - buffer->offset;
718
719 UINT8 *packet = (UINT8 *)buffer + sizeof(BT_HDR) + buffer->offset;
720
721 // If we don't have an undelivered packet left over, pull one from the TAP driver.
722 // We save it in the congest_packet right away in case we can't deliver it in this
723 // attempt.
724 if (!btpan_cb.congest_packet_size) {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700725 ssize_t ret = TEMP_FAILURE_RETRY(read(fd, btpan_cb.congest_packet, sizeof(btpan_cb.congest_packet)));
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700726 switch (ret) {
727 case -1:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700728 BTIF_TRACE_ERROR("%s unable to read from driver: %s", __func__, strerror(errno));
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700729 GKI_freebuf(buffer);
Zhenye Zhu285f7c62014-11-25 15:51:07 -0800730 //add fd back to monitor thread to try it again later
731 btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700732 return;
733 case 0:
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700734 BTIF_TRACE_WARNING("%s end of file reached.", __func__);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700735 GKI_freebuf(buffer);
Zhenye Zhu285f7c62014-11-25 15:51:07 -0800736 //add fd back to monitor thread to process the exception
737 btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700738 return;
739 default:
740 btpan_cb.congest_packet_size = ret;
741 break;
742 }
743 }
744
745 memcpy(packet, btpan_cb.congest_packet, MIN(btpan_cb.congest_packet_size, buffer->len));
746 buffer->len = MIN(btpan_cb.congest_packet_size, buffer->len);
747
748 if (buffer->len > sizeof(tETH_HDR) && should_forward((tETH_HDR *)packet)) {
749 // Extract the ethernet header from the buffer since the PAN_WriteBuf inside
750 // forward_bnep can't handle two pointers that point inside the same GKI buffer.
751 tETH_HDR hdr;
752 memcpy(&hdr, packet, sizeof(tETH_HDR));
753
754 // Skip the ethernet header.
755 buffer->len -= sizeof(tETH_HDR);
756 buffer->offset += sizeof(tETH_HDR);
757 if (forward_bnep(&hdr, buffer) != FORWARD_CONGEST)
758 btpan_cb.congest_packet_size = 0;
759 } else {
Sharvil Nanavatie8c3d752014-05-04 10:12:26 -0700760 BTIF_TRACE_WARNING("%s dropping packet of length %d", __func__, buffer->len);
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700761 btpan_cb.congest_packet_size = 0;
762 GKI_freebuf(buffer);
763 }
764
765 // Bail out of the loop if reading from the TAP fd would block.
766 ufd.fd = fd;
767 ufd.events = POLLIN;
768 ufd.revents = 0;
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700769 if(TEMP_FAILURE_RETRY(poll(&ufd, 1, 0)) <= 0 || IS_EXCEPTION(ufd.revents))
Zhenye Zhu285f7c62014-11-25 15:51:07 -0800770 break;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800771 }
Zhenye Zhu285f7c62014-11-25 15:51:07 -0800772 //add fd back to monitor thread
773 btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800774}
775
Sharvil Nanavati4186b0e2014-04-07 13:52:37 -0700776static void btif_pan_close_all_conns() {
777 int i;
778 if (!stack_initialized)
779 return;
780
781 for (i = 0; i < MAX_PAN_CONNS; ++i)
782 if (btpan_cb.conns[i].handle != -1)
783 BTA_PanClose(btpan_cb.conns[i].handle);
784}
785
786static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id) {
787 assert(btpan_cb.tap_fd == fd);
788
789 if (btpan_cb.tap_fd != fd)
790 return;
791
792 if(flags & SOCK_THREAD_FD_EXCEPTION) {
793 btpan_cb.tap_fd = -1;
794 btpan_tap_close(fd);
795 btif_pan_close_all_conns();
796 } else if(flags & SOCK_THREAD_FD_RD)
797 bta_dmexecutecallback(btu_exec_tap_fd_read, (void *)fd);
798}