/****************************************************************************** * * Copyright (C) 2010-2014 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This is the implementation file for the NFA P2P. * ******************************************************************************/ #include <android-base/stringprintf.h> #include <base/logging.h> #include "llcp_api.h" #include "nfa_dm_int.h" #include "nfa_p2p_api.h" #include "nfa_p2p_int.h" using android::base::StringPrintf; extern bool nfc_debug_enabled; /***************************************************************************** ** Global Variables *****************************************************************************/ /***************************************************************************** ** Static Functions *****************************************************************************/ /***************************************************************************** ** Constants *****************************************************************************/ /******************************************************************************* ** ** Function nfa_p2p_allocate_conn_cb ** ** Description Allocate data link connection control block ** ** ** Returns uint8_t ** *******************************************************************************/ static uint8_t nfa_p2p_allocate_conn_cb(uint8_t local_sap) { uint8_t xx; for (xx = 0; xx < LLCP_MAX_DATA_LINK; xx++) { if (nfa_p2p_cb.conn_cb[xx].flags == 0) { nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_IN_USE; nfa_p2p_cb.conn_cb[xx].local_sap = local_sap; return (xx); } } LOG(ERROR) << StringPrintf("No resource"); return LLCP_MAX_DATA_LINK; } /******************************************************************************* ** ** Function nfa_p2p_deallocate_conn_cb ** ** Description Deallocate data link connection control block ** ** ** Returns void ** *******************************************************************************/ static void nfa_p2p_deallocate_conn_cb(uint8_t xx) { if (xx < LLCP_MAX_DATA_LINK) { nfa_p2p_cb.conn_cb[xx].flags = 0; } else { LOG(ERROR) << StringPrintf("Invalid index (%d)", xx); } } /******************************************************************************* ** ** Function nfa_p2p_find_conn_cb ** ** Description Find data link connection control block by local/remote SAP ** ** ** Returns uint8_t ** *******************************************************************************/ static uint8_t nfa_p2p_find_conn_cb(uint8_t local_sap, uint8_t remote_sap) { uint8_t xx; for (xx = 0; xx < LLCP_MAX_DATA_LINK; xx++) { if ((nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_IN_USE) && (nfa_p2p_cb.conn_cb[xx].local_sap == local_sap) && (nfa_p2p_cb.conn_cb[xx].remote_sap == remote_sap)) { return (xx); } } return (LLCP_MAX_DATA_LINK); } /******************************************************************************* ** ** Function nfa_p2p_llcp_cback ** ** Description Processing SAP callback events from LLCP ** ** ** Returns None ** *******************************************************************************/ static void nfa_p2p_llcp_cback(tLLCP_SAP_CBACK_DATA* p_data) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event:0x%02X, local_sap:0x%02X", p_data->hdr.event, p_data->hdr.local_sap); switch (p_data->hdr.event) { case LLCP_SAP_EVT_DATA_IND: nfa_p2p_proc_llcp_data_ind(p_data); break; case LLCP_SAP_EVT_CONNECT_IND: nfa_p2p_proc_llcp_connect_ind(p_data); break; case LLCP_SAP_EVT_CONNECT_RESP: nfa_p2p_proc_llcp_connect_resp(p_data); break; case LLCP_SAP_EVT_DISCONNECT_IND: nfa_p2p_proc_llcp_disconnect_ind(p_data); break; case LLCP_SAP_EVT_DISCONNECT_RESP: nfa_p2p_proc_llcp_disconnect_resp(p_data); break; case LLCP_SAP_EVT_CONGEST: nfa_p2p_proc_llcp_congestion(p_data); break; case LLCP_SAP_EVT_LINK_STATUS: nfa_p2p_proc_llcp_link_status(p_data); break; default: LOG(ERROR) << StringPrintf("Unknown event:0x%02X", p_data->hdr.event); return; } } /******************************************************************************* ** ** Function nfa_p2p_sdp_cback ** ** Description Process SDP callback event from LLCP ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_sdp_cback(uint8_t tid, uint8_t remote_sap) { uint8_t local_sap; uint8_t xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("tid:0x%02X, remote_sap:0x%02X", tid, remote_sap); /* search for callback function to process */ for (xx = 0; xx < LLCP_MAX_SDP_TRANSAC; xx++) { if ((nfa_p2p_cb.sdp_cb[xx].local_sap != LLCP_INVALID_SAP) && (nfa_p2p_cb.sdp_cb[xx].tid == tid)) { local_sap = nfa_p2p_cb.sdp_cb[xx].local_sap; evt_data.sdp.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.sdp.remote_sap = remote_sap; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_SDP_EVT, &evt_data); nfa_p2p_cb.sdp_cb[xx].local_sap = LLCP_INVALID_SAP; break; } } } /******************************************************************************* ** ** Function nfa_p2p_start_sdp ** ** Description Initiate SDP ** ** ** Returns TRUE if success ** *******************************************************************************/ bool nfa_p2p_start_sdp(char* p_service_name, uint8_t local_sap) { int xx; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("SN:<%s>", p_service_name); /* search for empty slot */ for (xx = 0; xx < LLCP_MAX_SDP_TRANSAC; xx++) { if (nfa_p2p_cb.sdp_cb[xx].local_sap == LLCP_INVALID_SAP) { if (LLCP_DiscoverService(p_service_name, nfa_p2p_sdp_cback, &(nfa_p2p_cb.sdp_cb[xx].tid)) == LLCP_STATUS_SUCCESS) { nfa_p2p_cb.sdp_cb[xx].local_sap = local_sap; return true; } else { /* failure of SDP */ return false; } } } return false; } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_data_ind ** ** Description Processing incoming data event from LLCP ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_data_ind(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = p_data->data_ind.local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { evt_data.data.handle = 0; /* if connectionless */ if (p_data->data_ind.link_type == NFA_P2P_LLINK_TYPE) { evt_data.data.handle = (NFA_HANDLE_GROUP_P2P | local_sap); } else { xx = nfa_p2p_find_conn_cb(p_data->data_ind.local_sap, p_data->data_ind.remote_sap); if (xx != LLCP_MAX_DATA_LINK) { evt_data.data.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); } } evt_data.data.remote_sap = p_data->data_ind.remote_sap; evt_data.data.link_type = p_data->data_ind.link_type; /* notify upper layer that there are data at LLCP */ nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DATA_EVT, &evt_data); } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_connect_ind ** ** Description Processing connection request from peer ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_connect_ind(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t server_sap, local_sap; tNFA_P2P_EVT_DATA evt_data; uint8_t xx; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("server_sap:0x%x", p_data->connect_ind.server_sap); server_sap = p_data->connect_ind.server_sap; local_sap = p_data->connect_ind.local_sap; if (nfa_p2p_cb.sap_cb[server_sap].p_cback) { xx = nfa_p2p_allocate_conn_cb(server_sap); if (xx != LLCP_MAX_DATA_LINK) { nfa_p2p_cb.conn_cb[xx].remote_sap = p_data->connect_ind.remote_sap; nfa_p2p_cb.conn_cb[xx].remote_miu = p_data->connect_ind.miu; /* peer will not receive any data */ if (p_data->connect_ind.rw == 0) nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_REMOTE_RW_ZERO; evt_data.conn_req.server_handle = (NFA_HANDLE_GROUP_P2P | server_sap); evt_data.conn_req.conn_handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.conn_req.remote_sap = p_data->connect_ind.remote_sap; evt_data.conn_req.remote_miu = p_data->connect_ind.miu; evt_data.conn_req.remote_rw = p_data->connect_ind.rw; nfa_p2p_cb.sap_cb[server_sap].p_cback(NFA_P2P_CONN_REQ_EVT, &evt_data); } } else { LOG(ERROR) << StringPrintf("Not registered"); } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_connect_resp ** ** Description Processing connection response from peer ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_connect_resp(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = p_data->connect_resp.local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { xx = nfa_p2p_allocate_conn_cb(local_sap); if (xx != LLCP_MAX_DATA_LINK) { nfa_p2p_cb.conn_cb[xx].remote_sap = p_data->connect_resp.remote_sap; nfa_p2p_cb.conn_cb[xx].remote_miu = p_data->connect_resp.miu; /* peer will not receive any data */ if (p_data->connect_resp.rw == 0) nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_REMOTE_RW_ZERO; evt_data.connected.client_handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.connected.conn_handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.connected.remote_sap = p_data->connect_resp.remote_sap; evt_data.connected.remote_miu = p_data->connect_resp.miu; evt_data.connected.remote_rw = p_data->connect_resp.rw; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONNECTED_EVT, &evt_data); } } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_disconnect_ind ** ** Description Processing disconnection request from peer ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_disconnect_ind(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = p_data->disconnect_ind.local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { xx = nfa_p2p_find_conn_cb(p_data->disconnect_ind.local_sap, p_data->disconnect_ind.remote_sap); if (xx != LLCP_MAX_DATA_LINK) { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.disc.reason = NFA_P2P_DISC_REASON_REMOTE_INITIATE; nfa_p2p_deallocate_conn_cb(xx); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } else { /* ** LLCP link has been deactivated before receiving CC or DM. ** Return NFA_P2P_DISC_EVT to indicate failure of creating ** connection */ evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.disc.reason = NFA_P2P_DISC_REASON_LLCP_DEACTIVATED; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); LOG(ERROR) << StringPrintf("Link deactivated"); } } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_disconnect_resp ** ** Description Processing rejected connection from peer ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_disconnect_resp(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = p_data->disconnect_resp.local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { if (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_RESP_DISC) { evt_data.disc.reason = NFA_P2P_DISC_REASON_LOCAL_INITITATE; } else if ((p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_APP_REJECTED) || (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_PERM_REJECT_THIS) || (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_PERM_REJECT_ANY) || (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_TEMP_REJECT_THIS) || (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_TEMP_REJECT_ANY)) { evt_data.disc.reason = NFA_P2P_DISC_REASON_REMOTE_REJECT; } else if (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_NO_SERVICE) { evt_data.disc.reason = NFA_P2P_DISC_REASON_NO_SERVICE; } else if (p_data->disconnect_resp.reason == LLCP_SAP_DM_REASON_NO_ACTIVE_CONNECTION) { evt_data.disc.reason = NFA_P2P_DISC_REASON_LLCP_DEACTIVATED; } else { evt_data.disc.reason = NFA_P2P_DISC_REASON_NO_INFORMATION; } if (evt_data.disc.reason == NFA_P2P_DISC_REASON_LOCAL_INITITATE) { xx = nfa_p2p_find_conn_cb(p_data->disconnect_resp.local_sap, p_data->disconnect_resp.remote_sap); if (xx != LLCP_MAX_DATA_LINK) { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); nfa_p2p_deallocate_conn_cb(xx); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } else { LOG(ERROR) << StringPrintf("No connection found"); } } else { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | local_sap); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_congest ** ** Description Processing LLCP congestion event ** ** ** Returns None ** *******************************************************************************/ void nfa_p2p_proc_llcp_congestion(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, remote_sap, xx; tNFA_P2P_EVT_DATA evt_data; local_sap = p_data->congest.local_sap; remote_sap = p_data->congest.remote_sap; evt_data.congest.link_type = p_data->congest.link_type; evt_data.congest.is_congested = p_data->congest.is_congested; if (p_data->congest.is_congested) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("START SAP=(0x%x,0x%x)", local_sap, remote_sap); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("END SAP=(0x%x,0x%x)", local_sap, remote_sap); } if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { if (evt_data.congest.link_type == NFA_P2P_LLINK_TYPE) { evt_data.congest.handle = (NFA_HANDLE_GROUP_P2P | local_sap); if ((evt_data.congest.is_congested == false) && (nfa_p2p_cb.sap_cb[local_sap].flags & NFA_P2P_SAP_FLAG_LLINK_CONGESTED)) { nfa_p2p_cb.sap_cb[local_sap].flags &= ~NFA_P2P_SAP_FLAG_LLINK_CONGESTED; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONGEST_EVT, &evt_data); } else if ((evt_data.congest.is_congested == true) && (!(nfa_p2p_cb.sap_cb[local_sap].flags & NFA_P2P_SAP_FLAG_LLINK_CONGESTED))) { /* this is overall congestion due to high usage of buffer pool */ nfa_p2p_cb.sap_cb[local_sap].flags |= NFA_P2P_SAP_FLAG_LLINK_CONGESTED; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONGEST_EVT, &evt_data); } } else { xx = nfa_p2p_find_conn_cb(local_sap, remote_sap); if (xx != LLCP_MAX_DATA_LINK) { evt_data.congest.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); if ((evt_data.congest.is_congested == false) && (nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_CONGESTED)) { nfa_p2p_cb.conn_cb[xx].flags &= ~NFA_P2P_CONN_FLAG_CONGESTED; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONGEST_EVT, &evt_data); } else if ((evt_data.congest.is_congested == true) && (!(nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_CONGESTED))) { /* this is overall congestion due to high usage of buffer pool */ nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_CONGESTED; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONGEST_EVT, &evt_data); } } else { LOG(ERROR) << StringPrintf("No connection found"); } } } } /******************************************************************************* ** ** Function nfa_p2p_proc_llcp_link_status ** ** Description Processing LLCP link status ** ** ** Returns next state after processing this event ** *******************************************************************************/ void nfa_p2p_proc_llcp_link_status(tLLCP_SAP_CBACK_DATA* p_data) { uint8_t local_sap, xx; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("is_activated:%d", p_data->link_status.is_activated); local_sap = p_data->link_status.local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { if (p_data->link_status.is_activated) { /* only for server */ evt_data.activated.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.activated.local_link_miu = nfa_p2p_cb.local_link_miu; evt_data.activated.remote_link_miu = nfa_p2p_cb.remote_link_miu; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_ACTIVATED_EVT, &evt_data); } else /* if LLCP link is deactivated */ { for (xx = 0; xx < LLCP_MAX_DATA_LINK; xx++) { if ((nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_IN_USE) && (nfa_p2p_cb.conn_cb[xx].local_sap == local_sap)) { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.disc.reason = NFA_P2P_DISC_REASON_LLCP_DEACTIVATED; nfa_p2p_deallocate_conn_cb(xx); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } } /* notify deactivation and clear flags */ if (nfa_p2p_cb.sap_cb[local_sap].flags & NFA_P2P_SAP_FLAG_SERVER) { evt_data.deactivated.handle = (NFA_HANDLE_GROUP_P2P | local_sap); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DEACTIVATED_EVT, &evt_data); nfa_p2p_cb.sap_cb[local_sap].flags = NFA_P2P_SAP_FLAG_SERVER; } else if (nfa_p2p_cb.sap_cb[local_sap].flags & NFA_P2P_SAP_FLAG_CLIENT) { evt_data.deactivated.handle = (NFA_HANDLE_GROUP_P2P | local_sap); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DEACTIVATED_EVT, &evt_data); nfa_p2p_cb.sap_cb[local_sap].flags = NFA_P2P_SAP_FLAG_CLIENT; } else /* if this is not registered service */ { nfa_p2p_cb.sap_cb[local_sap].p_cback = NULL; } } } } /******************************************************************************* ** ** Function nfa_p2p_reg_server ** ** Description Allocate a service as server and register to LLCP ** ** ** Returns FALSE if need to keep buffer ** *******************************************************************************/ bool nfa_p2p_reg_server(tNFA_P2P_MSG* p_msg) { tNFA_P2P_EVT_DATA evt_data; uint8_t server_sap; DLOG_IF(INFO, nfc_debug_enabled) << __func__; server_sap = LLCP_RegisterServer( p_msg->api_reg_server.server_sap, p_msg->api_reg_server.link_type, p_msg->api_reg_server.service_name, nfa_p2p_llcp_cback); if (server_sap == LLCP_INVALID_SAP) { evt_data.reg_server.server_handle = NFA_HANDLE_INVALID; evt_data.reg_server.server_sap = NFA_P2P_INVALID_SAP; strncpy(evt_data.reg_server.service_name, p_msg->api_reg_server.service_name, LLCP_MAX_SN_LEN); evt_data.reg_server.service_name[LLCP_MAX_SN_LEN] = 0; p_msg->api_reg_server.p_cback(NFA_P2P_REG_SERVER_EVT, &evt_data); return true; } /* if need to update WKS in LLCP Gen bytes */ if (server_sap <= LLCP_UPPER_BOUND_WK_SAP) { nfa_p2p_enable_listening(NFA_ID_P2P, true); } else if (!nfa_p2p_cb.is_p2p_listening) { nfa_p2p_enable_listening(NFA_ID_P2P, false); } nfa_p2p_cb.sap_cb[server_sap].p_cback = p_msg->api_reg_server.p_cback; nfa_p2p_cb.sap_cb[server_sap].flags = NFA_P2P_SAP_FLAG_SERVER; evt_data.reg_server.server_handle = (NFA_HANDLE_GROUP_P2P | server_sap); evt_data.reg_server.server_sap = server_sap; strncpy(evt_data.reg_server.service_name, p_msg->api_reg_server.service_name, LLCP_MAX_SN_LEN); evt_data.reg_server.service_name[LLCP_MAX_SN_LEN] = 0; /* notify NFA_P2P_REG_SERVER_EVT to server */ nfa_p2p_cb.sap_cb[server_sap].p_cback(NFA_P2P_REG_SERVER_EVT, &evt_data); /* if LLCP is already activated */ if (nfa_p2p_cb.llcp_state == NFA_P2P_LLCP_STATE_ACTIVATED) { evt_data.activated.handle = (NFA_HANDLE_GROUP_P2P | server_sap); evt_data.activated.local_link_miu = nfa_p2p_cb.local_link_miu; evt_data.activated.remote_link_miu = nfa_p2p_cb.remote_link_miu; /* notify NFA_P2P_ACTIVATED_EVT to server */ nfa_p2p_cb.sap_cb[server_sap].p_cback(NFA_P2P_ACTIVATED_EVT, &evt_data); } return true; } /******************************************************************************* ** ** Function nfa_p2p_reg_client ** ** Description Allocate a service as client and register to LLCP ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_reg_client(tNFA_P2P_MSG* p_msg) { tNFA_P2P_EVT_DATA evt_data; uint8_t local_sap; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = LLCP_RegisterClient(p_msg->api_reg_client.link_type, nfa_p2p_llcp_cback); if (local_sap == LLCP_INVALID_SAP) { evt_data.reg_client.client_handle = NFA_HANDLE_INVALID; p_msg->api_reg_client.p_cback(NFA_P2P_REG_CLIENT_EVT, &evt_data); return true; } nfa_p2p_cb.sap_cb[local_sap].p_cback = p_msg->api_reg_client.p_cback; nfa_p2p_cb.sap_cb[local_sap].flags = NFA_P2P_SAP_FLAG_CLIENT; evt_data.reg_client.client_handle = (NFA_HANDLE_GROUP_P2P | local_sap); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_REG_CLIENT_EVT, &evt_data); /* if LLCP is already activated */ if (nfa_p2p_cb.llcp_state == NFA_P2P_LLCP_STATE_ACTIVATED) { evt_data.activated.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.activated.local_link_miu = nfa_p2p_cb.local_link_miu; evt_data.activated.remote_link_miu = nfa_p2p_cb.remote_link_miu; /* notify NFA_P2P_ACTIVATED_EVT to client */ nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_ACTIVATED_EVT, &evt_data); } return true; } /******************************************************************************* ** ** Function nfa_p2p_dereg ** ** Description Deallocate a service as server or client and deregister to ** LLCP. LLCP will deallocate data link connection created by ** this server ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_dereg(tNFA_P2P_MSG* p_msg) { uint8_t local_sap, xx; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = (uint8_t)(p_msg->api_dereg.handle & NFA_HANDLE_MASK); if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { for (xx = 0; xx < LLCP_MAX_DATA_LINK; xx++) { if ((nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_IN_USE) && (nfa_p2p_cb.conn_cb[xx].local_sap == local_sap)) { nfa_p2p_deallocate_conn_cb(xx); } } } LLCP_Deregister(local_sap); nfa_p2p_cb.sap_cb[local_sap].p_cback = NULL; if (nfa_p2p_cb.is_p2p_listening) { /* check if this is the last server on NFA P2P */ for (xx = 0; xx < NFA_P2P_NUM_SAP; xx++) { if ((nfa_p2p_cb.sap_cb[xx].p_cback) && (nfa_p2p_cb.sap_cb[xx].flags & NFA_P2P_SAP_FLAG_SERVER)) { break; } } if (xx >= NFA_P2P_NUM_SAP) { /* if need to update WKS in LLCP Gen bytes */ if (local_sap <= LLCP_UPPER_BOUND_WK_SAP) nfa_p2p_disable_listening(NFA_ID_P2P, true); else nfa_p2p_disable_listening(NFA_ID_P2P, false); } /* if need to update WKS in LLCP Gen bytes */ else if (local_sap <= LLCP_UPPER_BOUND_WK_SAP) { nfa_p2p_enable_listening(NFA_ID_P2P, true); } } return true; } /******************************************************************************* ** ** Function nfa_p2p_accept_connection ** ** Description Connection Confirm from local application ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_accept_connection(tNFA_P2P_MSG* p_msg) { uint8_t xx; tLLCP_CONNECTION_PARAMS params; DLOG_IF(INFO, nfc_debug_enabled) << __func__; xx = (uint8_t)(p_msg->api_accept.conn_handle & NFA_HANDLE_MASK); xx &= ~NFA_P2P_HANDLE_FLAG_CONN; params.miu = p_msg->api_accept.miu; params.rw = p_msg->api_accept.rw; params.sn[0] = 0; LLCP_ConnectCfm(nfa_p2p_cb.conn_cb[xx].local_sap, nfa_p2p_cb.conn_cb[xx].remote_sap, ¶ms); return true; } /******************************************************************************* ** ** Function nfa_p2p_reject_connection ** ** Description Reject connection by local application ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_reject_connection(tNFA_P2P_MSG* p_msg) { uint8_t xx; DLOG_IF(INFO, nfc_debug_enabled) << __func__; xx = (uint8_t)(p_msg->api_reject.conn_handle & NFA_HANDLE_MASK); xx &= ~NFA_P2P_HANDLE_FLAG_CONN; LLCP_ConnectReject(nfa_p2p_cb.conn_cb[xx].local_sap, nfa_p2p_cb.conn_cb[xx].remote_sap, LLCP_SAP_DM_REASON_APP_REJECTED); /* no need to deregister service on LLCP */ nfa_p2p_deallocate_conn_cb(xx); return true; } /******************************************************************************* ** ** Function nfa_p2p_disconnect ** ** Description Disconnect data link connection by local application ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_disconnect(tNFA_P2P_MSG* p_msg) { uint8_t local_sap, xx; tLLCP_STATUS status; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; xx = (uint8_t)(p_msg->api_disconnect.conn_handle & NFA_HANDLE_MASK); /* if this is for data link connection */ if (xx & NFA_P2P_HANDLE_FLAG_CONN) { xx &= ~NFA_P2P_HANDLE_FLAG_CONN; status = LLCP_DisconnectReq(nfa_p2p_cb.conn_cb[xx].local_sap, nfa_p2p_cb.conn_cb[xx].remote_sap, p_msg->api_disconnect.flush); if (status == LLCP_STATUS_SUCCESS) { /* wait for disconnect response if successful */ return true; } else { /* ** while we are waiting for connect confirm, ** we cannot sent DISC because we don't know DSAP yet */ local_sap = nfa_p2p_cb.conn_cb[xx].local_sap; if (nfa_p2p_cb.sap_cb[local_sap].p_cback) { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.disc.reason = NFA_P2P_DISC_REASON_LOCAL_INITITATE; nfa_p2p_deallocate_conn_cb(xx); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } } } else { LOG(ERROR) << StringPrintf("Handle is not for Data link connection"); } return true; } /******************************************************************************* ** ** Function nfa_p2p_create_data_link_connection ** ** Description Create data link connection ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_create_data_link_connection(tNFA_P2P_MSG* p_msg) { uint8_t local_sap; tNFA_P2P_EVT_DATA evt_data; tLLCP_CONNECTION_PARAMS conn_params; tLLCP_STATUS status; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = (uint8_t)(p_msg->api_connect.client_handle & NFA_HANDLE_MASK); conn_params.miu = p_msg->api_connect.miu; conn_params.rw = p_msg->api_connect.rw; /* NFA_P2pConnectBySap () */ if (p_msg->api_connect.dsap != LLCP_INVALID_SAP) { conn_params.sn[0] = 0; status = LLCP_ConnectReq(local_sap, p_msg->api_connect.dsap, &conn_params); } /* NFA_P2pConnectByName () */ else { strncpy(conn_params.sn, p_msg->api_connect.service_name, LLCP_MAX_SN_LEN); conn_params.sn[LLCP_MAX_SN_LEN] = 0; status = LLCP_ConnectReq(local_sap, LLCP_SAP_SDP, &conn_params); } if (status != LLCP_STATUS_SUCCESS) { evt_data.disc.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.disc.reason = NFA_P2P_DISC_REASON_NO_INFORMATION; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_DISC_EVT, &evt_data); } return true; } /******************************************************************************* ** ** Function nfa_p2p_send_ui ** ** Description Send UI PDU ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_send_ui(tNFA_P2P_MSG* p_msg) { uint8_t local_sap; tLLCP_STATUS status; tNFA_P2P_EVT_DATA evt_data; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = (uint8_t)(p_msg->api_send_ui.handle & NFA_HANDLE_MASK); /* decrease number of tx UI PDU which is not processed by NFA for congestion * control */ if (nfa_p2p_cb.sap_cb[local_sap].num_pending_ui_pdu) nfa_p2p_cb.sap_cb[local_sap].num_pending_ui_pdu--; if (nfa_p2p_cb.total_pending_ui_pdu) nfa_p2p_cb.total_pending_ui_pdu--; status = LLCP_SendUI(local_sap, p_msg->api_send_ui.dsap, p_msg->api_send_ui.p_msg); if (status == LLCP_STATUS_CONGESTED) { if (!(nfa_p2p_cb.sap_cb[local_sap].flags & NFA_P2P_SAP_FLAG_LLINK_CONGESTED)) { nfa_p2p_cb.sap_cb[local_sap].flags |= NFA_P2P_SAP_FLAG_LLINK_CONGESTED; /* notify that this logical link is congested */ evt_data.congest.link_type = NFA_P2P_LLINK_TYPE; evt_data.congest.handle = (NFA_HANDLE_GROUP_P2P | local_sap); evt_data.congest.is_congested = true; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_CONGEST_EVT, &evt_data); } } return true; } /******************************************************************************* ** ** Function nfa_p2p_send_data ** ** Description Send I PDU ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_send_data(tNFA_P2P_MSG* p_msg) { tNFA_P2P_EVT_DATA evt_data; tLLCP_STATUS status; uint8_t xx; DLOG_IF(INFO, nfc_debug_enabled) << __func__; xx = (uint8_t)(p_msg->api_send_data.conn_handle & NFA_HANDLE_MASK); xx &= ~NFA_P2P_HANDLE_FLAG_CONN; /* decrease number of tx I PDU which is not processed by NFA for congestion * control */ if (nfa_p2p_cb.conn_cb[xx].num_pending_i_pdu) nfa_p2p_cb.conn_cb[xx].num_pending_i_pdu--; if (nfa_p2p_cb.total_pending_i_pdu) nfa_p2p_cb.total_pending_i_pdu--; status = LLCP_SendData(nfa_p2p_cb.conn_cb[xx].local_sap, nfa_p2p_cb.conn_cb[xx].remote_sap, p_msg->api_send_data.p_msg); if (status == LLCP_STATUS_CONGESTED) { if (!(nfa_p2p_cb.conn_cb[xx].flags & NFA_P2P_CONN_FLAG_CONGESTED)) { nfa_p2p_cb.conn_cb[xx].flags |= NFA_P2P_CONN_FLAG_CONGESTED; /* notify that this data link is congested */ evt_data.congest.link_type = NFA_P2P_DLINK_TYPE; evt_data.congest.handle = (NFA_HANDLE_GROUP_P2P | NFA_P2P_HANDLE_FLAG_CONN | xx); evt_data.congest.is_congested = true; nfa_p2p_cb.sap_cb[nfa_p2p_cb.conn_cb[xx].local_sap].p_cback( NFA_P2P_CONGEST_EVT, &evt_data); } } return true; } /******************************************************************************* ** ** Function nfa_p2p_set_local_busy ** ** Description Set or reset local busy ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_set_local_busy(tNFA_P2P_MSG* p_msg) { uint8_t xx; DLOG_IF(INFO, nfc_debug_enabled) << __func__; xx = (uint8_t)(p_msg->api_local_busy.conn_handle & NFA_HANDLE_MASK); xx &= ~NFA_P2P_HANDLE_FLAG_CONN; LLCP_SetLocalBusyStatus(nfa_p2p_cb.conn_cb[xx].local_sap, nfa_p2p_cb.conn_cb[xx].remote_sap, p_msg->api_local_busy.is_busy); return true; } /******************************************************************************* ** ** Function nfa_p2p_get_link_info ** ** Description Get WKS of remote and link MIU ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_get_link_info(tNFA_P2P_MSG* p_msg) { tNFA_P2P_EVT_DATA evt_data; uint8_t local_sap; DLOG_IF(INFO, nfc_debug_enabled) << __func__; evt_data.link_info.handle = p_msg->api_link_info.handle; evt_data.link_info.wks = LLCP_GetRemoteWKS(); evt_data.link_info.local_link_miu = nfa_p2p_cb.local_link_miu; evt_data.link_info.remote_link_miu = nfa_p2p_cb.remote_link_miu; local_sap = (uint8_t)(p_msg->api_link_info.handle & NFA_HANDLE_MASK); nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_LINK_INFO_EVT, &evt_data); return true; } /******************************************************************************* ** ** Function nfa_p2p_get_remote_sap ** ** Description Get remote SAP ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_get_remote_sap(tNFA_P2P_MSG* p_msg) { tNFA_P2P_EVT_DATA evt_data; uint8_t local_sap; DLOG_IF(INFO, nfc_debug_enabled) << __func__; local_sap = (uint8_t)(p_msg->api_remote_sap.handle & NFA_HANDLE_MASK); if (!nfa_p2p_start_sdp(p_msg->api_remote_sap.service_name, local_sap)) { evt_data.sdp.handle = p_msg->api_remote_sap.handle; evt_data.sdp.remote_sap = 0x00; nfa_p2p_cb.sap_cb[local_sap].p_cback(NFA_P2P_SDP_EVT, &evt_data); } return true; } /******************************************************************************* ** ** Function nfa_p2p_set_llcp_cfg ** ** Description Set LLCP configuration ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_set_llcp_cfg(tNFA_P2P_MSG* p_msg) { LLCP_SetConfig(p_msg->api_set_llcp_cfg.link_miu, p_msg->api_set_llcp_cfg.opt, p_msg->api_set_llcp_cfg.wt, p_msg->api_set_llcp_cfg.link_timeout, p_msg->api_set_llcp_cfg.inact_timeout_init, p_msg->api_set_llcp_cfg.inact_timeout_target, p_msg->api_set_llcp_cfg.symm_delay, p_msg->api_set_llcp_cfg.data_link_timeout, p_msg->api_set_llcp_cfg.delay_first_pdu_timeout); return true; } /******************************************************************************* ** ** Function nfa_p2p_restart_rf_discovery ** ** Description Restart RF discovery by deactivating to IDLE ** ** ** Returns TRUE to deallocate buffer ** *******************************************************************************/ bool nfa_p2p_restart_rf_discovery(__attribute__((unused)) tNFA_P2P_MSG* p_msg) { DLOG_IF(INFO, nfc_debug_enabled) << __func__; nfa_dm_rf_deactivate(NFA_DEACTIVATE_TYPE_IDLE); return true; }