diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-12-12 16:00:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-12-12 16:00:35 -0800 |
commit | 5738f83aeb59361a0a2eda2460113f6dc9194271 (patch) | |
tree | bf9fb1c890a681253207fe5d48e2cd56b94de3a7 /stack/pan | |
download | android_system_bt-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.gz android_system_bt-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.bz2 android_system_bt-5738f83aeb59361a0a2eda2460113f6dc9194271.zip |
Snapshot cdeccf6fdd8c2d494ea2867cb37a025bf8879baf
Change-Id: Ia2de32ccb97a9641462c72363b0a8c4288f4f36d
Diffstat (limited to 'stack/pan')
-rw-r--r-- | stack/pan/pan_api.c | 853 | ||||
-rw-r--r-- | stack/pan/pan_int.h | 158 | ||||
-rw-r--r-- | stack/pan/pan_main.c | 730 | ||||
-rw-r--r-- | stack/pan/pan_utils.c | 351 |
4 files changed, 2092 insertions, 0 deletions
diff --git a/stack/pan/pan_api.c b/stack/pan/pan_api.c new file mode 100644 index 000000000..6aa24b9c6 --- /dev/null +++ b/stack/pan/pan_api.c @@ -0,0 +1,853 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 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 file contains main functions to support PAN profile + * commands and events. + * + *****************************************************************************/ + +#include <string.h> +#include "gki.h" +#include "bt_types.h" +#include "bnep_api.h" +#include "pan_api.h" +#include "pan_int.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "l2c_api.h" +#include "hcidefs.h" +#include "btm_api.h" + + +/******************************************************************************* +** +** Function PAN_Register +** +** Description This function is called by the application to register +** its callbacks with PAN profile. The application then +** should set the PAN role explicitly. +** +** Parameters: p_register - contains all callback function pointers +** +** +** Returns none +** +*******************************************************************************/ +void PAN_Register (tPAN_REGISTER *p_register) +{ + BTM_SetDiscoverability (BTM_GENERAL_DISCOVERABLE, 0, 0); + BTM_SetConnectability (BTM_CONNECTABLE, 0, 0); + + pan_register_with_bnep (); + + if (!p_register) + return; + + pan_cb.pan_conn_state_cb = p_register->pan_conn_state_cb; + pan_cb.pan_bridge_req_cb = p_register->pan_bridge_req_cb; + pan_cb.pan_data_buf_ind_cb = p_register->pan_data_buf_ind_cb; + pan_cb.pan_data_ind_cb = p_register->pan_data_ind_cb; + pan_cb.pan_pfilt_ind_cb = p_register->pan_pfilt_ind_cb; + pan_cb.pan_mfilt_ind_cb = p_register->pan_mfilt_ind_cb; + pan_cb.pan_tx_data_flow_cb = p_register->pan_tx_data_flow_cb; + + return; +} + + + +/******************************************************************************* +** +** Function PAN_Deregister +** +** Description This function is called by the application to de-register +** its callbacks with PAN profile. This will make the PAN to +** become inactive. This will deregister PAN services from SDP +** and close all active connections +** +** Parameters: none +** +** +** Returns none +** +*******************************************************************************/ +void PAN_Deregister (void) +{ + pan_cb.pan_bridge_req_cb = NULL; + pan_cb.pan_data_buf_ind_cb = NULL; + pan_cb.pan_data_ind_cb = NULL; + pan_cb.pan_conn_state_cb = NULL; + pan_cb.pan_pfilt_ind_cb = NULL; + pan_cb.pan_mfilt_ind_cb = NULL; + + PAN_SetRole (PAN_ROLE_INACTIVE, NULL, NULL, NULL, NULL); + BNEP_Deregister (); + + return; +} + + + + +/******************************************************************************* +** +** Function PAN_SetRole +** +** Description This function is called by the application to set the PAN +** profile role. This should be called after PAN_Register. +** This can be called any time to change the PAN role +** +** Parameters: role - is bit map of roles to be active +** PAN_ROLE_CLIENT is for PANU role +** PAN_ROLE_GN_SERVER is for GN role +** PAN_ROLE_NAP_SERVER is for NAP role +** sec_mask - Security mask for different roles +** It is array of UINT8. The byte represent the +** security for roles PANU, GN and NAP in order +** p_user_name - Service name for PANU role +** p_gn_name - Service name for GN role +** p_nap_name - Service name for NAP role +** Can be NULL if user wants it to be default +** +** Returns PAN_SUCCESS - if the role is set successfully +** PAN_FAILURE - if the role is not valid +** +*******************************************************************************/ +tPAN_RESULT PAN_SetRole (UINT8 role, + UINT8 *sec_mask, + char *p_user_name, + char *p_gn_name, + char *p_nap_name) +{ + char *p_desc; + UINT8 security[3] = {PAN_PANU_SECURITY_LEVEL, + PAN_GN_SECURITY_LEVEL, + PAN_NAP_SECURITY_LEVEL}; + UINT8 *p_sec; + + /* If the role is not a valid combination reject it */ + if ((!(role & (PAN_ROLE_CLIENT | PAN_ROLE_GN_SERVER | PAN_ROLE_NAP_SERVER))) && + role != PAN_ROLE_INACTIVE) + { + PAN_TRACE_ERROR1 ("PAN role %d is invalid", role); + return PAN_FAILURE; + } + + /* If the current active role is same as the role being set do nothing */ + if (pan_cb.role == role) + { + PAN_TRACE_EVENT1 ("PAN role already was set to: %d", role); + return PAN_SUCCESS; + } + + if (!sec_mask) + p_sec = security; + else + p_sec = sec_mask; + + /* Register all the roles with SDP */ + PAN_TRACE_API1 ("PAN_SetRole() called with role 0x%x", role); +#if (defined (PAN_SUPPORTS_ROLE_NAP) && PAN_SUPPORTS_ROLE_NAP == TRUE) + /* Check the service name */ + if ((p_nap_name == NULL) || (*p_nap_name == 0)) + p_nap_name = PAN_NAP_DEFAULT_SERVICE_NAME; + + if (role & PAN_ROLE_NAP_SERVER) + { + /* Registering for NAP service with SDP */ + p_desc = PAN_NAP_DEFAULT_DESCRIPTION; + + if (pan_cb.pan_nap_sdp_handle != 0) + SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle); + + pan_cb.pan_nap_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_NAP, p_sec[2], p_nap_name, p_desc); +// btla-specific ++ + bta_sys_add_uuid(UUID_SERVCLASS_NAP); +// btla-specific -- + } + /* If the NAP role is already active and now being cleared delete the record */ + else if (pan_cb.role & PAN_ROLE_NAP_SERVER) + { + if (pan_cb.pan_nap_sdp_handle != 0) + { + SDP_DeleteRecord (pan_cb.pan_nap_sdp_handle); + pan_cb.pan_nap_sdp_handle = 0; +// btla-specific ++ + bta_sys_remove_uuid(UUID_SERVCLASS_NAP); +// btla-specific -- + } + } +#endif + +#if (defined (PAN_SUPPORTS_ROLE_GN) && PAN_SUPPORTS_ROLE_GN == TRUE) + /* Check the service name */ + if ((p_gn_name == NULL) || (*p_gn_name == 0)) + p_gn_name = PAN_GN_DEFAULT_SERVICE_NAME; + + if (role & PAN_ROLE_GN_SERVER) + { + /* Registering for GN service with SDP */ + p_desc = PAN_GN_DEFAULT_DESCRIPTION; + + if (pan_cb.pan_gn_sdp_handle != 0) + SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle); + + pan_cb.pan_gn_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_GN, p_sec[1], p_gn_name, p_desc); +// btla-specific ++ + bta_sys_add_uuid(UUID_SERVCLASS_GN); +// btla-specific -- + } + /* If the GN role is already active and now being cleared delete the record */ + else if (pan_cb.role & PAN_ROLE_GN_SERVER) + { + if (pan_cb.pan_gn_sdp_handle != 0) + { + SDP_DeleteRecord (pan_cb.pan_gn_sdp_handle); + pan_cb.pan_gn_sdp_handle = 0; +// btla-specific ++ + bta_sys_remove_uuid(UUID_SERVCLASS_GN); +// btla-specific -- + } + } +#endif + +#if (defined (PAN_SUPPORTS_ROLE_PANU) && PAN_SUPPORTS_ROLE_PANU == TRUE) + /* Check the service name */ + if ((p_user_name == NULL) || (*p_user_name == 0)) + p_user_name = PAN_PANU_DEFAULT_SERVICE_NAME; + + if (role & PAN_ROLE_CLIENT) + { + /* Registering for PANU service with SDP */ + p_desc = PAN_PANU_DEFAULT_DESCRIPTION; + if (pan_cb.pan_user_sdp_handle != 0) + SDP_DeleteRecord (pan_cb.pan_user_sdp_handle); + + pan_cb.pan_user_sdp_handle = pan_register_with_sdp (UUID_SERVCLASS_PANU, p_sec[0], p_user_name, p_desc); +// btla-specific ++ + bta_sys_add_uuid(UUID_SERVCLASS_PANU); +// btla-specific -- + } + /* If the PANU role is already active and now being cleared delete the record */ + else if (pan_cb.role & PAN_ROLE_CLIENT) + { + if (pan_cb.pan_user_sdp_handle != 0) + { + SDP_DeleteRecord (pan_cb.pan_user_sdp_handle); + pan_cb.pan_user_sdp_handle = 0; +// btla-specific ++ + bta_sys_remove_uuid(UUID_SERVCLASS_PANU); +// btla-specific -- + } + } +#endif + + /* Check if it is a shutdown request */ + if (role == PAN_ROLE_INACTIVE) + pan_close_all_connections (); + + pan_cb.role = role; + PAN_TRACE_EVENT1 ("PAN role set to: %d", role); + return PAN_SUCCESS; +} + + + +/******************************************************************************* +** +** Function PAN_Connect +** +** Description This function is called by the application to initiate a +** connection to the remote device +** +** Parameters: rem_bda - BD Addr of the remote device +** src_role - Role of the local device for the connection +** dst_role - Role of the remote device for the connection +** PAN_ROLE_CLIENT is for PANU role +** PAN_ROLE_GN_SERVER is for GN role +** PAN_ROLE_NAP_SERVER is for NAP role +** *handle - Pointer for returning Handle to the connection +** +** Returns PAN_SUCCESS - if the connection is initiated successfully +** PAN_NO_RESOURCES - resources are not sufficent +** PAN_FAILURE - if the connection cannot be initiated +** this can be because of the combination of +** src and dst roles may not be valid or +** allowed at that point of time +** +*******************************************************************************/ +tPAN_RESULT PAN_Connect (BD_ADDR rem_bda, UINT8 src_role, UINT8 dst_role, UINT16 *handle) +{ + tPAN_CONN *pcb; + tBNEP_RESULT result; + tBT_UUID src_uuid, dst_uuid; + UINT8 service_id; + UINT32 mx_chan_id; + + /* + ** Initialize the handle so that in case of failure return values + ** the profile will not get confused + */ + *handle = BNEP_INVALID_HANDLE; + + /* Check if PAN is active or not */ + if (!(pan_cb.role & src_role)) + { + PAN_TRACE_ERROR1 ("PAN is not active for the role %d", src_role); + return PAN_FAILURE; + } + + /* Validate the parameters before proceeding */ + if ((src_role != PAN_ROLE_CLIENT && src_role != PAN_ROLE_GN_SERVER && src_role != PAN_ROLE_NAP_SERVER) || + (dst_role != PAN_ROLE_CLIENT && dst_role != PAN_ROLE_GN_SERVER && dst_role != PAN_ROLE_NAP_SERVER)) + { + PAN_TRACE_ERROR2 ("Either source %d or destination role %d is invalid", src_role, dst_role); + return PAN_FAILURE; + } + + /* Check if connection exists for this remote device */ + pcb = pan_get_pcb_by_addr (rem_bda); + + /* If we are PANU for this role validate destination role */ + if (src_role == PAN_ROLE_CLIENT) + { + if ((pan_cb.num_conns > 1) || (pan_cb.num_conns && (!pcb))) + { + /* + ** If the request is not for existing connection reject it + ** because if there is already a connection we cannot accept + ** another connection in PANU role + */ + PAN_TRACE_ERROR0 ("Cannot make PANU connections when there are more than one connection"); + return PAN_INVALID_SRC_ROLE; + } + + src_uuid.uu.uuid16 = UUID_SERVCLASS_PANU; + if (dst_role == PAN_ROLE_CLIENT) + { + service_id = BTM_SEC_SERVICE_BNEP_PANU; + dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU; + } + else if (dst_role == PAN_ROLE_GN_SERVER) + { + service_id = BTM_SEC_SERVICE_BNEP_GN; + dst_uuid.uu.uuid16 = UUID_SERVCLASS_GN; + } + else + { + service_id = BTM_SEC_SERVICE_BNEP_NAP; + dst_uuid.uu.uuid16 = UUID_SERVCLASS_NAP; + } + mx_chan_id = dst_uuid.uu.uuid16; + } + /* If destination is PANU role validate source role */ + else if (dst_role == PAN_ROLE_CLIENT) + { + if (pan_cb.num_conns && pan_cb.active_role == PAN_ROLE_CLIENT && !pcb) + { + PAN_TRACE_ERROR0 ("Device already have a connection in PANU role"); + return PAN_INVALID_SRC_ROLE; + } + + dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU; + if (src_role == PAN_ROLE_GN_SERVER) + { + service_id = BTM_SEC_SERVICE_BNEP_GN; + src_uuid.uu.uuid16 = UUID_SERVCLASS_GN; + } + else + { + service_id = BTM_SEC_SERVICE_BNEP_NAP; + src_uuid.uu.uuid16 = UUID_SERVCLASS_NAP; + } + mx_chan_id = src_uuid.uu.uuid16; + } + /* The role combination is not valid */ + else + { + PAN_TRACE_ERROR2 ("Source %d and Destination roles %d are not valid combination", + src_role, dst_role); + return PAN_FAILURE; + } + + /* Allocate control block and initiate connection */ + if (!pcb) + pcb = pan_allocate_pcb (rem_bda, BNEP_INVALID_HANDLE); + if (!pcb) + { + PAN_TRACE_ERROR0 ("PAN Connection failed because of no resources"); + return PAN_NO_RESOURCES; + } + BTM_SetOutService(rem_bda, BTM_SEC_SERVICE_BNEP_PANU, mx_chan_id); + + PAN_TRACE_API6 ("PAN_Connect() for BD Addr %x.%x.%x.%x.%x.%x", + rem_bda[0], rem_bda[1], rem_bda[2], rem_bda[3], rem_bda[4], rem_bda[5]); + if (pcb->con_state == PAN_STATE_IDLE) + { + pan_cb.num_conns++; + } + else if (pcb->con_state == PAN_STATE_CONNECTED) + { + pcb->con_flags |= PAN_FLAGS_CONN_COMPLETED; + } + else + /* PAN connection is still in progress */ + return PAN_WRONG_STATE; + + pcb->con_state = PAN_STATE_CONN_START; + pcb->prv_src_uuid = pcb->src_uuid; + pcb->prv_dst_uuid = pcb->dst_uuid; + + pcb->src_uuid = src_uuid.uu.uuid16; + pcb->dst_uuid = dst_uuid.uu.uuid16; + + src_uuid.len = 2; + dst_uuid.len = 2; + + result = BNEP_Connect (rem_bda, &src_uuid, &dst_uuid, &(pcb->handle)); + if (result != BNEP_SUCCESS) + { + pan_release_pcb (pcb); + return result; + } + + PAN_TRACE_DEBUG1 ("PAN_Connect() current active role set to %d", src_role); + pan_cb.prv_active_role = pan_cb.active_role; + pan_cb.active_role = src_role; + *handle = pcb->handle; + return PAN_SUCCESS; +} + + + + +/******************************************************************************* +** +** Function PAN_Disconnect +** +** Description This is used to disconnect the connection +** +** Parameters: handle - handle for the connection +** +** Returns PAN_SUCCESS - if the connection is closed successfully +** PAN_FAILURE - if the connection is not found or +** there is an error in disconnecting +** +*******************************************************************************/ +tPAN_RESULT PAN_Disconnect (UINT16 handle) +{ + tPAN_CONN *pcb; + tBNEP_RESULT result; + + /* Check if the connection exists */ + pcb = pan_get_pcb_by_handle (handle); + if(!pcb) + { + PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle); + return PAN_FAILURE; + } + + result = BNEP_Disconnect (pcb->handle); + if (pcb->con_state == PAN_STATE_CONNECTED) + pan_cb.num_conns--; + + if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP) + (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE); + + pan_release_pcb (pcb); + + if (result != BNEP_SUCCESS) + { + PAN_TRACE_EVENT0 ("Error in closing PAN connection"); + return PAN_FAILURE; + } + + PAN_TRACE_EVENT0 ("PAN connection closed"); + return PAN_SUCCESS; +} + + +/******************************************************************************* +** +** Function PAN_Write +** +** Description This sends data over the PAN connections. If this is called +** on GN or NAP side and the packet is multicast or broadcast +** it will be sent on all the links. Otherwise the correct link +** is found based on the destination address and forwarded on it +** If the return value is not PAN_SUCCESS the application should +** take care of releasing the message buffer +** +** Parameters: handle - handle for the connection +** dst - MAC or BD Addr of the destination device +** src - MAC or BD Addr of the source who sent this packet +** protocol - protocol of the ethernet packet like IP or ARP +** p_data - pointer to the data +** len - length of the data +** ext - to indicate that extension headers present +** +** Returns PAN_SUCCESS - if the data is sent successfully +** PAN_FAILURE - if the connection is not found or +** there is an error in sending data +** +*******************************************************************************/ +tPAN_RESULT PAN_Write (UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, UINT8 *p_data, UINT16 len, BOOLEAN ext) +{ + tPAN_CONN *pcb; + UINT16 i; + tBNEP_RESULT result; + + if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns))) + { + PAN_TRACE_ERROR0 ("PAN is not active Data write failed"); + return PAN_FAILURE; + } + + /* Check if it is broadcast or multicast packet */ + if (dst[0] & 0x01) + { + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED) + BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext); + } + + return PAN_SUCCESS; + } + + if (pan_cb.active_role == PAN_ROLE_CLIENT) + { + /* Data write is on PANU connection */ + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && + pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU) + break; + } + + if (i == MAX_PAN_CONNS) + { + PAN_TRACE_ERROR0 ("PAN Don't have any user connections"); + return PAN_FAILURE; + } + + result = BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext); + if (result == BNEP_IGNORE_CMD) + { + PAN_TRACE_DEBUG0 ("PAN ignored data for PANU connection"); + return result; + } + else if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR0 ("PAN failed to write data for the PANU connection"); + return result; + } + + PAN_TRACE_DEBUG0 ("PAN successfully wrote data for the PANU connection"); + return PAN_SUCCESS; + } + + pcb = pan_get_pcb_by_handle (handle); + if (!pcb) + { + PAN_TRACE_ERROR0 ("PAN Data write for wrong addr"); + return PAN_FAILURE; + } + + if (pcb->con_state != PAN_STATE_CONNECTED) + { + PAN_TRACE_ERROR0 ("PAN Data write when conn is not active"); + return PAN_FAILURE; + } + + result = BNEP_Write (pcb->handle, dst, p_data, len, protocol, src, ext); + if (result == BNEP_IGNORE_CMD) + { + PAN_TRACE_DEBUG0 ("PAN ignored data write to PANU"); + return result; + } + else if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR0 ("PAN failed to send data to the PANU"); + return result; + } + + PAN_TRACE_DEBUG0 ("PAN successfully sent data to the PANU"); + return PAN_SUCCESS; +} + + +/******************************************************************************* +** +** Function PAN_WriteBuf +** +** Description This sends data over the PAN connections. If this is called +** on GN or NAP side and the packet is multicast or broadcast +** it will be sent on all the links. Otherwise the correct link +** is found based on the destination address and forwarded on it +** If the return value is not PAN_SUCCESS the application should +** take care of releasing the message buffer +** +** Parameters: handle - handle for the connection +** dst - MAC or BD Addr of the destination device +** src - MAC or BD Addr of the source who sent this packet +** protocol - protocol of the ethernet packet like IP or ARP +** p_buf - pointer to the data buffer +** ext - to indicate that extension headers present +** +** Returns PAN_SUCCESS - if the data is sent successfully +** PAN_FAILURE - if the connection is not found or +** there is an error in sending data +** +*******************************************************************************/ +tPAN_RESULT PAN_WriteBuf (UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, BT_HDR *p_buf, BOOLEAN ext) +{ + tPAN_CONN *pcb; + UINT16 i; + tBNEP_RESULT result; + + /* Check if it is broadcast or multicast packet */ + if (dst[0] & 0x01) + { + UINT8 *p_data; + UINT16 len; + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + len = p_buf->len; + PAN_Write (handle, dst, src, protocol, p_data, len, ext); + GKI_freebuf (p_buf); + return PAN_SUCCESS; + } + + if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns))) + { + PAN_TRACE_ERROR0 ("PAN is not active Data write failed"); + GKI_freebuf (p_buf); + return PAN_FAILURE; + } + + /* Check if the data write is on PANU side */ + if (pan_cb.active_role == PAN_ROLE_CLIENT) + { + /* Data write is on PANU connection */ + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && + pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU) + break; + } + + if (i == MAX_PAN_CONNS) + { + PAN_TRACE_ERROR0 ("PAN Don't have any user connections"); + GKI_freebuf (p_buf); + return PAN_FAILURE; + } + + result = BNEP_WriteBuf (pan_cb.pcb[i].handle, dst, p_buf, protocol, src, ext); + if (result == BNEP_IGNORE_CMD) + { + PAN_TRACE_DEBUG0 ("PAN ignored data write for PANU connection"); + return result; + } + else if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR0 ("PAN failed to write data for the PANU connection"); + return result; + } + + PAN_TRACE_DEBUG0 ("PAN successfully wrote data for the PANU connection"); + return PAN_SUCCESS; + } + + /* findout to which connection the data is meant for */ + pcb = pan_get_pcb_by_handle (handle); + if (!pcb) + { + PAN_TRACE_ERROR0 ("PAN Buf write for wrong handle"); + GKI_freebuf (p_buf); + return PAN_FAILURE; + } + + if (pcb->con_state != PAN_STATE_CONNECTED) + { + PAN_TRACE_ERROR0 ("PAN Buf write when conn is not active"); + GKI_freebuf (p_buf); + return PAN_FAILURE; + } + + result = BNEP_WriteBuf (pcb->handle, dst, p_buf, protocol, src, ext); + if (result == BNEP_IGNORE_CMD) + { + PAN_TRACE_DEBUG0 ("PAN ignored data buf write to PANU"); + return result; + } + else if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR0 ("PAN failed to send data buf to the PANU"); + return result; + } + + PAN_TRACE_DEBUG0 ("PAN successfully sent data buf to the PANU"); + return PAN_SUCCESS; +} + + +/******************************************************************************* +** +** Function PAN_SetProtocolFilters +** +** Description This function is used to set protocol filters on the peer +** +** Parameters: handle - handle for the connection +** num_filters - number of protocol filter ranges +** start - array of starting protocol numbers +** end - array of ending protocol numbers +** +** +** Returns PAN_SUCCESS if protocol filters are set successfully +** PAN_FAILURE if connection not found or error in setting +** +*******************************************************************************/ +tPAN_RESULT PAN_SetProtocolFilters (UINT16 handle, + UINT16 num_filters, + UINT16 *p_start_array, + UINT16 *p_end_array) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + tPAN_CONN *pcb; + tPAN_RESULT result; + + /* Check if the connection exists */ + pcb = pan_get_pcb_by_handle (handle); + if(!pcb) + { + PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle); + return PAN_FAILURE; + } + + result = BNEP_SetProtocolFilters (pcb->handle, num_filters, p_start_array, p_end_array); + if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR1 ("PAN failed to set protocol filters for handle %d", handle); + return result; + } + + PAN_TRACE_API1 ("PAN successfully sent protocol filters for handle %d", handle); + return PAN_SUCCESS; +#else + return PAN_FAILURE; +#endif +} + + + +/******************************************************************************* +** +** Function PAN_SetMulticastFilters +** +** Description This function is used to set multicast filters on the peer +** +** Parameters: handle - handle for the connection +** num_filters - number of multicast filter ranges +** start - array of starting multicast filter addresses +** end - array of ending multicast filter addresses +** +** +** Returns PAN_SUCCESS if multicast filters are set successfully +** PAN_FAILURE if connection not found or error in setting +** +*******************************************************************************/ +tBNEP_RESULT PAN_SetMulticastFilters (UINT16 handle, + UINT16 num_mcast_filters, + UINT8 *p_start_array, + UINT8 *p_end_array) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + tPAN_CONN *pcb; + tPAN_RESULT result; + + /* Check if the connection exists */ + pcb = pan_get_pcb_by_handle (handle); + if(!pcb) + { + PAN_TRACE_ERROR1 ("PAN connection not found for the handle %d", handle); + return PAN_FAILURE; + } + + result = BNEP_SetMulticastFilters (pcb->handle, + num_mcast_filters, p_start_array, p_end_array); + if (result != BNEP_SUCCESS) + { + PAN_TRACE_ERROR1 ("PAN failed to set multicast filters for handle %d", handle); + return result; + } + + PAN_TRACE_API1 ("PAN successfully sent multicast filters for handle %d", handle); + return PAN_SUCCESS; +#else + return PAN_FAILURE; +#endif +} + + +/******************************************************************************* +** +** Function PAN_SetTraceLevel +** +** Description This function sets the trace level for PAN. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +UINT8 PAN_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + pan_cb.trace_level = new_level; + else + pan_dump_status (); + + return (pan_cb.trace_level); +} + +/******************************************************************************* +** +** Function PAN_Init +** +** Description This function initializes the PAN module variables +** +** Parameters: none +** +** Returns none +** +*******************************************************************************/ +void PAN_Init (void) +{ + memset (&pan_cb, 0, sizeof (tPAN_CB)); + +#if defined(PAN_INITIAL_TRACE_LEVEL) + pan_cb.trace_level = PAN_INITIAL_TRACE_LEVEL; +#else + pan_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif +} + + diff --git a/stack/pan/pan_int.h b/stack/pan/pan_int.h new file mode 100644 index 000000000..4e0223645 --- /dev/null +++ b/stack/pan/pan_int.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * Copyright (C) 2001-2012 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 file contains internally used PAN definitions + * + ******************************************************************************/ + +#ifndef PAN_INT_H +#define PAN_INT_H + +#include "pan_api.h" + +/* +** This role is used to shutdown the profile. Used internally +** Applications should call PAN_Deregister to shutdown the profile +*/ +#define PAN_ROLE_INACTIVE 0 + +/* Protocols supported by the host internal stack, are registered with SDP */ +#define PAN_PROTOCOL_IP 0x0800 +#define PAN_PROTOCOL_ARP 0x0806 + +#define PAN_PROFILE_VERSION 0x0100 /* Version 1.00 */ + +/* Define the PAN Connection Control Block +*/ +typedef struct +{ +#define PAN_STATE_IDLE 0 +#define PAN_STATE_CONN_START 1 +#define PAN_STATE_CONNECTED 2 + UINT8 con_state; + +#define PAN_FLAGS_CONN_COMPLETED 0x01 + UINT8 con_flags; + + UINT16 handle; + BD_ADDR rem_bda; + + UINT16 bad_pkts_rcvd; + UINT16 src_uuid; + UINT16 dst_uuid; + UINT16 prv_src_uuid; + UINT16 prv_dst_uuid; + UINT16 ip_addr_known; + UINT32 ip_addr; + +} tPAN_CONN; + + +/* The main PAN control block +*/ +typedef struct +{ + UINT8 role; + UINT8 active_role; + UINT8 prv_active_role; + tPAN_CONN pcb[MAX_PAN_CONNS]; + + tPAN_CONN_STATE_CB *pan_conn_state_cb; /* Connection state callback */ + tPAN_BRIDGE_REQ_CB *pan_bridge_req_cb; + tPAN_DATA_IND_CB *pan_data_ind_cb; + tPAN_DATA_BUF_IND_CB *pan_data_buf_ind_cb; + tPAN_FILTER_IND_CB *pan_pfilt_ind_cb; /* protocol filter indication callback */ + tPAN_MFILTER_IND_CB *pan_mfilt_ind_cb; /* multicast filter indication callback */ + tPAN_TX_DATA_FLOW_CB *pan_tx_data_flow_cb; + + BD_ADDR my_bda; /* BD Address of this device */ + char *user_service_name; + char *gn_service_name; + char *nap_service_name; + UINT32 pan_user_sdp_handle; + UINT32 pan_gn_sdp_handle; + UINT32 pan_nap_sdp_handle; + UINT8 num_conns; + UINT8 trace_level; +} tPAN_CB; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global PAN data +*/ +#if PAN_DYNAMIC_MEMORY == FALSE +PAN_API extern tPAN_CB pan_cb; +#else +PAN_API extern tPAN_CB *pan_cb_ptr; +#define pan_cb (*pan_cb_ptr) +#endif + +/*******************************************************************************/ +extern void pan_register_with_bnep (void); +extern void pan_conn_ind_cb (UINT16 handle, + BD_ADDR p_bda, + tBT_UUID *remote_uuid, + tBT_UUID *local_uuid, + BOOLEAN is_role_change); +extern void pan_connect_state_cb (UINT16 handle, BD_ADDR rem_bda, tBNEP_RESULT result, BOOLEAN is_role_change); +extern void pan_data_ind_cb (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + UINT8 *p_data, + UINT16 len, + BOOLEAN fw_ext_present); +extern void pan_data_buf_ind_cb (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + BT_HDR *p_buf, + BOOLEAN ext); +extern void pan_tx_data_flow_cb (UINT16 handle, + tBNEP_RESULT event); +void pan_proto_filt_ind_cb (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_filters, + UINT8 *p_filters); +void pan_mcast_filt_ind_cb (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_filters, + UINT8 *p_filters); +extern UINT32 pan_register_with_sdp (UINT16 uuid, UINT8 sec_mask, char *p_name, char *p_desc); +extern tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, UINT16 handle); +extern tPAN_CONN *pan_get_pcb_by_handle (UINT16 handle); +extern tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda); +extern void pan_close_all_connections (void); +extern void pan_release_pcb (tPAN_CONN *p_pcb); +extern void pan_dump_status (void); + +/********************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/stack/pan/pan_main.c b/stack/pan/pan_main.c new file mode 100644 index 000000000..6cbe1ce8d --- /dev/null +++ b/stack/pan/pan_main.c @@ -0,0 +1,730 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 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 file contains main functions to support PAN profile + * commands and events. + * + ******************************************************************************/ + +#include <string.h> +#include "gki.h" +#include "bt_types.h" +#include "bnep_api.h" +#include "pan_api.h" +#include "pan_int.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "l2c_api.h" +#include "hcidefs.h" + + +#if PAN_DYNAMIC_MEMORY == FALSE +tPAN_CB pan_cb; +#endif + +#define UUID_CONSTANT_PART 12 +UINT8 constant_pan_uuid[UUID_CONSTANT_PART] = {0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb}; + + +/******************************************************************************* +** +** Function pan_register_with_bnep +** +** Description This function registers PAN profile with BNEP +** +** Parameters: none +** +** Returns none +** +*******************************************************************************/ +void pan_register_with_bnep (void) +{ + tBNEP_REGISTER reg_info; + + memset (®_info, 0, sizeof (tBNEP_REGISTER)); + + reg_info.p_conn_ind_cb = pan_conn_ind_cb; + reg_info.p_conn_state_cb = pan_connect_state_cb; + reg_info.p_data_buf_cb = pan_data_buf_ind_cb; + reg_info.p_data_ind_cb = NULL; + reg_info.p_tx_data_flow_cb = pan_tx_data_flow_cb; + reg_info.p_filter_ind_cb = pan_proto_filt_ind_cb; + reg_info.p_mfilter_ind_cb = pan_mcast_filt_ind_cb; + + BNEP_Register (®_info); +} + + +/******************************************************************************* +** +** Function pan_conn_ind_cb +** +** Description This function is registered with BNEP as connection indication +** callback. BNEP will call this when there is connection +** request from the peer. PAN should call BNEP_ConnectResp to +** indicate whether to accept the connection or reject +** +** Parameters: handle - handle for the connection +** p_bda - BD Addr of the peer requesting the connection +** remote_uuid - UUID of the source role (peer device role) +** local_uuid - UUID of the destination role (local device role) +** is_role_change - Flag to indicate that it is a role change +** +** Returns none +** +*******************************************************************************/ +void pan_conn_ind_cb (UINT16 handle, + BD_ADDR p_bda, + tBT_UUID *remote_uuid, + tBT_UUID *local_uuid, + BOOLEAN is_role_change) +{ + tPAN_CONN *pcb; + UINT8 req_role; + BOOLEAN wrong_uuid; + + /* + ** If we are in GN or NAP role and have one or more + ** active connections and the received connection is + ** for user role reject it. + ** If we are in user role with one connection active + ** reject the connection. + ** Allocate PCB and store the parameters + ** Make bridge request to the host system if connection + ** is for NAP + */ + wrong_uuid = FALSE; +#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE) + if (remote_uuid->len == 16) + { + /* + ** If the UUID is 16 bytes forst two bytes should be zeros + ** and last 12 bytes should match the spec defined constant value + */ + if (memcmp (constant_pan_uuid, remote_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART)) + wrong_uuid = TRUE; + + if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1]) + wrong_uuid = TRUE; + + /* Extract the 16 bit equivalent of the UUID */ + remote_uuid->uu.uuid16 = (UINT16)((remote_uuid->uu.uuid128[2] << 8) | remote_uuid->uu.uuid128[3]); + remote_uuid->len = 2; + } + if (remote_uuid->len == 4) + { + /* First two bytes should be zeros */ + if (remote_uuid->uu.uuid32 & 0xFFFF0000) + wrong_uuid = TRUE; + + remote_uuid->uu.uuid16 = (UINT16)remote_uuid->uu.uuid32; + remote_uuid->len = 2; + } + + if (wrong_uuid) + { + PAN_TRACE_ERROR0 ("PAN Connection failed because of wrong remote UUID "); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID); + return; + } + + wrong_uuid = FALSE; + if (local_uuid->len == 16) + { + /* + ** If the UUID is 16 bytes forst two bytes should be zeros + ** and last 12 bytes should match the spec defined constant value + */ + if (memcmp (constant_pan_uuid, local_uuid->uu.uuid128 + 4, UUID_CONSTANT_PART)) + wrong_uuid = TRUE; + + if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1]) + wrong_uuid = TRUE; + + /* Extract the 16 bit equivalent of the UUID */ + local_uuid->uu.uuid16 = (UINT16)((local_uuid->uu.uuid128[2] << 8) | local_uuid->uu.uuid128[3]); + local_uuid->len = 2; + } + if (local_uuid->len == 4) + { + /* First two bytes should be zeros */ + if (local_uuid->uu.uuid32 & 0xFFFF0000) + wrong_uuid = TRUE; + + local_uuid->uu.uuid16 = (UINT16)local_uuid->uu.uuid32; + local_uuid->len = 2; + } + + if (wrong_uuid) + { + PAN_TRACE_ERROR0 ("PAN Connection failed because of wrong local UUID "); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID); + return; + } + + PAN_TRACE_EVENT5 ("pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src uuid 0x%x, role change %s", + handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16, is_role_change?"YES":"NO"); + /* The acceptable UUID size is only 2 */ + if (remote_uuid->len != 2) + { + PAN_TRACE_ERROR1 ("PAN Connection failed because of wrong UUID size %d", remote_uuid->len); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_UUID_SIZE); + return; + } +#endif + + /* Check if the source UUID is a valid one */ + if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU && + remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP && + remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN) + { + PAN_TRACE_ERROR1 ("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_SRC_UUID); + return; + } + + /* Check if the destination UUID is a valid one */ + if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU && + local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP && + local_uuid->uu.uuid16 != UUID_SERVCLASS_GN) + { + PAN_TRACE_ERROR1 ("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID); + return; + } + + /* Check if currently we support the destination role requested */ + if (((!(pan_cb.role & UUID_SERVCLASS_PANU)) + && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) || + ((!(pan_cb.role & UUID_SERVCLASS_GN)) + && local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) || + ((!(pan_cb.role & UUID_SERVCLASS_NAP)) + && local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP)) + { + PAN_TRACE_ERROR1 ("PAN Connection failed because of unsupported destination UUID 0x%x", local_uuid->uu.uuid16); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID); + return; + } + + /* Requested destination role is */ + if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) + req_role = PAN_ROLE_CLIENT; + else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) + req_role = PAN_ROLE_GN_SERVER; + else + req_role = PAN_ROLE_NAP_SERVER; + + /* If the connection indication is for the existing connection + ** Check if the new destination role is acceptable + */ + pcb = pan_get_pcb_by_handle (handle); + if (pcb) + { + if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) + { + /* There are connections other than this one + ** so we cann't accept PANU role. Reject + */ + PAN_TRACE_ERROR0 ("Dst UUID should be either GN or NAP only because there are other connections"); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID); + return; + } + + /* If it is already in connected state check for bridging status */ + if (pcb->con_state == PAN_STATE_CONNECTED) + { + PAN_TRACE_EVENT2 ("PAN Role changing New Src 0x%x Dst 0x%x", + remote_uuid->uu.uuid16, local_uuid->uu.uuid16); + + pcb->prv_src_uuid = pcb->src_uuid; + pcb->prv_dst_uuid = pcb->dst_uuid; + + if (pcb->src_uuid == UUID_SERVCLASS_NAP && + local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP) + { + /* Remove bridging */ + if (pan_cb.pan_bridge_req_cb) + (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE); + } + } + /* Set the latest active PAN role */ + pan_cb.active_role = req_role; + pcb->src_uuid = local_uuid->uu.uuid16; + pcb->dst_uuid = remote_uuid->uu.uuid16; + BNEP_ConnectResp (handle, BNEP_SUCCESS); + return; + } + else + { + /* If this a new connection and destination is PANU role and + ** we already have a connection then reject the request. + ** If we have a connection in PANU role then reject it + */ + if (pan_cb.num_conns && + (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU || + pan_cb.active_role == PAN_ROLE_CLIENT)) + { + PAN_TRACE_ERROR0 ("PAN already have a connection and can't be user"); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED_DST_UUID); + return; + } + } + + /* This is a new connection */ + PAN_TRACE_DEBUG1 ("New connection indication for handle %d", handle); + pcb = pan_allocate_pcb (p_bda, handle); + if (!pcb) + { + PAN_TRACE_ERROR0 ("PAN no control block for new connection"); + BNEP_ConnectResp (handle, BNEP_CONN_FAILED); + return; + } + + PAN_TRACE_EVENT1 ("PAN connection destination UUID is 0x%x", local_uuid->uu.uuid16); + /* Set the latest active PAN role */ + pan_cb.active_role = req_role; + pcb->src_uuid = local_uuid->uu.uuid16; + pcb->dst_uuid = remote_uuid->uu.uuid16; + pcb->con_state = PAN_STATE_CONN_START; + pan_cb.num_conns++; + + BNEP_ConnectResp (handle, BNEP_SUCCESS); + return; +} + + +/******************************************************************************* +** +** Function pan_connect_state_cb +** +** Description This function is registered with BNEP as connection state +** change callback. BNEP will call this when the connection +** is established successfully or terminated +** +** Parameters: handle - handle for the connection given in the connection +** indication callback +** rem_bda - remote device bd addr +** result - indicates whether the connection is up or down +** BNEP_SUCCESS if the connection is up +** all other values indicates appropriate errors +** is_role_change - flag to indicate that it is a role change +** +** Returns none +** +*******************************************************************************/ +void pan_connect_state_cb (UINT16 handle, BD_ADDR rem_bda, tBNEP_RESULT result, BOOLEAN is_role_change) +{ + tPAN_CONN *pcb; + UINT8 peer_role; + + PAN_TRACE_EVENT2 ("pan_connect_state_cb - for handle %d, result %d", handle, result); + pcb = pan_get_pcb_by_handle (handle); + if (!pcb) + { + PAN_TRACE_ERROR1 ("PAN State change indication for wrong handle %d", handle); + return; + } + + /* If the connection is getting terminated remove bridging */ + if (result != BNEP_SUCCESS) + { + /* Inform the application that connection is down */ + if (pan_cb.pan_conn_state_cb) + (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, result, is_role_change, PAN_ROLE_INACTIVE, PAN_ROLE_INACTIVE); + + /* Check if this failure is for role change only */ + if (pcb->con_state != PAN_STATE_CONNECTED && + (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED)) + { + /* restore the original values */ + PAN_TRACE_EVENT0 ("restoring the connection state to active"); + pcb->con_state = PAN_STATE_CONNECTED; + pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED); + + pcb->src_uuid = pcb->prv_src_uuid; + pcb->dst_uuid = pcb->prv_dst_uuid; + pan_cb.active_role = pan_cb.prv_active_role; + + if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb) + (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE); + + return; + } + + if (pcb->con_state == PAN_STATE_CONNECTED) + { + /* If the connections destination role is NAP remove bridging */ + if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb) + (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, FALSE); + } + + pan_cb.num_conns--; + pan_release_pcb (pcb); + return; + } + + /* Requested destination role is */ + if (pcb->src_uuid == UUID_SERVCLASS_PANU) + pan_cb.active_role = PAN_ROLE_CLIENT; + else if (pcb->src_uuid == UUID_SERVCLASS_GN) + pan_cb.active_role = PAN_ROLE_GN_SERVER; + else + pan_cb.active_role = PAN_ROLE_NAP_SERVER; + + if (pcb->dst_uuid == UUID_SERVCLASS_PANU) + peer_role = PAN_ROLE_CLIENT; + else if (pcb->dst_uuid == UUID_SERVCLASS_GN) + peer_role = PAN_ROLE_GN_SERVER; + else + peer_role = PAN_ROLE_NAP_SERVER; + + pcb->con_state = PAN_STATE_CONNECTED; + + /* Inform the application that connection is down */ + if (pan_cb.pan_conn_state_cb) + (*pan_cb.pan_conn_state_cb) (pcb->handle, pcb->rem_bda, PAN_SUCCESS, is_role_change, pan_cb.active_role, peer_role); + + /* Create bridge if the destination role is NAP */ + if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP) + { + PAN_TRACE_EVENT0 ("PAN requesting for bridge"); + (*pan_cb.pan_bridge_req_cb) (pcb->rem_bda, TRUE); + } +} + + +/******************************************************************************* +** +** Function pan_data_ind_cb +** +** Description This function is registered with BNEP as data indication +** callback. BNEP will call this when the peer sends any data +** on this connection +** +** Parameters: handle - handle for the connection +** src - source BD Addr +** dst - destination BD Addr +** protocol - Network protocol of the Eth packet +** p_data - pointer to the data +** len - length of the data +** fw_ext_present - to indicate whether the data contains any +** extension headers before the payload +** +** Returns none +** +*******************************************************************************/ +void pan_data_ind_cb (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + UINT8 *p_data, + UINT16 len, + BOOLEAN ext) +{ + tPAN_CONN *pcb; + UINT16 i; + BOOLEAN forward; + + /* + ** Check the connection status + ** If the destination address is MAC broadcast send on all links + ** except on the one received + ** If the destination uuid is for NAP send to host system also + ** If the destination address is one of the devices connected + ** send the packet to over that link + ** If the destination address is unknown and destination uuid is NAP + ** send it to the host system + */ + + PAN_TRACE_EVENT1 ("pan_data_ind_cb - for handle %d", handle); + pcb = pan_get_pcb_by_handle (handle); + if (!pcb) + { + PAN_TRACE_ERROR1 ("PAN Data indication for wrong handle %d", handle); + return; + } + + if (pcb->con_state != PAN_STATE_CONNECTED) + { + PAN_TRACE_ERROR2 ("PAN Data indication in wrong state %d for handle %d", + pcb->con_state, handle); + return; + } + + /* Check if it is broadcast packet */ + if (dst[0] & 0x01) + { + PAN_TRACE_DEBUG2 ("PAN received broadcast packet on handle %d, src uuid 0x%x", + handle, pcb->src_uuid); + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && + pan_cb.pcb[i].handle != handle && + pcb->src_uuid == pan_cb.pcb[i].src_uuid) + { + BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext); + } + } + + if (pan_cb.pan_data_ind_cb) + (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, TRUE); + + return; + } + + /* Check if it is for any other PAN connection */ + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && + pcb->src_uuid == pan_cb.pcb[i].src_uuid) + { + if (memcmp (pan_cb.pcb[i].rem_bda, dst, BD_ADDR_LEN) == 0) + { + BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext); + return; + } + } + } + + if (pcb->src_uuid == UUID_SERVCLASS_NAP) + forward = TRUE; + else + forward = FALSE; + + /* Send it over the LAN or give it to host software */ + if (pan_cb.pan_data_ind_cb) + (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward); + + return; +} + + +/******************************************************************************* +** +** Function pan_data_buf_ind_cb +** +** Description This function is registered with BNEP as data buffer indication +** callback. BNEP will call this when the peer sends any data +** on this connection. PAN is responsible to release the buffer +** +** Parameters: handle - handle for the connection +** src - source BD Addr +** dst - destination BD Addr +** protocol - Network protocol of the Eth packet +** p_buf - pointer to the data buffer +** ext - to indicate whether the data contains any +** extension headers before the payload +** +** Returns none +** +*******************************************************************************/ +void pan_data_buf_ind_cb (UINT16 handle, + UINT8 *src, + UINT8 *dst, + UINT16 protocol, + BT_HDR *p_buf, + BOOLEAN ext) +{ + tPAN_CONN *pcb, *dst_pcb; + tBNEP_RESULT result; + UINT16 i, len; + UINT8 *p_data; + BOOLEAN forward = FALSE; + + /* Check if the connection is in right state */ + pcb = pan_get_pcb_by_handle (handle); + if (!pcb) + { + PAN_TRACE_ERROR1 ("PAN Data buffer indication for wrong handle %d", handle); + GKI_freebuf (p_buf); + return; + } + + if (pcb->con_state != PAN_STATE_CONNECTED) + { + PAN_TRACE_ERROR2 ("PAN Data indication in wrong state %d for handle %d", + pcb->con_state, handle); + GKI_freebuf (p_buf); + return; + } + + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + len = p_buf->len; + + PAN_TRACE_EVENT4 ("pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d", + handle, protocol, len, ext); + + if (pcb->src_uuid == UUID_SERVCLASS_NAP) + forward = TRUE; + else + forward = FALSE; + + /* Check if it is broadcast or multicast packet */ + if (pcb->src_uuid != UUID_SERVCLASS_PANU) + { + if (dst[0] & 0x01) + { + PAN_TRACE_DEBUG2 ("PAN received broadcast packet on handle %d, src uuid 0x%x", + handle, pcb->src_uuid); + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED && + pan_cb.pcb[i].handle != handle && + pcb->src_uuid == pan_cb.pcb[i].src_uuid) + { + BNEP_Write (pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext); + } + } + + if (pan_cb.pan_data_buf_ind_cb) + (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward); + else if (pan_cb.pan_data_ind_cb) + { + (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward); + GKI_freebuf (p_buf); + } + + return; + } + + /* Check if it is for any other PAN connection */ + dst_pcb = pan_get_pcb_by_addr (dst); + if (dst_pcb) + { + PAN_TRACE_EVENT0 ("pan_data_buf_ind_cb - destination PANU found and sending the data"); + result = BNEP_WriteBuf (dst_pcb->handle, dst, p_buf, protocol, src, ext); + if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD) + PAN_TRACE_ERROR1 ("Failed to write data for PAN connection handle %d", dst_pcb->handle); + return; + } + } + + /* Send it over the LAN or give it to host software */ + if (pan_cb.pan_data_buf_ind_cb) + (*pan_cb.pan_data_buf_ind_cb) (pcb->handle, src, dst, protocol, p_buf, ext, forward); + else if (pan_cb.pan_data_ind_cb) + { + (*pan_cb.pan_data_ind_cb) (pcb->handle, src, dst, protocol, p_data, len, ext, forward); + GKI_freebuf (p_buf); + } + else + GKI_freebuf (p_buf); + + return; +} + +/******************************************************************************* +** +** Function pan_proto_filt_ind_cb +** +** Description This function is registered with BNEP to receive tx data +** flow status +** +** Parameters: handle - handle for the connection +** event - flow status +** +** Returns none +** +*******************************************************************************/ +void pan_tx_data_flow_cb (UINT16 handle, + tBNEP_RESULT event) +{ + + if (pan_cb.pan_tx_data_flow_cb) + (*pan_cb.pan_tx_data_flow_cb) (handle, event); + + return; +} + +/******************************************************************************* +** +** Function pan_proto_filt_ind_cb +** +** Description This function is registered with BNEP as proto filter indication +** callback. BNEP will call this when the peer sends any protocol +** filter set for the connection or to indicate the result of the +** protocol filter set by the local device +** +** Parameters: handle - handle for the connection +** indication - TRUE if this is indication +** FALSE if it is called to give the result of local +** device protocol filter set +** result - This gives the result of the filter set operation +** num_filters - number of filters set by the peer device +** p_filters - pointer to the filters set by the peer device +** +** Returns none +** +*******************************************************************************/ +void pan_proto_filt_ind_cb (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_filters, + UINT8 *p_filters) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + PAN_TRACE_EVENT4 ("pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, num %d", + handle, indication, result, num_filters); + + if (pan_cb.pan_pfilt_ind_cb) + (*pan_cb.pan_pfilt_ind_cb) (handle, indication, result, num_filters, p_filters); +#endif + + return; +} + + +/******************************************************************************* +** +** Function pan_mcast_filt_ind_cb +** +** Description This function is registered with BNEP as mcast filter indication +** callback. BNEP will call this when the peer sends any multicast +** filter set for the connection or to indicate the result of the +** multicast filter set by the local device +** +** Parameters: handle - handle for the connection +** indication - TRUE if this is indication +** FALSE if it is called to give the result of local +** device multicast filter set +** result - This gives the result of the filter set operation +** num_filters - number of filters set by the peer device +** p_filters - pointer to the filters set by the peer device +** +** Returns none +** +*******************************************************************************/ +void pan_mcast_filt_ind_cb (UINT16 handle, + BOOLEAN indication, + tBNEP_RESULT result, + UINT16 num_filters, + UINT8 *p_filters) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + PAN_TRACE_EVENT4 ("pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, num %d", + handle, indication, result, num_filters); + + if (pan_cb.pan_mfilt_ind_cb) + (*pan_cb.pan_mfilt_ind_cb) (handle, indication, result, num_filters, p_filters); +#endif + + return; +} + diff --git a/stack/pan/pan_utils.c b/stack/pan/pan_utils.c new file mode 100644 index 000000000..9ebbb759b --- /dev/null +++ b/stack/pan/pan_utils.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 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 file contains main functions to support PAN profile + * commands and events. + * + *****************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include "gki.h" +#include "bnep_api.h" +#include "pan_api.h" +#include "pan_int.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "l2c_api.h" +#include "hcidefs.h" +#include "btm_api.h" + + +static const UINT8 pan_proto_elem_data[] = { + 0x35, 0x18, /* data element sequence of length 0x18 bytes */ + 0x35, 0x06, /* data element sequence for L2CAP descriptor */ + 0x19, 0x01, 0x00, /* UUID for L2CAP - 0x0100 */ + 0x09, 0x00, 0x0F, /* PSM for BNEP - 0x000F */ + 0x35, 0x0E, /* data element seqence for BNEP descriptor */ + 0x19, 0x00, 0x0F, /* UUID for BNEP - 0x000F */ + 0x09, 0x01, 0x00, /* BNEP specific parameter 0 -- Version of BNEP = version 1 = 0x0001 */ + 0x35, 0x06, /* BNEP specific parameter 1 -- Supported network packet type list */ + 0x09, 0x08, 0x00, /* network packet type IPv4 = 0x0800 */ + 0x09, 0x08, 0x06 /* network packet type ARP = 0x0806 */ +}; + +/******************************************************************************* +** +** Function pan_register_with_sdp +** +** Description +** +** Returns +** +*******************************************************************************/ +UINT32 pan_register_with_sdp (UINT16 uuid, UINT8 sec_mask, char *p_name, char *p_desc) +{ + UINT32 sdp_handle; + UINT16 browse_list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + UINT16 security = 0; + UINT8 availability; + UINT32 proto_len = (UINT32)pan_proto_elem_data[1]; + + /* Create a record */ + sdp_handle = SDP_CreateRecord (); + + if (sdp_handle == 0) + { + PAN_TRACE_ERROR0 ("PAN_SetRole - could not create SDP record"); + return 0; + } + + /* Service Class ID List */ + SDP_AddServiceClassIdList (sdp_handle, 1, &uuid); + + /* Add protocol element sequence from the constant string */ + SDP_AddAttribute (sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST, DATA_ELE_SEQ_DESC_TYPE, + proto_len, (UINT8 *)(pan_proto_elem_data+2)); + +// btla-specific ++ +#if 0 + availability = 0xFF; + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_AVAILABILITY, UINT_DESC_TYPE, 1, &availability); +#endif +// btla-specific -- + + /* Language base */ + SDP_AddLanguageBaseAttrIDList (sdp_handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID); + + /* Profile descriptor list */ + SDP_AddProfileDescriptorList (sdp_handle, uuid, PAN_PROFILE_VERSION); + + /* Service Name */ + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT8) (strlen(p_name) + 1), (UINT8 *)p_name); + + /* Service description */ + SDP_AddAttribute (sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, + (UINT8) (strlen(p_desc) + 1), (UINT8 *)p_desc); + + /* Security description */ + if (sec_mask) + { + UINT16_TO_BE_FIELD(&security, 0x0001); + } + SDP_AddAttribute (sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2, (UINT8 *)&security); + +#if (defined (PAN_SUPPORTS_ROLE_NAP) && PAN_SUPPORTS_ROLE_NAP == TRUE) + if (uuid == UUID_SERVCLASS_NAP) + { + UINT16 NetAccessType = 0x0005; /* Ethernet */ + UINT32 NetAccessRate = 0x0001312D0; /* 10Mb/sec */ + UINT8 array[10], *p; + + /* Net access type. */ + p = array; + UINT16_TO_BE_STREAM (p, NetAccessType); + SDP_AddAttribute (sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2, array); + + /* Net access rate. */ + p = array; + UINT32_TO_BE_STREAM (p, NetAccessRate); + SDP_AddAttribute (sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4, array); + + /* Register with Security Manager for the specific security level */ + if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_NAP, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP)) + || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_NAP, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_NAP))) + { + PAN_TRACE_ERROR0 ("PAN Security Registration failed for PANU"); + } + } +#endif +#if (defined (PAN_SUPPORTS_ROLE_GN) && PAN_SUPPORTS_ROLE_GN == TRUE) + if (uuid == UUID_SERVCLASS_GN) + { + if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_GN, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN)) + || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_GN, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_GN))) + { + PAN_TRACE_ERROR0 ("PAN Security Registration failed for GN"); + } + } +#endif +#if (defined (PAN_SUPPORTS_ROLE_PANU) && PAN_SUPPORTS_ROLE_PANU == TRUE) + if (uuid == UUID_SERVCLASS_PANU) + { + if ((!BTM_SetSecurityLevel (TRUE, p_name, BTM_SEC_SERVICE_BNEP_PANU, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU)) + || (!BTM_SetSecurityLevel (FALSE, p_name, BTM_SEC_SERVICE_BNEP_PANU, + sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP, UUID_SERVCLASS_PANU))) + { + PAN_TRACE_ERROR0 ("PAN Security Registration failed for PANU"); + } + } +#endif + + /* Make the service browsable */ + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list); + + + return sdp_handle; +} + + + +/******************************************************************************* +** +** Function pan_allocate_pcb +** +** Description +** +** Returns +** +*******************************************************************************/ +tPAN_CONN *pan_allocate_pcb (BD_ADDR p_bda, UINT16 handle) +{ + UINT16 i; + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE && + pan_cb.pcb[i].handle == handle) + return NULL; + } + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE && + memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0) + return NULL; + } + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE) + { + memset (&(pan_cb.pcb[i]), 0, sizeof (tPAN_CONN)); + memcpy (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN); + pan_cb.pcb[i].handle = handle; + return &(pan_cb.pcb[i]); + } + } + return NULL; +} + + +/******************************************************************************* +** +** Function pan_get_pcb_by_handle +** +** Description +** +** Returns +** +*******************************************************************************/ +tPAN_CONN *pan_get_pcb_by_handle (UINT16 handle) +{ + UINT16 i; + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE && + pan_cb.pcb[i].handle == handle) + return &(pan_cb.pcb[i]); + } + + return NULL; +} + + +/******************************************************************************* +** +** Function pan_get_pcb_by_addr +** +** Description +** +** Returns +** +*******************************************************************************/ +tPAN_CONN *pan_get_pcb_by_addr (BD_ADDR p_bda) +{ + UINT16 i; + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE) + continue; + + if (memcmp (pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0) + return &(pan_cb.pcb[i]); + + /* + if (pan_cb.pcb[i].mfilter_present && + (memcmp (p_bda, pan_cb.pcb[i].multi_cast_bridge, BD_ADDR_LEN) == 0)) + return &(pan_cb.pcb[i]); + */ + } + + return NULL; +} + + + + +/******************************************************************************* +** +** Function pan_close_all_connections +** +** Description +** +** Returns void +** +*******************************************************************************/ +void pan_close_all_connections (void) +{ + UINT16 i; + + for (i=0; i<MAX_PAN_CONNS; i++) + { + if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE) + { + BNEP_Disconnect (pan_cb.pcb[i].handle); + pan_cb.pcb[i].con_state = PAN_STATE_IDLE; + } + } + + pan_cb.active_role = PAN_ROLE_INACTIVE; + pan_cb.num_conns = 0; + return; +} + + +/******************************************************************************* +** +** Function pan_release_pcb +** +** Description This function releases a PCB. +** +** Returns void +** +*******************************************************************************/ +void pan_release_pcb (tPAN_CONN *p_pcb) +{ + /* Drop any response pointer we may be holding */ + memset (p_pcb, 0, sizeof (tPAN_CONN)); + p_pcb->con_state = PAN_STATE_IDLE; +} + + +/******************************************************************************* +** +** Function pan_dump_status +** +** Description This function dumps the pan control block and connection +** blocks information +** +** Returns none +** +*******************************************************************************/ +void pan_dump_status (void) +{ +#if (defined (PAN_SUPPORTS_DEBUG_DUMP) && PAN_SUPPORTS_DEBUG_DUMP == TRUE) + UINT16 i; + char buff[200]; + tPAN_CONN *p_pcb; + + PAN_TRACE_DEBUG3 ("PAN role %x, active role %d, num_conns %d", + pan_cb.role, pan_cb.active_role, pan_cb.num_conns); + + for (i = 0, p_pcb = pan_cb.pcb; i < MAX_PAN_CONNS; i++, p_pcb++) + { + sprintf (buff, "%d state %d, handle %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x", + i, p_pcb->con_state, p_pcb->handle, p_pcb->src_uuid, p_pcb->dst_uuid, + p_pcb->rem_bda[0], p_pcb->rem_bda[1], p_pcb->rem_bda[2], + p_pcb->rem_bda[3], p_pcb->rem_bda[4], p_pcb->rem_bda[5]); + + PAN_TRACE_DEBUG0 (buff); + } +#endif +} + + + |