tBTA_JV_CB bta_jv_cb;
-/* one of these exists for each client */
-struct fc_client {
- struct fc_client* next_all_list;
- struct fc_client* next_chan_list;
- RawAddress remote_addr;
- uint32_t id;
- tBTA_JV_L2CAP_CBACK* p_cback;
- uint32_t l2cap_socket_id;
- uint16_t handle;
- uint16_t chan;
- uint8_t sec_id;
- unsigned server : 1;
- unsigned init_called : 1;
-};
-
-/* one of these exists for each channel we're dealing with */
-struct fc_channel {
- struct fc_channel* next;
- struct fc_client* clients;
- uint8_t has_server : 1;
- uint16_t chan;
-};
-
-static struct fc_client* fc_clients;
-static struct fc_channel* fc_channels;
-static uint32_t fc_next_id;
-
-static void fcchan_conn_chng_cbk(uint16_t chan, const RawAddress& bd_addr,
- bool connected, uint16_t reason,
- tBT_TRANSPORT);
-static void fcchan_data_cbk(uint16_t chan, const RawAddress& bd_addr,
- BT_HDR* p_buf);
-
static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
tBTA_JV_PCB* p_pcb_open);
static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle);
}
}
/******************************************************************************/
-
-static struct fc_channel* fcchan_get(uint16_t chan, char create) {
- struct fc_channel* t = fc_channels;
- static tL2CAP_FIXED_CHNL_REG fcr = {
- .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
- .pL2CA_FixedData_Cb = fcchan_data_cbk,
- .default_idle_tout = 0xffff,
- };
-
- while (t && t->chan != chan) t = t->next;
-
- if (t)
- return t;
- else if (!create)
- return NULL; /* we cannot alloc a struct if not asked to */
-
- t = static_cast<struct fc_channel*>(osi_calloc(sizeof(*t)));
- t->chan = chan;
-
- if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
- osi_free(t);
- return NULL;
- }
-
- // link it in
- t->next = fc_channels;
- fc_channels = t;
-
- return t;
-}
-
-/* pass NULL to find servers */
-static struct fc_client* fcclient_find_by_addr(struct fc_client* start,
- const RawAddress* addr) {
- struct fc_client* t = start;
-
- while (t) {
- /* match client if have addr */
- if (addr && addr == &t->remote_addr) break;
-
- /* match server if do not have addr */
- if (!addr && t->server) break;
-
- t = t->next_all_list;
- }
-
- return t;
-}
-
-static struct fc_client* fcclient_find_by_id(uint32_t id) {
- struct fc_client* t = fc_clients;
-
- while (t && t->id != id) t = t->next_all_list;
-
- return t;
-}
-
-static struct fc_client* fcclient_alloc(uint16_t chan, char server,
- const uint8_t* sec_id_to_use) {
- struct fc_channel* fc = fcchan_get(chan, true);
- struct fc_client* t;
- uint8_t sec_id;
-
- if (!fc) return NULL;
-
- if (fc->has_server && server)
- return NULL; /* no way to have multiple servers on same channel */
-
- if (sec_id_to_use)
- sec_id = *sec_id_to_use;
- else
- sec_id = bta_jv_alloc_sec_id();
-
- t = static_cast<fc_client*>(osi_calloc(sizeof(*t)));
- // Allocate it a unique ID
- do {
- t->id = ++fc_next_id;
- } while (!t->id || fcclient_find_by_id(t->id));
-
- // Populate some params
- t->chan = chan;
- t->server = server;
-
- // Get a security id
- t->sec_id = sec_id;
-
- // Link it in to global list
- t->next_all_list = fc_clients;
- fc_clients = t;
-
- // Link it in to channel list
- t->next_chan_list = fc->clients;
- fc->clients = t;
-
- // Update channel if needed
- if (server) fc->has_server = true;
-
- return t;
-}
-
-static void fcclient_free(struct fc_client* fc) {
- struct fc_client* t = fc_clients;
- struct fc_channel* tc = fcchan_get(fc->chan, false);
-
- // remove from global list
- while (t && t->next_all_list != fc) t = t->next_all_list;
-
- if (!t && fc != fc_clients) return; /* prevent double-free */
-
- if (t)
- t->next_all_list = fc->next_all_list;
- else
- fc_clients = fc->next_all_list;
-
- // remove from channel list
- if (tc) {
- t = tc->clients;
-
- while (t && t->next_chan_list != fc) t = t->next_chan_list;
-
- if (t)
- t->next_chan_list = fc->next_chan_list;
- else
- tc->clients = fc->next_chan_list;
-
- // if was server then channel no longer has a server
- if (fc->server) tc->has_server = false;
- }
-
- // free security id
- bta_jv_free_sec_id(&fc->sec_id);
-
- osi_free(fc);
-}
-
-static void fcchan_conn_chng_cbk(uint16_t chan, const RawAddress& bd_addr,
- bool connected, uint16_t reason,
- tBT_TRANSPORT transport) {
- tBTA_JV init_evt;
- tBTA_JV open_evt;
- struct fc_channel* tc;
- struct fc_client *t = NULL, *new_conn;
- tBTA_JV_L2CAP_CBACK* p_cback = NULL;
- char call_init = false;
- uint32_t l2cap_socket_id;
-
- tc = fcchan_get(chan, false);
- if (tc) {
- t = fcclient_find_by_addr(
- tc->clients,
- &bd_addr); // try to find an open socked for that addr
- if (t) {
- p_cback = t->p_cback;
- l2cap_socket_id = t->l2cap_socket_id;
- } else {
- t = fcclient_find_by_addr(
- tc->clients,
- NULL); // try to find a listening socked for that channel
- if (t) {
- // found: create a normal connection socket and assign the connection to
- // it
- new_conn = fcclient_alloc(chan, false, &t->sec_id);
- if (new_conn) {
- new_conn->remote_addr = bd_addr;
- new_conn->p_cback = NULL; // for now
- new_conn->init_called = true; /*nop need to do it again */
-
- p_cback = t->p_cback;
- l2cap_socket_id = t->l2cap_socket_id;
-
- t = new_conn;
- }
- } else {
- // drop it
- return;
- }
- }
- }
-
- if (t) {
- if (!t->init_called) {
- call_init = true;
- t->init_called = true;
-
- init_evt.l2c_cl_init.handle = t->id;
- init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
- init_evt.l2c_cl_init.sec_id = t->sec_id;
- }
-
- open_evt.l2c_open.handle = t->id;
- open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
- memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr,
- sizeof(open_evt.l2c_le_open.rem_bda));
- // TODO: (apanicke) Change the way these functions work so that casting
- // isn't needed
- open_evt.l2c_le_open.p_p_cback = (void**)&t->p_cback;
- open_evt.l2c_le_open.p_user_data = (void**)&t->l2cap_socket_id;
- open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
-
- if (connected) {
- open_evt.l2c_open.status = BTA_JV_SUCCESS;
- } else {
- fcclient_free(t);
- open_evt.l2c_open.status = BTA_JV_FAILURE;
- }
- }
-
- if (call_init) p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, l2cap_socket_id);
-
- // call this with lock taken so socket does not disappear from under us */
- if (p_cback) {
- p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, l2cap_socket_id);
- if (!t->p_cback) /* no callback set, means they do not want this one... */
- fcclient_free(t);
- }
-}
-
-static void fcchan_data_cbk(uint16_t chan, const RawAddress& bd_addr,
- BT_HDR* p_buf) {
- tBTA_JV evt_data;
- struct fc_channel* tc;
- struct fc_client* t = NULL;
- tBTA_JV_L2CAP_CBACK* sock_cback = NULL;
- uint32_t sock_id;
-
- tc = fcchan_get(chan, false);
- if (tc) {
- // try to find an open socked for that addr and channel
- t = fcclient_find_by_addr(tc->clients, &bd_addr);
- }
- if (!t) {
- // no socket -> drop it
- return;
- }
-
-
- sock_cback = t->p_cback;
- sock_id = t->l2cap_socket_id;
- evt_data.le_data_ind.handle = t->id;
- evt_data.le_data_ind.p_buf = p_buf;
-
- if (sock_cback) sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_id);
-}
-
-/* stops an LE L2CAP server */
-void bta_jv_l2cap_stop_server_le(uint16_t local_chan) {
- struct fc_client* fcclient;
-
- tBTA_JV evt;
- evt.l2c_close.status = BTA_JV_FAILURE;
- evt.l2c_close.async = false;
- evt.l2c_close.handle = GAP_INVALID_HANDLE;
-
- struct fc_channel* fcchan = fcchan_get(local_chan, false);
- if (fcchan) {
- while ((fcclient = fcchan->clients)) {
- tBTA_JV_L2CAP_CBACK* p_cback = fcclient->p_cback;
- uint32_t l2cap_socket_id = fcclient->l2cap_socket_id;
-
- evt.l2c_close.handle = fcclient->id;
- evt.l2c_close.status = BTA_JV_SUCCESS;
- evt.l2c_close.async = false;
-
- fcclient_free(fcclient);
-
- if (p_cback) p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, l2cap_socket_id);
- }
- }
-}