diff options
author | Andre Eisenbach <andre@broadcom.com> | 2012-02-22 13:18:21 -0800 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2012-07-14 11:19:11 -0700 |
commit | e448862a47c08eb23185aaed574b39264f5005fc (patch) | |
tree | 2bc6246e3091315e77224fd798ea2fe8074ef972 /stack/bnep | |
parent | a2ca4b83ab8bbbfd8d5f6693e927ed4b82094624 (diff) | |
download | external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.zip external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.gz external_bluetooth_bluedroid-e448862a47c08eb23185aaed574b39264f5005fc.tar.bz2 |
Initial Bluedroid stack commit
Diffstat (limited to 'stack/bnep')
-rw-r--r-- | stack/bnep/bnep_api.c | 768 | ||||
-rw-r--r-- | stack/bnep/bnep_int.h | 238 | ||||
-rw-r--r-- | stack/bnep/bnep_main.c | 825 | ||||
-rw-r--r-- | stack/bnep/bnep_utils.c | 1449 |
4 files changed, 3280 insertions, 0 deletions
diff --git a/stack/bnep/bnep_api.c b/stack/bnep/bnep_api.c new file mode 100644 index 0000000..28a7c6b --- /dev/null +++ b/stack/bnep/bnep_api.c @@ -0,0 +1,768 @@ +/*****************************************************************************/ +/* */ +/* Name: bnep_api.c */ +/* */ +/* Description: this file contains the BNEP API code */ +/* */ +/* */ +/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */ +/* WIDCOMM Bluetooth Core. Proprietary and confidential. */ +/*****************************************************************************/ + +#include <string.h> +#include "bnep_api.h" +#include "bnep_int.h" + +/******************************************************************************* +** +** Function BNEP_Init +** +** Description This function initializes the BNEP unit. It should be called +** before accessing any other APIs to initialize the control block +** +** Returns void +** +*******************************************************************************/ +void BNEP_Init (void) +{ + memset (&bnep_cb, 0, sizeof (tBNEP_CB)); + +#if defined(BNEP_INITIAL_TRACE_LEVEL) + bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL; +#else + bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */ +#endif + + /* Start a timer to read our BD address */ + btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2); +} + + +/******************************************************************************* +** +** Function BNEP_Register +** +** Description This function is called by the upper layer to register +** its callbacks with BNEP +** +** Parameters: p_reg_info - contains all callback function pointers +** +** +** Returns BNEP_SUCCESS if registered successfully +** BNEP_FAILURE if connection state callback is missing +** +*******************************************************************************/ +tBNEP_RESULT BNEP_Register (tBNEP_REGISTER *p_reg_info) +{ + /* There should be connection state call back registered */ + if ((!p_reg_info) || (!(p_reg_info->p_conn_state_cb))) + return BNEP_SECURITY_FAIL; + + bnep_cb.p_conn_ind_cb = p_reg_info->p_conn_ind_cb; + bnep_cb.p_conn_state_cb = p_reg_info->p_conn_state_cb; + bnep_cb.p_data_ind_cb = p_reg_info->p_data_ind_cb; + bnep_cb.p_data_buf_cb = p_reg_info->p_data_buf_cb; + bnep_cb.p_filter_ind_cb = p_reg_info->p_filter_ind_cb; + bnep_cb.p_mfilter_ind_cb = p_reg_info->p_mfilter_ind_cb; + bnep_cb.p_tx_data_flow_cb = p_reg_info->p_tx_data_flow_cb; + + if (bnep_register_with_l2cap ()) + return BNEP_SECURITY_FAIL; + + bnep_cb.profile_registered = TRUE; + + return BNEP_SUCCESS; +} + + +/******************************************************************************* +** +** Function BNEP_Deregister +** +** Description This function is called by the upper layer to de-register +** its callbacks. +** +** Parameters: void +** +** +** Returns void +** +*******************************************************************************/ +void BNEP_Deregister (void) +{ + /* Clear all the call backs registered */ + bnep_cb.p_conn_ind_cb = NULL; + bnep_cb.p_conn_state_cb = NULL; + bnep_cb.p_data_ind_cb = NULL; + bnep_cb.p_data_buf_cb = NULL; + bnep_cb.p_filter_ind_cb = NULL; + bnep_cb.p_mfilter_ind_cb = NULL; + + bnep_cb.profile_registered = FALSE; + L2CA_Deregister (BT_PSM_BNEP); +} + + +/******************************************************************************* +** +** Function BNEP_Connect +** +** Description This function creates a BNEP connection to a remote +** device. +** +** Parameters: p_rem_addr - BD_ADDR of the peer +** src_uuid - source uuid for the connection +** dst_uuid - destination uuid for the connection +** p_handle - pointer to return the handle for the connection +** +** Returns BNEP_SUCCESS if connection started +** BNEP_NO_RESOURCES if no resources +** +*******************************************************************************/ +tBNEP_RESULT BNEP_Connect (BD_ADDR p_rem_bda, + tBT_UUID *src_uuid, + tBT_UUID *dst_uuid, + UINT16 *p_handle) +{ + UINT16 cid; + tBNEP_CONN *p_bcb = bnepu_find_bcb_by_bd_addr (p_rem_bda); + + BNEP_TRACE_API6 ("BNEP_Connect() BDA: %02x-%02x-%02x-%02x-%02x-%02x", + p_rem_bda[0], p_rem_bda[1], p_rem_bda[2], + p_rem_bda[3], p_rem_bda[4], p_rem_bda[5]); + + if (!bnep_cb.profile_registered) + return BNEP_WRONG_STATE; + + /* Both source and destination UUID lengths should be same */ + if (src_uuid->len != dst_uuid->len) + return BNEP_CONN_FAILED_UUID_SIZE; + +#if (!defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) || BNEP_SUPPORTS_ALL_UUID_LENGTHS == FALSE) + if (src_uuid->len != 2) + return BNEP_CONN_FAILED_UUID_SIZE; +#endif + + if (!p_bcb) + { + if ((p_bcb = bnepu_allocate_bcb (p_rem_bda)) == NULL) + return (BNEP_NO_RESOURCES); + } + else if (p_bcb->con_state != BNEP_STATE_CONNECTED) + return BNEP_WRONG_STATE; + else + { + /* Backup current UUID values to restore if role change fails */ + memcpy ((UINT8 *)&(p_bcb->prv_src_uuid), (UINT8 *)&(p_bcb->src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->prv_dst_uuid), (UINT8 *)&(p_bcb->dst_uuid), sizeof (tBT_UUID)); + } + + /* We are the originator of this connection */ + p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG; + + memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)src_uuid, sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)dst_uuid, sizeof (tBT_UUID)); + + if (p_bcb->con_state == BNEP_STATE_CONNECTED) + { + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_bcb->con_state = BNEP_STATE_SEC_CHECKING; + + BNEP_TRACE_API1 ("BNEP initiating security procedures for src uuid 0x%x", + p_bcb->src_uuid.uu.uuid16); + +#if (defined (BNEP_DO_AUTH_FOR_ROLE_SWITCH) && BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE) + btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE, + BTM_SEC_PROTO_BNEP, + bnep_get_uuid32(src_uuid), + &bnep_sec_check_complete, p_bcb); +#else + bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS); +#endif + + } + else + { + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_bcb->con_state = BNEP_STATE_CONN_START; + + if ((cid = L2CA_ConnectReq (BT_PSM_BNEP, p_bcb->rem_bda)) != 0) + { + p_bcb->l2cap_cid = cid; + + } + else + { + BNEP_TRACE_ERROR0 ("BNEP - Originate failed"); + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE); + bnepu_release_bcb (p_bcb); + return BNEP_CONN_FAILED; + } + + /* Start timer waiting for connect */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); + } + + *p_handle = p_bcb->handle; + return (BNEP_SUCCESS); +} + + +/******************************************************************************* +** +** Function BNEP_ConnectResp +** +** Description This function is called in responce to connection indication +** +** +** Parameters: handle - handle given in the connection indication +** resp - responce for the connection indication +** +** Returns BNEP_SUCCESS if connection started +** BNEP_WRONG_HANDLE if the connection is not found +** BNEP_WRONG_STATE if the responce is not expected +** +*******************************************************************************/ +tBNEP_RESULT BNEP_ConnectResp (UINT16 handle, tBNEP_RESULT resp) +{ + tBNEP_CONN *p_bcb; + UINT16 resp_code = BNEP_SETUP_CONN_OK; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + if (p_bcb->con_state != BNEP_STATE_CONN_SETUP || + (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD))) + return (BNEP_WRONG_STATE); + + BNEP_TRACE_API2 ("BNEP_ConnectResp() for handle %d, responce %d", handle, resp); + + /* Form appropriate responce based on profile responce */ + if (resp == BNEP_CONN_FAILED_SRC_UUID) resp_code = BNEP_SETUP_INVALID_SRC_UUID; + else if (resp == BNEP_CONN_FAILED_DST_UUID) resp_code = BNEP_SETUP_INVALID_DEST_UUID; + else if (resp == BNEP_CONN_FAILED_UUID_SIZE) resp_code = BNEP_SETUP_INVALID_UUID_SIZE; + else if (resp == BNEP_SUCCESS) resp_code = BNEP_SETUP_CONN_OK; + else resp_code = BNEP_SETUP_CONN_NOT_ALLOWED; + + bnep_send_conn_responce (p_bcb, resp_code); + p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); + + if (resp == BNEP_SUCCESS) + bnep_connected (p_bcb); + else if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + { + /* Restore the original parameters */ + p_bcb->con_state = BNEP_STATE_CONNECTED; + p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); + + memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID)); + } + + /* Process remaining part of the setup message (extension headers) */ + if (p_bcb->p_pending_data) + { + UINT8 extension_present = TRUE, *p, ext_type; + UINT16 rem_len; + + rem_len = p_bcb->p_pending_data->len; + p = (UINT8 *)(p_bcb->p_pending_data + 1) + p_bcb->p_pending_data->offset; + while (extension_present && p && rem_len) + { + ext_type = *p++; + extension_present = ext_type >> 7; + ext_type &= 0x7F; + + /* if unknown extension present stop processing */ + if (ext_type) + break; + + p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE); + } + + GKI_freebuf (p_bcb->p_pending_data); + p_bcb->p_pending_data = NULL; + } + return (BNEP_SUCCESS); +} + + +/******************************************************************************* +** +** Function BNEP_Disconnect +** +** Description This function is called to close the specified connection. +** +** Parameters: handle - handle of the connection +** +** Returns BNEP_SUCCESS if connection is disconnected +** BNEP_WRONG_HANDLE if no connection is not found +** +*******************************************************************************/ +tBNEP_RESULT BNEP_Disconnect (UINT16 handle) +{ + tBNEP_CONN *p_bcb; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + if (p_bcb->con_state == BNEP_STATE_IDLE) + return (BNEP_WRONG_HANDLE); + + BNEP_TRACE_API1 ("BNEP_Disconnect() for handle %d", handle); + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + bnepu_release_bcb (p_bcb); + + return (BNEP_SUCCESS); +} + + +/******************************************************************************* +** +** Function BNEP_WriteBuf +** +** Description This function sends data in a GKI buffer on BNEP connection +** +** Parameters: handle - handle of the connection to write +** p_dest_addr - BD_ADDR/Ethernet addr of the destination +** p_buf - pointer to address of buffer with data +** protocol - protocol type of the packet +** p_src_addr - (optional) BD_ADDR/ethernet address of the source +** (should be NULL if it is local BD Addr) +** fw_ext_present - forwarded extensions present +** +** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid +** BNEP_MTU_EXCEDED - If the data length is greater than MTU +** BNEP_IGNORE_CMD - If the packet is filtered out +** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full +** BNEP_SUCCESS - If written successfully +** +*******************************************************************************/ +tBNEP_RESULT BNEP_WriteBuf (UINT16 handle, + UINT8 *p_dest_addr, + BT_HDR *p_buf, + UINT16 protocol, + UINT8 *p_src_addr, + BOOLEAN fw_ext_present) +{ + tBNEP_CONN *p_bcb; + UINT8 *p_data; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + { + GKI_freebuf (p_buf); + return (BNEP_WRONG_HANDLE); + } + + p_bcb = &(bnep_cb.bcb[handle - 1]); + /* Check MTU size */ + if (p_buf->len > BNEP_MTU_SIZE) + { + BNEP_TRACE_ERROR2 ("BNEP_Write() length %d exceeded MTU %d", p_buf->len, BNEP_MTU_SIZE); + GKI_freebuf (p_buf); + return (BNEP_MTU_EXCEDED); + } + + /* Check if the packet should be filtered out */ + p_data = (UINT8 *)(p_buf + 1) + p_buf->offset; + if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS) + { + /* + ** If packet is filtered and ext headers are present + ** drop the data and forward the ext headers + */ + if (fw_ext_present) + { + UINT8 ext, length; + UINT16 org_len, new_len; + /* parse the extension headers and findout the new packet len */ + org_len = p_buf->len; + new_len = 0; + do { + + ext = *p_data++; + length = *p_data++; + p_data += length; + + new_len += (length + 2); + + if (new_len > org_len) + { + GKI_freebuf (p_buf); + return BNEP_IGNORE_CMD; + } + + } while (ext & 0x80); + + if (protocol != BNEP_802_1_P_PROTOCOL) + protocol = 0; + else + { + new_len += 4; + p_data[2] = 0; + p_data[3] = 0; + } + p_buf->len = new_len; + } + else + { + GKI_freebuf (p_buf); + return BNEP_IGNORE_CMD; + } + } + + /* Check transmit queue */ + if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH) + { + GKI_freebuf (p_buf); + return (BNEP_Q_SIZE_EXCEEDED); + } + + /* Build the BNEP header */ + bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present); + + /* Send the data or queue it up */ + bnepu_check_send_packet (p_bcb, p_buf); + + return (BNEP_SUCCESS); +} + + +/******************************************************************************* +** +** Function BNEP_Write +** +** Description This function sends data over a BNEP connection +** +** Parameters: handle - handle of the connection to write +** p_dest_addr - BD_ADDR/Ethernet addr of the destination +** p_data - pointer to data start +** protocol - protocol type of the packet +** p_src_addr - (optional) BD_ADDR/ethernet address of the source +** (should be NULL if it is local BD Addr) +** fw_ext_present - forwarded extensions present +** +** Returns: BNEP_WRONG_HANDLE - if passed handle is not valid +** BNEP_MTU_EXCEDED - If the data length is greater than MTU +** BNEP_IGNORE_CMD - If the packet is filtered out +** BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full +** BNEP_NO_RESOURCES - If not able to allocate a buffer +** BNEP_SUCCESS - If written successfully +** +*******************************************************************************/ +tBNEP_RESULT BNEP_Write (UINT16 handle, + UINT8 *p_dest_addr, + UINT8 *p_data, + UINT16 len, + UINT16 protocol, + UINT8 *p_src_addr, + BOOLEAN fw_ext_present) +{ + BT_HDR *p_buf; + tBNEP_CONN *p_bcb; + UINT8 *p; + + /* Check MTU size. Consider the possibility of having extension headers */ + if (len > BNEP_MTU_SIZE) + { + BNEP_TRACE_ERROR2 ("BNEP_Write() length %d exceeded MTU %d", len, BNEP_MTU_SIZE); + return (BNEP_MTU_EXCEDED); + } + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + /* Check if the packet should be filtered out */ + if (bnep_is_packet_allowed (p_bcb, p_dest_addr, protocol, fw_ext_present, p_data) != BNEP_SUCCESS) + { + /* + ** If packet is filtered and ext headers are present + ** drop the data and forward the ext headers + */ + if (fw_ext_present) + { + UINT8 ext, length; + UINT16 org_len, new_len; + /* parse the extension headers and findout the new packet len */ + org_len = len; + new_len = 0; + p = p_data; + do { + + ext = *p_data++; + length = *p_data++; + p_data += length; + + new_len += (length + 2); + + if (new_len > org_len) + return BNEP_IGNORE_CMD; + + } while (ext & 0x80); + + if (protocol != BNEP_802_1_P_PROTOCOL) + protocol = 0; + else + { + new_len += 4; + p_data[2] = 0; + p_data[3] = 0; + } + len = new_len; + p_data = p; + } + else + return BNEP_IGNORE_CMD; + } + + /* Check transmit queue */ + if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH) + return (BNEP_Q_SIZE_EXCEEDED); + + /* Get a buffer to copy teh data into */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP_Write() not able to get buffer"); + return (BNEP_NO_RESOURCES); + } + + p_buf->len = len; + p_buf->offset = BNEP_MINIMUM_OFFSET; + p = (UINT8 *)(p_buf + 1) + BNEP_MINIMUM_OFFSET; + + memcpy (p, p_data, len); + + /* Build the BNEP header */ + bnepu_build_bnep_hdr (p_bcb, p_buf, protocol, p_src_addr, p_dest_addr, fw_ext_present); + + /* Send the data or queue it up */ + bnepu_check_send_packet (p_bcb, p_buf); + + return (BNEP_SUCCESS); +} + + +/******************************************************************************* +** +** Function BNEP_SetProtocolFilters +** +** Description This function sets the protocol filters on peer device +** +** Parameters: handle - Handle for the connection +** num_filters - total number of filter ranges +** p_start_array - Array of beginings of all protocol ranges +** p_end_array - Array of ends of all protocol ranges +** +** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid +** BNEP_SET_FILTER_FAIL - if the connection is in wrong state +** BNEP_TOO_MANY_FILTERS - if too many filters +** BNEP_SUCCESS - if request sent successfully +** +*******************************************************************************/ +tBNEP_RESULT BNEP_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) + UINT16 xx; + tBNEP_CONN *p_bcb; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + /* Check the connection state */ + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + return (BNEP_WRONG_STATE); + + /* Validate the parameters */ + if (num_filters && (!p_start_array || !p_end_array)) + return (BNEP_SET_FILTER_FAIL); + + if (num_filters > BNEP_MAX_PROT_FILTERS) + return (BNEP_TOO_MANY_FILTERS); + + /* Fill the filter values in connnection block */ + for (xx = 0; xx < num_filters; xx++) + { + p_bcb->sent_prot_filter_start[xx] = *p_start_array++; + p_bcb->sent_prot_filter_end[xx] = *p_end_array++; + } + + p_bcb->sent_num_filters = num_filters; + + bnepu_send_peer_our_filters (p_bcb); + + return (BNEP_SUCCESS); +#else + return (BNEP_SET_FILTER_FAIL); +#endif +} + + +/******************************************************************************* +** +** Function BNEP_SetMulticastFilters +** +** Description This function sets the filters for multicast addresses for BNEP. +** +** Parameters: handle - Handle for the connection +** num_filters - total number of filter ranges +** p_start_array - Pointer to sequence of beginings of all +** multicast address ranges +** p_end_array - Pointer to sequence of ends of all +** multicast address ranges +** +** Returns BNEP_WRONG_HANDLE - if the connection handle is not valid +** BNEP_SET_FILTER_FAIL - if the connection is in wrong state +** BNEP_TOO_MANY_FILTERS - if too many filters +** BNEP_SUCCESS - if request sent successfully +** +*******************************************************************************/ +tBNEP_RESULT BNEP_SetMulticastFilters (UINT16 handle, + UINT16 num_filters, + UINT8 *p_start_array, + UINT8 *p_end_array) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + UINT16 xx; + tBNEP_CONN *p_bcb; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + /* Check the connection state */ + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + return (BNEP_WRONG_STATE); + + /* Validate the parameters */ + if (num_filters && (!p_start_array || !p_end_array)) + return (BNEP_SET_FILTER_FAIL); + + if (num_filters > BNEP_MAX_MULTI_FILTERS) + return (BNEP_TOO_MANY_FILTERS); + + /* Fill the multicast filter values in connnection block */ + for (xx = 0; xx < num_filters; xx++) + { + memcpy (p_bcb->sent_mcast_filter_start[xx], p_start_array, BD_ADDR_LEN); + memcpy (p_bcb->sent_mcast_filter_end[xx], p_end_array, BD_ADDR_LEN); + + p_start_array += BD_ADDR_LEN; + p_end_array += BD_ADDR_LEN; + } + + p_bcb->sent_mcast_filters = num_filters; + + bnepu_send_peer_our_multi_filters (p_bcb); + + return (BNEP_SUCCESS); +#else + return (BNEP_SET_FILTER_FAIL); +#endif +} + + +/******************************************************************************* +** +** Function BNEP_GetMyBdAddr +** +** Description This function returns a pointer to the local device BD address. +** If the BD address has not been read yet, it returns NULL. +** +** Returns the BD address +** +*******************************************************************************/ +UINT8 *BNEP_GetMyBdAddr (void) +{ + if (bnep_cb.got_my_bd_addr) + return (bnep_cb.my_bda); + else + return (NULL); +} + +/******************************************************************************* +** +** Function BNEP_SetTraceLevel +** +** Description This function sets the trace level for BNEP. If called with +** a value of 0xFF, it simply reads the current trace level. +** +** Returns the new (current) trace level +** +*******************************************************************************/ +UINT8 BNEP_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) + bnep_cb.trace_level = new_level; + + return (bnep_cb.trace_level); +} + + +/******************************************************************************* +** +** Function BNEP_GetStatus +** +** Description This function gets the status information for BNEP connection +** +** Returns BNEP_SUCCESS - if the status is available +** BNEP_NO_RESOURCES - if no structure is passed for output +** BNEP_WRONG_HANDLE - if the handle is invalid +** BNEP_WRONG_STATE - if not in connected state +** +*******************************************************************************/ +tBNEP_RESULT BNEP_GetStatus (UINT16 handle, tBNEP_STATUS *p_status) +{ +#if (defined (BNEP_SUPPORTS_STATUS_API) && BNEP_SUPPORTS_STATUS_API == TRUE) + tBNEP_CONN *p_bcb; + + if (!p_status) + return BNEP_NO_RESOURCES; + + if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) + return (BNEP_WRONG_HANDLE); + + p_bcb = &(bnep_cb.bcb[handle - 1]); + + memset (p_status, 0, sizeof (tBNEP_STATUS)); + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + return BNEP_WRONG_STATE; + + /* Read the status parameters from the connection control block */ + p_status->con_status = BNEP_STATUS_CONNECTED; + p_status->l2cap_cid = p_bcb->l2cap_cid; + p_status->rem_mtu_size = p_bcb->rem_mtu_size; + p_status->xmit_q_depth = p_bcb->xmit_q.count; + p_status->sent_num_filters = p_bcb->sent_num_filters; + p_status->sent_mcast_filters = p_bcb->sent_mcast_filters; + p_status->rcvd_num_filters = p_bcb->rcvd_num_filters; + p_status->rcvd_mcast_filters = p_bcb->rcvd_mcast_filters; + + memcpy (p_status->rem_bda, p_bcb->rem_bda, BD_ADDR_LEN); + memcpy (&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof (tBT_UUID)); + memcpy (&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof (tBT_UUID)); + + return BNEP_SUCCESS; +#else + return (BNEP_IGNORE_CMD); +#endif +} + + diff --git a/stack/bnep/bnep_int.h b/stack/bnep/bnep_int.h new file mode 100644 index 0000000..a849052 --- /dev/null +++ b/stack/bnep/bnep_int.h @@ -0,0 +1,238 @@ +/****************************************************************************/ +/* */ +/* Name: bnep_int.h */ +/* */ +/* Function this file contains internally used BNEP definitions */ +/* */ +/* */ +/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */ +/* WIDCOMM Bluetooth Core. Proprietary and confidential. */ +/* */ +/****************************************************************************/ +#ifndef BNEP_INT_H +#define BNEP_INT_H + +#include "bt_target.h" +#include "gki.h" +#include "bnep_api.h" +#include "btm_int.h" +#include "btu.h" + + +/* BNEP frame types +*/ +#define BNEP_FRAME_GENERAL_ETHERNET 0x00 +#define BNEP_FRAME_CONTROL 0x01 +#define BNEP_FRAME_COMPRESSED_ETHERNET 0x02 +#define BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY 0x03 +#define BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY 0x04 + + +/* BNEP filter control message types +*/ +#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD 0x00 +#define BNEP_SETUP_CONNECTION_REQUEST_MSG 0x01 +#define BNEP_SETUP_CONNECTION_RESPONSE_MSG 0x02 +#define BNEP_FILTER_NET_TYPE_SET_MSG 0x03 +#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG 0x04 +#define BNEP_FILTER_MULTI_ADDR_SET_MSG 0x05 +#define BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG 0x06 + + +/* BNEP header extension types +*/ +#define BNEP_EXTENSION_FILTER_CONTROL 0x00 + + +/* BNEP Setup Connection response codes +*/ +#define BNEP_SETUP_CONN_OK 0x0000 +#define BNEP_SETUP_INVALID_DEST_UUID 0x0001 +#define BNEP_SETUP_INVALID_SRC_UUID 0x0002 +#define BNEP_SETUP_INVALID_UUID_SIZE 0x0003 +#define BNEP_SETUP_CONN_NOT_ALLOWED 0x0004 + + +/* BNEP filter control response codes +*/ +#define BNEP_FILTER_CRL_OK 0x0000 +#define BNEP_FILTER_CRL_UNSUPPORTED 0x0001 +#define BNEP_FILTER_CRL_BAD_RANGE 0x0002 +#define BNEP_FILTER_CRL_MAX_REACHED 0x0003 +#define BNEP_FILTER_CRL_SECURITY_ERR 0x0004 + + +/* 802.1p protocol packet will have actual protocol field in side the payload */ +#define BNEP_802_1_P_PROTOCOL 0x8100 + +/* Timeout definitions. +*/ +#define BNEP_CONN_TIMEOUT 20 /* Connection related timeout */ +#define BNEP_HOST_TIMEOUT 200 /* host responce timeout */ +#define BNEP_FILTER_SET_TIMEOUT 10 + +/* Define the Out-Flow default values. */ +#define BNEP_OFLOW_QOS_FLAG 0 +#define BNEP_OFLOW_SERV_TYPE 0 +#define BNEP_OFLOW_TOKEN_RATE 0 +#define BNEP_OFLOW_TOKEN_BUCKET_SIZE 0 +#define BNEP_OFLOW_PEAK_BANDWIDTH 0 +#define BNEP_OFLOW_LATENCY 0 +#define BNEP_OFLOW_DELAY_VARIATION 0 + +/* Define the In-Flow default values. */ +#define BNEP_IFLOW_QOS_FLAG 0 +#define BNEP_IFLOW_SERV_TYPE 0 +#define BNEP_IFLOW_TOKEN_RATE 0 +#define BNEP_IFLOW_TOKEN_BUCKET_SIZE 0 +#define BNEP_IFLOW_PEAK_BANDWIDTH 0 +#define BNEP_IFLOW_LATENCY 0 +#define BNEP_IFLOW_DELAY_VARIATION 0 + +#define BNEP_FLUSH_TO 0xFFFF + +#define BNEP_MAX_RETRANSMITS 3 + +/* Define the BNEP Connection Control Block +*/ +typedef struct +{ +#define BNEP_STATE_IDLE 0 +#define BNEP_STATE_CONN_START 1 +#define BNEP_STATE_CFG_SETUP 2 +#define BNEP_STATE_CONN_SETUP 3 +#define BNEP_STATE_SEC_CHECKING 4 +#define BNEP_STATE_SETUP_RCVD 5 +#define BNEP_STATE_CONNECTED 6 + UINT8 con_state; + +#define BNEP_FLAGS_IS_ORIG 0x01 +#define BNEP_FLAGS_HIS_CFG_DONE 0x02 +#define BNEP_FLAGS_MY_CFG_DONE 0x04 +#define BNEP_FLAGS_L2CAP_CONGESTED 0x08 +#define BNEP_FLAGS_FILTER_RESP_PEND 0x10 +#define BNEP_FLAGS_MULTI_RESP_PEND 0x20 +#define BNEP_FLAGS_SETUP_RCVD 0x40 +#define BNEP_FLAGS_CONN_COMPLETED 0x80 + UINT8 con_flags; + BT_HDR *p_pending_data; + + UINT16 l2cap_cid; + BD_ADDR rem_bda; + UINT16 rem_mtu_size; + TIMER_LIST_ENT conn_tle; + BUFFER_Q xmit_q; + + UINT16 sent_num_filters; + UINT16 sent_prot_filter_start[BNEP_MAX_PROT_FILTERS]; + UINT16 sent_prot_filter_end[BNEP_MAX_PROT_FILTERS]; + + UINT16 sent_mcast_filters; + BD_ADDR sent_mcast_filter_start[BNEP_MAX_MULTI_FILTERS]; + BD_ADDR sent_mcast_filter_end[BNEP_MAX_MULTI_FILTERS]; + + UINT16 rcvd_num_filters; + UINT16 rcvd_prot_filter_start[BNEP_MAX_PROT_FILTERS]; + UINT16 rcvd_prot_filter_end[BNEP_MAX_PROT_FILTERS]; + + UINT16 rcvd_mcast_filters; + BD_ADDR rcvd_mcast_filter_start[BNEP_MAX_MULTI_FILTERS]; + BD_ADDR rcvd_mcast_filter_end[BNEP_MAX_MULTI_FILTERS]; + + UINT16 bad_pkts_rcvd; + UINT8 re_transmits; + UINT16 handle; + tBT_UUID prv_src_uuid; + tBT_UUID prv_dst_uuid; + tBT_UUID src_uuid; + tBT_UUID dst_uuid; + +} tBNEP_CONN; + + +/* The main BNEP control block +*/ +typedef struct +{ + tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */ + tBNEP_CONN bcb[BNEP_MAX_CONNECTIONS]; + + tBNEP_CONNECT_IND_CB *p_conn_ind_cb; + tBNEP_CONN_STATE_CB *p_conn_state_cb; + tBNEP_DATA_IND_CB *p_data_ind_cb; + tBNEP_DATA_BUF_CB *p_data_buf_cb; + tBNEP_FILTER_IND_CB *p_filter_ind_cb; + tBNEP_MFILTER_IND_CB *p_mfilter_ind_cb; + tBNEP_TX_DATA_FLOW_CB *p_tx_data_flow_cb; + + tL2CAP_APPL_INFO reg_info; + + TIMER_LIST_ENT bnep_tle; + BOOLEAN profile_registered; /* TRUE when we got our BD addr */ + UINT8 trace_level; + BOOLEAN got_my_bd_addr; /* TRUE when we got our BD addr */ + BD_ADDR my_bda; /* BD Address of this device */ + +} tBNEP_CB; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global BNEP data +*/ +#if BNEP_DYNAMIC_MEMORY == FALSE +BNEP_API extern tBNEP_CB bnep_cb; +#else +BNEP_API extern tBNEP_CB *bnep_cb_ptr; +#define bnep_cb (*bnep_cb_ptr) +#endif + +/* Functions provided by bnep_main.c +*/ +extern tBNEP_RESULT bnep_register_with_l2cap (void); +extern void bnep_disconnect (tBNEP_CONN *p_bcb, UINT16 reason); +extern tBNEP_CONN *bnep_conn_originate (UINT8 *p_bd_addr); +extern void bnep_process_timeout (TIMER_LIST_ENT *p_tle); +extern void bnep_connected (tBNEP_CONN *p_bcb); + + +/* Functions provided by bnep_utils.c +*/ +extern tBNEP_CONN *bnepu_find_bcb_by_cid (UINT16 cid); +extern tBNEP_CONN *bnepu_find_bcb_by_bd_addr (UINT8 *p_bda); +extern tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda); +extern void bnepu_release_bcb (tBNEP_CONN *p_bcb); +extern void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb); +extern void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb); +extern BOOLEAN bnepu_does_dest_support_prot (tBNEP_CONN *p_bcb, UINT16 protocol); +extern void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol, + UINT8 *p_src_addr, UINT8 *p_dest_addr, BOOLEAN ext_bit); +extern void test_bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol, + UINT8 *p_src_addr, UINT8 *p_dest_addr, UINT8 type); + +extern tBNEP_CONN *bnepu_get_route_to_dest (UINT8 *p_bda); +extern void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf); +extern void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, UINT8 cmd_code); +extern void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len); +extern void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data); +extern void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data); +extern void bnep_send_conn_req (tBNEP_CONN *p_bcb); +extern void bnep_send_conn_responce (tBNEP_CONN *p_bcb, UINT16 resp_code); +extern void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, UINT8 *p_setup, UINT8 len); +extern void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup); +extern UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *len, BOOLEAN is_ext); +extern void bnep_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 result); +extern tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, BD_ADDR p_dest_addr, UINT16 protocol, BOOLEAN fw_ext_present, UINT8 *p_data); +extern UINT32 bnep_get_uuid32 (tBT_UUID *src_uuid); +extern void bnep_dump_status (void); + + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/stack/bnep/bnep_main.c b/stack/bnep/bnep_main.c new file mode 100644 index 0000000..fca0d22 --- /dev/null +++ b/stack/bnep/bnep_main.c @@ -0,0 +1,825 @@ +/***************************************************************************** +** +** Name: bnep_main.c +** +** Description: this file contains the main BNEP functions +** +** +** Copyright (c) 2001-2008, Broadcom Corp., All Rights Reserved. +** WIDCOMM Bluetooth Core. Proprietary and confidential. +******************************************************************************/ + +#include "bt_target.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "gki.h" +#include "bt_types.h" +#include "l2cdefs.h" +#include "hcidefs.h" +#include "hcimsgs.h" + +#include "l2c_api.h" +#include "l2cdefs.h" + +#include "btu.h" +#include "btm_api.h" + +#include "bnep_api.h" +#include "bnep_int.h" + + +/********************************************************************************/ +/* G L O B A L B N E P D A T A */ +/********************************************************************************/ +#if BNEP_DYNAMIC_MEMORY == FALSE +tBNEP_CB bnep_cb; +#endif + +const UINT16 bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8}; + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static void bnep_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id); +static void bnep_connect_cfm (UINT16 l2cap_cid, UINT16 result); +static void bnep_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void bnep_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg); +static void bnep_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed); +static void bnep_disconnect_cfm (UINT16 l2cap_cid, UINT16 result); +static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg); +static void bnep_congestion_ind (UINT16 lcid, BOOLEAN is_congested); + +static void bnep_read_addr_cb (void *p_bda); + + +/******************************************************************************* +** +** Function bnep_register_with_l2cap +** +** Description This function registers BNEP PSM with L2CAP +** +** Returns void +** +*******************************************************************************/ +tBNEP_RESULT bnep_register_with_l2cap (void) +{ + /* Initialize the L2CAP configuration. We only care about MTU and flush */ + memset(&bnep_cb.l2cap_my_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + + bnep_cb.l2cap_my_cfg.mtu_present = TRUE; + bnep_cb.l2cap_my_cfg.mtu = BNEP_MTU_SIZE; + bnep_cb.l2cap_my_cfg.flush_to_present = TRUE; + bnep_cb.l2cap_my_cfg.flush_to = BNEP_FLUSH_TO; + + bnep_cb.reg_info.pL2CA_ConnectInd_Cb = bnep_connect_ind; + bnep_cb.reg_info.pL2CA_ConnectCfm_Cb = bnep_connect_cfm; + bnep_cb.reg_info.pL2CA_ConfigInd_Cb = bnep_config_ind; + bnep_cb.reg_info.pL2CA_ConfigCfm_Cb = bnep_config_cfm; + bnep_cb.reg_info.pL2CA_DisconnectInd_Cb = bnep_disconnect_ind; + bnep_cb.reg_info.pL2CA_DisconnectCfm_Cb = bnep_disconnect_cfm; + bnep_cb.reg_info.pL2CA_DataInd_Cb = bnep_data_ind; + bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind; + + /* Now, register with L2CAP */ + if (!L2CA_Register (BT_PSM_BNEP, &bnep_cb.reg_info)) + { + BNEP_TRACE_ERROR0 ("BNEP - Registration failed"); + return BNEP_SECURITY_FAIL; + } + + return BNEP_SUCCESS; +} + + +/******************************************************************************* +** +** Function bnep_connect_ind +** +** Description This function handles an inbound connection indication +** from L2CAP. This is the case where we are acting as a +** server. +** +** Returns void +** +*******************************************************************************/ +static void bnep_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id) +{ + tBNEP_CONN *p_bcb = bnepu_find_bcb_by_bd_addr (bd_addr); + + /* If we are not acting as server, or already have a connection, or have */ + /* no more resources to handle the connection, reject the connection. */ + if (!(bnep_cb.profile_registered) || (p_bcb) + || ((p_bcb = bnepu_allocate_bcb(bd_addr)) == NULL)) + { + L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0); + return; + } + + /* Transition to the next appropriate state, waiting for config setup. */ + p_bcb->con_state = BNEP_STATE_CFG_SETUP; + + /* Save the L2CAP Channel ID. */ + p_bcb->l2cap_cid = l2cap_cid; + + /* Send response to the L2CAP layer. */ + L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK); + + /* Send a Configuration Request. */ + L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg); + + /* Start timer waiting for config setup */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); + + BNEP_TRACE_EVENT1("BNEP - Rcvd L2CAP conn ind, CID: 0x%x", p_bcb->l2cap_cid); + +} + + +/******************************************************************************* +** +** Function bnep_connect_cfm +** +** Description This function handles the connect confirm events +** from L2CAP. This is the case when we are acting as a +** client and have sent a connect request. +** +** Returns void +** +*******************************************************************************/ +static void bnep_connect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + tBNEP_CONN *bcb; + + /* Find CCB based on CID */ + if ((bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid); + return; + } + + /* If the connection response contains success status, then */ + /* Transition to the next state and startup the timer. */ + if ((result == L2CAP_CONN_OK) && (bcb->con_state == BNEP_STATE_CONN_START)) + { + bcb->con_state = BNEP_STATE_CFG_SETUP; + + /* Send a Configuration Request. */ + L2CA_ConfigReq (l2cap_cid, &bnep_cb.l2cap_my_cfg); + + /* Start timer waiting for config results */ + btu_start_timer (&bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); + + BNEP_TRACE_EVENT1 ("BNEP - got conn cnf, sent cfg req, CID: 0x%x", bcb->l2cap_cid); + } + else + { + BNEP_TRACE_WARNING2 ("BNEP - Rcvd conn cnf with error: 0x%x CID 0x%x", result, bcb->l2cap_cid); + + /* Tell the upper layer, if he has a callback */ + if (bnep_cb.p_conn_state_cb && + bcb->con_flags & BNEP_FLAGS_IS_ORIG) + { + (*bnep_cb.p_conn_state_cb) (bcb->handle, bcb->rem_bda, BNEP_CONN_FAILED, FALSE); + } + + bnepu_release_bcb (bcb); + } +} + +/******************************************************************************* +** +** Function bnep_config_ind +** +** Description This function processes the L2CAP configuration indication +** event. +** +** Returns void +** +*******************************************************************************/ +static void bnep_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tBNEP_CONN *p_bcb; + UINT16 result, mtu = 0; + + /* Find CCB based on CID */ + if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + return; + } + + BNEP_TRACE_EVENT1 ("BNEP - Rcvd cfg ind, CID: 0x%x", l2cap_cid); + + /* Remember the remote MTU size */ + if ((!p_cfg->mtu_present) || (p_cfg->mtu < BNEP_MIN_MTU_SIZE)) + { + mtu = p_cfg->mtu; + p_cfg->flush_to_present = FALSE; + p_cfg->mtu_present = TRUE; + p_cfg->mtu = BNEP_MIN_MTU_SIZE; + p_cfg->result = result = L2CAP_CFG_UNACCEPTABLE_PARAMS; + } + else + { + if (p_cfg->mtu > BNEP_MTU_SIZE) + p_bcb->rem_mtu_size = BNEP_MTU_SIZE; + else + p_bcb->rem_mtu_size = p_cfg->mtu; + + /* For now, always accept configuration from the other side */ + p_cfg->flush_to_present = FALSE; + p_cfg->mtu_present = FALSE; + p_cfg->result = result = L2CAP_CFG_OK; + } + + L2CA_ConfigRsp (l2cap_cid, p_cfg); + + if (result != L2CAP_CFG_OK) + { + BNEP_TRACE_EVENT2 ("BNEP - Rcvd cfg ind with bad MTU %d, CID: 0x%x", mtu, l2cap_cid); + return; + } + + p_bcb->con_flags |= BNEP_FLAGS_HIS_CFG_DONE; + + if (p_bcb->con_flags & BNEP_FLAGS_MY_CFG_DONE) + { + p_bcb->con_state = BNEP_STATE_SEC_CHECKING; + + /* Start timer waiting for setup or response */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_HOST_TIMEOUT); + + if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) + { + btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE, + BTM_SEC_PROTO_BNEP, + bnep_get_uuid32(&(p_bcb->src_uuid)), + &bnep_sec_check_complete, p_bcb); + } + } +} + + +/******************************************************************************* +** +** Function bnep_config_cfm +** +** Description This function processes the L2CAP configuration confirmation +** event. +** +** Returns void +** +*******************************************************************************/ +static void bnep_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) +{ + tBNEP_CONN *p_bcb; + + BNEP_TRACE_EVENT2 ("BNEP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result); + + /* Find CCB based on CID */ + if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid); + return; + } + + /* For now, always accept configuration from the other side */ + if (p_cfg->result == L2CAP_CFG_OK) + { + p_bcb->con_flags |= BNEP_FLAGS_MY_CFG_DONE; + + if (p_bcb->con_flags & BNEP_FLAGS_HIS_CFG_DONE) + { + p_bcb->con_state = BNEP_STATE_SEC_CHECKING; + + /* Start timer waiting for setup or response */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_HOST_TIMEOUT); + + if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) + { + btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, TRUE, + BTM_SEC_PROTO_BNEP, + bnep_get_uuid32(&(p_bcb->src_uuid)), + &bnep_sec_check_complete, p_bcb); + } + } + } + else + { + /* Tell the upper layer, if he has a callback */ + if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) + { + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED_CFG, FALSE); + } + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + bnepu_release_bcb (p_bcb); + } +} + + +/******************************************************************************* +** +** Function bnep_disconnect_ind +** +** Description This function handles a disconnect event from L2CAP. If +** requested to, we ack the disconnect before dropping the CCB +** +** Returns void +** +*******************************************************************************/ +static void bnep_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed) +{ + tBNEP_CONN *p_bcb; + + if (ack_needed) + L2CA_DisconnectRsp (l2cap_cid); + + /* Find CCB based on CID */ + if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid); + return; + } + + BNEP_TRACE_EVENT1 ("BNEP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); + + /* Tell the user if he has a callback */ + if (p_bcb->con_state == BNEP_STATE_CONNECTED) + { + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_DISCONNECTED, FALSE); + } + else + { + if (((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) || + p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE); + } + + bnepu_release_bcb (p_bcb); +} + + + +/******************************************************************************* +** +** Function bnep_disconnect_cfm +** +** Description This function gets the disconnect confirm event from L2CAP +** +** Returns void +** +*******************************************************************************/ +static void bnep_disconnect_cfm (UINT16 l2cap_cid, UINT16 result) +{ + BNEP_TRACE_EVENT2 ("BNEP - Rcvd L2CAP disc cfm, CID: 0x%x, Result 0x%x", l2cap_cid, result); +} + + + +/******************************************************************************* +** +** Function bnep_congestion_ind +** +** Description This is a callback function called by L2CAP when +** congestion status changes +** +*******************************************************************************/ +static void bnep_congestion_ind (UINT16 l2cap_cid, BOOLEAN is_congested) +{ + tBNEP_CONN *p_bcb; + + /* Find BCB based on CID */ + if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP cong, unknown CID: 0x%x", l2cap_cid); + return; + } + + if (is_congested) + { + p_bcb->con_flags |= BNEP_FLAGS_L2CAP_CONGESTED; + if(bnep_cb.p_tx_data_flow_cb) + { + bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_OFF); + } + } + else + { + p_bcb->con_flags &= ~BNEP_FLAGS_L2CAP_CONGESTED; + + if(bnep_cb.p_tx_data_flow_cb) + { + bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_ON); + } + + /* While not congested, send as many buffers as we can */ + while (!(p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED)) + { + BT_HDR *p_buf = (BT_HDR *)GKI_dequeue (&p_bcb->xmit_q); + + if (!p_buf) + break; + + L2CA_DataWrite (l2cap_cid, p_buf); + } + } +} + + + +/******************************************************************************* +** +** Function bnep_data_ind +** +** Description This function is called when data is received from L2CAP. +** if we are the originator of the connection, we are the SDP +** client, and the received message is queued up for the client. +** +** If we are the destination of the connection, we are the SDP +** server, so the message is passed to the server processing +** function. +** +** Returns void +** +*******************************************************************************/ +static void bnep_data_ind (UINT16 l2cap_cid, BT_HDR *p_buf) +{ + tBNEP_CONN *p_bcb; + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + UINT16 rem_len = p_buf->len; + UINT8 type, ctrl_type, ext_type = 0; + BOOLEAN extension_present, fw_ext_present; + UINT16 protocol = 0; + UINT8 *p_src_addr, *p_dst_addr; + + + /* Find CCB based on CID */ + if ((p_bcb = bnepu_find_bcb_by_cid (l2cap_cid)) == NULL) + { + BNEP_TRACE_WARNING1 ("BNEP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid); + GKI_freebuf (p_buf); + return; + } + + /* Get the type and extension bits */ + type = *p++; + extension_present = type >> 7; + type &= 0x7f; + if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE)) + { + BNEP_TRACE_EVENT2 ("BNEP - rcvd frame, bad len: %d type: 0x%02x", p_buf->len, type); + GKI_freebuf (p_buf); + return; + } + + rem_len--; + + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)) && + (type != BNEP_FRAME_CONTROL)) + { + BNEP_TRACE_WARNING2 ("BNEP - Ignored L2CAP data while in state: %d, CID: 0x%x", + p_bcb->con_state, l2cap_cid); + + if (extension_present) + { + /* + ** When there is no connection if a data packet is received + ** with unknown control extension headers then those should be processed + ** according to complain/ignore law + */ + UINT8 ext, length, *p_data; + UINT16 org_len, new_len; + /* parse the extension headers and process unknown control headers */ + org_len = rem_len; + new_len = 0; + p_data = p; + do { + + ext = *p++; + length = *p++; + p += length; + + if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG)) + bnep_send_command_not_understood (p_bcb, *p); + + new_len += (length + 2); + + if (new_len > org_len) + break; + + } while (ext & 0x80); + } + + GKI_freebuf (p_buf); + return; + } + + if (type > BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY) + { + BNEP_TRACE_EVENT1 ("BNEP - rcvd frame, unknown type: 0x%02x", type); + GKI_freebuf (p_buf); + return; + } + + BNEP_TRACE_DEBUG3 ("BNEP - rcv frame, type: %d len: %d Ext: %d", type, p_buf->len, extension_present); + + /* Initialize addresses to 'not supplied' */ + p_src_addr = p_dst_addr = NULL; + + switch (type) + { + case BNEP_FRAME_GENERAL_ETHERNET: + p_dst_addr = p; + p += BD_ADDR_LEN; + p_src_addr = p; + p += BD_ADDR_LEN; + BE_STREAM_TO_UINT16 (protocol, p); + rem_len -= 14; + break; + + case BNEP_FRAME_CONTROL: + ctrl_type = *p; + p = bnep_process_control_packet (p_bcb, p, &rem_len, FALSE); + + if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG && + p_bcb->con_state != BNEP_STATE_CONNECTED && + extension_present && p && rem_len) + { + p_bcb->p_pending_data = (BT_HDR *)GKI_getbuf (rem_len); + if (p_bcb->p_pending_data) + { + memcpy ((UINT8 *)(p_bcb->p_pending_data + 1), p, rem_len); + p_bcb->p_pending_data->len = rem_len; + p_bcb->p_pending_data->offset = 0; + } + } + else + { + while (extension_present && p && rem_len) + { + ext_type = *p++; + extension_present = ext_type >> 7; + ext_type &= 0x7F; + + /* if unknown extension present stop processing */ + if (ext_type) + break; + + p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE); + } + } + GKI_freebuf (p_buf); + return; + + case BNEP_FRAME_COMPRESSED_ETHERNET: + BE_STREAM_TO_UINT16 (protocol, p); + rem_len -= 2; + break; + + case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY: + p_src_addr = p; + p += BD_ADDR_LEN; + BE_STREAM_TO_UINT16 (protocol, p); + rem_len -= 8; + break; + + case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY: + p_dst_addr = p; + p += BD_ADDR_LEN; + BE_STREAM_TO_UINT16 (protocol, p); + rem_len -= 8; + break; + } + + /* Process the header extension if there is one */ + while (extension_present && p && rem_len) + { + ext_type = *p; + extension_present = ext_type >> 7; + ext_type &= 0x7F; + + /* if unknown extension present stop processing */ + if (ext_type) + { + BNEP_TRACE_EVENT1 ("Data extension type 0x%x found", ext_type); + break; + } + + p++; + rem_len--; + p = bnep_process_control_packet (p_bcb, p, &rem_len, TRUE); + } + + p_buf->offset += p_buf->len - rem_len; + p_buf->len = rem_len; + + /* Always give the upper layer MAC addresses */ + if (!p_src_addr) + p_src_addr = (UINT8 *) p_bcb->rem_bda; + + if (!p_dst_addr) + p_dst_addr = (UINT8 *) bnep_cb.my_bda; + + /* check whether there are any extensions to be forwarded */ + if (ext_type) + fw_ext_present = TRUE; + else + fw_ext_present = FALSE; + + if (bnep_cb.p_data_buf_cb) + { + (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p_buf, fw_ext_present); + } + else if (bnep_cb.p_data_ind_cb) + { + (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p, rem_len, fw_ext_present); + GKI_freebuf (p_buf); + } +} + + + +/******************************************************************************* +** +** Function bnep_process_timeout +** +** Description This function processes a timeout. If it is a startup +** timeout, we check for reading our BD address. If it +** is an L2CAP timeout, we send a disconnect req to L2CAP. +** +** Returns void +** +*******************************************************************************/ +void bnep_process_timeout (TIMER_LIST_ENT *p_tle) +{ + tBNEP_CONN *p_bcb; + + if (!p_tle->param) + { + if (!bnep_cb.got_my_bd_addr) + { + if (BTM_IsDeviceUp()) + BTM_ReadLocalDeviceAddr (bnep_read_addr_cb); + + btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2); + } + return; + } + + p_bcb = (tBNEP_CONN *)p_tle->param; + + BNEP_TRACE_EVENT4 ("BNEP - CCB timeout in state: %d CID: 0x%x flags %x, re_transmit %d", + p_bcb->con_state, p_bcb->l2cap_cid, p_bcb->con_flags, p_bcb->re_transmits); + + if (p_bcb->con_state == BNEP_STATE_CONN_SETUP) + { + BNEP_TRACE_EVENT2 ("BNEP - CCB timeout in state: %d CID: 0x%x", + p_bcb->con_state, p_bcb->l2cap_cid); + + if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) + { + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + bnepu_release_bcb (p_bcb); + return; + } + + if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) + { + bnep_send_conn_req (p_bcb); + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); + } + else + { + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE); + + bnepu_release_bcb (p_bcb); + return; + } + } + else if (p_bcb->con_state != BNEP_STATE_CONNECTED) + { + BNEP_TRACE_EVENT2 ("BNEP - CCB timeout in state: %d CID: 0x%x", + p_bcb->con_state, p_bcb->l2cap_cid); + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + /* Tell the user if he has a callback */ + if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_CONN_FAILED, FALSE); + + bnepu_release_bcb (p_bcb); + } +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND) + { + if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) + { + bnepu_send_peer_our_filters (p_bcb); + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT); + } + else + { + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + /* Tell the user if he has a callback */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, FALSE); + + bnepu_release_bcb (p_bcb); + return; + } + } +#endif +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND) + { + if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) + { + bnepu_send_peer_our_multi_filters (p_bcb); + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT); + } + else + { + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + /* Tell the user if he has a callback */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SET_FILTER_FAIL, FALSE); + + bnepu_release_bcb (p_bcb); + return; + } + } +#endif +} + + +/******************************************************************************* +** +** Function bnep_connected +** +** Description This function is called when a connection is established +** (after config). +** +** Returns void +** +*******************************************************************************/ +void bnep_connected (tBNEP_CONN *p_bcb) +{ + BOOLEAN is_role_change; + + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + is_role_change = TRUE; + else + is_role_change = FALSE; + + p_bcb->con_state = BNEP_STATE_CONNECTED; + p_bcb->con_flags |= BNEP_FLAGS_CONN_COMPLETED; + p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); + + /* Ensure timer is stopped */ + btu_stop_timer (&p_bcb->conn_tle); + p_bcb->re_transmits = 0; + + /* Tell the upper layer, if he has a callback */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SUCCESS, is_role_change); +} + + +/******************************************************************************* +** +** Function bnep_read_addr_cb +** +** Description This function is called by BTM when the local BD address +** is read. It saves the BD address, and flags it as read. +** +** Returns void +** +*******************************************************************************/ +static void bnep_read_addr_cb (void *p_bda) +{ + UINT8 *bda = (UINT8 *)p_bda; + if (p_bda && + (bda[0] | bda[1] | bda[2] | bda[3] | bda[4] | bda[5]) != 0) + { + /* Save my BD address */ + memcpy (bnep_cb.my_bda, p_bda, BD_ADDR_LEN); + + bnep_cb.got_my_bd_addr = TRUE; + } + else + /* Retry after a couple seconds */ + btu_start_timer (&bnep_cb.bnep_tle, BTU_TTYPE_BNEP, 2); +} + diff --git a/stack/bnep/bnep_utils.c b/stack/bnep/bnep_utils.c new file mode 100644 index 0000000..22c2730 --- /dev/null +++ b/stack/bnep/bnep_utils.c @@ -0,0 +1,1449 @@ +/*****************************************************************************/ +/* */ +/* Name: bnep_utils.c */ +/* */ +/* Description: this file contains BNEP utility functions */ +/* */ +/* */ +/* Copyright (c) 2001-2004, WIDCOMM Inc., All Rights Reserved. */ +/* WIDCOMM Bluetooth Core. Proprietary and confidential. */ +/*****************************************************************************/ +#include <stdio.h> +#include <string.h> +#include "gki.h" +#include "bt_types.h" +#include "bnep_int.h" +#include "btu.h" +#include "btm_int.h" + + +/********************************************************************************/ +/* L O C A L F U N C T I O N P R O T O T Y P E S */ +/********************************************************************************/ +static UINT8 *bnepu_init_hdr (BT_HDR *p_buf, UINT16 hdr_len, UINT8 pkt_type); + +void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len); +void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code); + + +/******************************************************************************* +** +** Function bnepu_find_bcb_by_cid +** +** Description This function searches the bcb table for an entry with the +** passed CID. +** +** Returns the BCB address, or NULL if not found. +** +*******************************************************************************/ +tBNEP_CONN *bnepu_find_bcb_by_cid (UINT16 cid) +{ + UINT16 xx; + tBNEP_CONN *p_bcb; + + /* Look through each connection control block */ + for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) + { + if ((p_bcb->con_state != BNEP_STATE_IDLE) && (p_bcb->l2cap_cid == cid)) + return (p_bcb); + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function bnepu_find_bcb_by_bd_addr +** +** Description This function searches the BCB table for an entry with the +** passed Bluetooth Address. +** +** Returns the BCB address, or NULL if not found. +** +*******************************************************************************/ +tBNEP_CONN *bnepu_find_bcb_by_bd_addr (UINT8 *p_bda) +{ + UINT16 xx; + tBNEP_CONN *p_bcb; + + /* Look through each connection control block */ + for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) + { + if (p_bcb->con_state != BNEP_STATE_IDLE) + { + if (!memcmp ((UINT8 *)(p_bcb->rem_bda), p_bda, BD_ADDR_LEN)) + return (p_bcb); + } + } + + /* If here, not found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function bnepu_allocate_bcb +** +** Description This function allocates a new BCB. +** +** Returns BCB address, or NULL if none available. +** +*******************************************************************************/ +tBNEP_CONN *bnepu_allocate_bcb (BD_ADDR p_rem_bda) +{ + UINT16 xx; + tBNEP_CONN *p_bcb; + + /* Look through each connection control block for a free one */ + for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) + { + if (p_bcb->con_state == BNEP_STATE_IDLE) + { + memset ((UINT8 *)p_bcb, 0, sizeof (tBNEP_CONN)); + + p_bcb->conn_tle.param = (UINT32) p_bcb; + + memcpy ((UINT8 *)(p_bcb->rem_bda), (UINT8 *)p_rem_bda, BD_ADDR_LEN); + p_bcb->handle = xx + 1; + + return (p_bcb); + } + } + + /* If here, no free BCB found */ + return (NULL); +} + + +/******************************************************************************* +** +** Function bnepu_release_bcb +** +** Description This function releases a BCB. +** +** Returns void +** +*******************************************************************************/ +void bnepu_release_bcb (tBNEP_CONN *p_bcb) +{ + /* Ensure timer is stopped */ + btu_stop_timer (&p_bcb->conn_tle); + + /* Drop any response pointer we may be holding */ + p_bcb->con_state = BNEP_STATE_IDLE; + p_bcb->p_pending_data = NULL; + + /* Free transmit queue */ + while (p_bcb->xmit_q.count) + { + GKI_freebuf (GKI_dequeue (&p_bcb->xmit_q)); + } +} + + +/******************************************************************************* +** +** Function bnep_send_conn_req +** +** Description This function sends a BNEP connection request to peer +** +** Returns void +** +*******************************************************************************/ +void bnep_send_conn_req (tBNEP_CONN *p_bcb) +{ + BT_HDR *p_buf; + UINT8 *p, *p_start; + + BNEP_TRACE_DEBUG1 ("BNEP sending setup req with dst uuid %x", p_bcb->dst_uuid.uu.uuid16); + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - not able to send connection request"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = p_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_REQUEST_MSG); + + UINT8_TO_BE_STREAM (p, p_bcb->dst_uuid.len); + + if (p_bcb->dst_uuid.len == 2) + { + UINT16_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid16); + UINT16_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid16); + } +#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE) + else if (p_bcb->dst_uuid.len == 4) + { + UINT32_TO_BE_STREAM (p, p_bcb->dst_uuid.uu.uuid32); + UINT32_TO_BE_STREAM (p, p_bcb->src_uuid.uu.uuid32); + } + else + { + memcpy (p, p_bcb->dst_uuid.uu.uuid128, p_bcb->dst_uuid.len); + p += p_bcb->dst_uuid.len; + memcpy (p, p_bcb->src_uuid.uu.uuid128, p_bcb->dst_uuid.len); + p += p_bcb->dst_uuid.len; + } +#endif + + p_buf->len = (UINT16)(p - p_start); + + bnepu_check_send_packet (p_bcb, p_buf); +} + + +/******************************************************************************* +** +** Function bnep_send_conn_responce +** +** Description This function sends a BNEP setup response to peer +** +** Returns void +** +*******************************************************************************/ +void bnep_send_conn_responce (tBNEP_CONN *p_bcb, UINT16 resp_code) +{ + BT_HDR *p_buf; + UINT8 *p; + + BNEP_TRACE_EVENT1 ("BNEP - bnep_send_conn_responce for CID: 0x%x", p_bcb->l2cap_cid); + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - not able to send connection response"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_SETUP_CONNECTION_RESPONSE_MSG); + + UINT16_TO_BE_STREAM (p, resp_code); + + p_buf->len = 4; + + bnepu_check_send_packet (p_bcb, p_buf); + +} + + +/******************************************************************************* +** +** Function bnepu_send_peer_our_filters +** +** Description This function sends our filters to a peer +** +** Returns void +** +*******************************************************************************/ +void bnepu_send_peer_our_filters (tBNEP_CONN *p_bcb) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + BT_HDR *p_buf; + UINT8 *p; + UINT16 xx; + + BNEP_TRACE_DEBUG0 ("BNEP sending peer our filters"); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - no buffer send filters"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_SET_MSG); + + UINT16_TO_BE_STREAM (p, (4 * p_bcb->sent_num_filters)); + for (xx = 0; xx < p_bcb->sent_num_filters; xx++) + { + UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_start[xx]); + UINT16_TO_BE_STREAM (p, p_bcb->sent_prot_filter_end[xx]); + } + + p_buf->len = 4 + (4 * p_bcb->sent_num_filters); + + bnepu_check_send_packet (p_bcb, p_buf); + + p_bcb->con_flags |= BNEP_FLAGS_FILTER_RESP_PEND; + + /* Start timer waiting for setup response */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT); +#endif +} + + +/******************************************************************************* +** +** Function bnepu_send_peer_our_multi_filters +** +** Description This function sends our multicast filters to a peer +** +** Returns void +** +*******************************************************************************/ +void bnepu_send_peer_our_multi_filters (tBNEP_CONN *p_bcb) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + BT_HDR *p_buf; + UINT8 *p; + UINT16 xx; + + BNEP_TRACE_DEBUG0 ("BNEP sending peer our multicast filters"); + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - no buffer to send multicast filters"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_SET_MSG); + + UINT16_TO_BE_STREAM (p, (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters)); + for (xx = 0; xx < p_bcb->sent_mcast_filters; xx++) + { + memcpy (p, p_bcb->sent_mcast_filter_start[xx], BD_ADDR_LEN); + p += BD_ADDR_LEN; + memcpy (p, p_bcb->sent_mcast_filter_end[xx], BD_ADDR_LEN); + p += BD_ADDR_LEN; + } + + p_buf->len = 4 + (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters); + + bnepu_check_send_packet (p_bcb, p_buf); + + p_bcb->con_flags |= BNEP_FLAGS_MULTI_RESP_PEND; + + /* Start timer waiting for setup response */ + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_FILTER_SET_TIMEOUT); +#endif +} + + +/******************************************************************************* +** +** Function bnepu_send_peer_filter_rsp +** +** Description This function sends a filter response to a peer +** +** Returns void +** +*******************************************************************************/ +void bnepu_send_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code) +{ + BT_HDR *p_buf; + UINT8 *p; + + BNEP_TRACE_DEBUG0 ("BNEP sending filter response"); + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - no buffer filter rsp"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_FILTER_NET_TYPE_RESPONSE_MSG); + + UINT16_TO_BE_STREAM (p, response_code); + + p_buf->len = 4; + + bnepu_check_send_packet (p_bcb, p_buf); +} + + +/******************************************************************************* +** +** Function bnep_send_command_not_understood +** +** Description This function sends a BNEP command not understood message +** +** Returns void +** +*******************************************************************************/ +void bnep_send_command_not_understood (tBNEP_CONN *p_bcb, UINT8 cmd_code) +{ + BT_HDR *p_buf; + UINT8 *p; + + BNEP_TRACE_EVENT2 ("BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x", p_bcb->l2cap_cid, cmd_code); + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - not able to send connection response"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD); + + UINT8_TO_BE_STREAM (p, cmd_code); + + p_buf->len = 3; + + bnepu_check_send_packet (p_bcb, p_buf); + +} + + +/******************************************************************************* +** +** Function bnepu_check_send_packet +** +** Description This function tries to send a packet to L2CAP. +** If L2CAP is flow controlled, it enqueues the +** packet to the transmit queue +** +** Returns void +** +*******************************************************************************/ +void bnepu_check_send_packet (tBNEP_CONN *p_bcb, BT_HDR *p_buf) +{ + BNEP_TRACE_EVENT1 ("BNEP - bnepu_check_send_packet for CID: 0x%x", p_bcb->l2cap_cid); + if (p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED) + { + if (p_bcb->xmit_q.count >= BNEP_MAX_XMITQ_DEPTH) + { + BNEP_TRACE_EVENT1 ("BNEP - congested, dropping buf, CID: 0x%x", p_bcb->l2cap_cid); + + GKI_freebuf (p_buf); + } + else + { + GKI_enqueue (&p_bcb->xmit_q, p_buf); + } + } + else + { + L2CA_DataWrite (p_bcb->l2cap_cid, p_buf); + } +} + + +/******************************************************************************* +** +** Function bnepu_build_bnep_hdr +** +** Description This function builds the BNEP header for a packet +** Extension headers are not sent yet, so there is no +** check for that. +** +** Returns void +** +*******************************************************************************/ +void bnepu_build_bnep_hdr (tBNEP_CONN *p_bcb, BT_HDR *p_buf, UINT16 protocol, + UINT8 *p_src_addr, UINT8 *p_dest_addr, BOOLEAN fw_ext_present) +{ + UINT8 ext_bit, *p = (UINT8 *)NULL; + UINT8 type = BNEP_FRAME_COMPRESSED_ETHERNET; + + ext_bit = fw_ext_present ? 0x80 : 0x00; + + if ((p_src_addr) && (memcmp (p_src_addr, bnep_cb.my_bda, BD_ADDR_LEN))) + type = BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY; + + if (memcmp (p_dest_addr, p_bcb->rem_bda, BD_ADDR_LEN)) + type = (type == BNEP_FRAME_COMPRESSED_ETHERNET) ? BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY : BNEP_FRAME_GENERAL_ETHERNET; + + if (!p_src_addr) + p_src_addr = (UINT8 *)bnep_cb.my_bda; + + switch (type) + { + case BNEP_FRAME_GENERAL_ETHERNET: + p = bnepu_init_hdr (p_buf, 15, (UINT8)(ext_bit | BNEP_FRAME_GENERAL_ETHERNET)); + + memcpy (p, p_dest_addr, BD_ADDR_LEN); + p += BD_ADDR_LEN; + + memcpy (p, p_src_addr, BD_ADDR_LEN); + p += BD_ADDR_LEN; + break; + + case BNEP_FRAME_COMPRESSED_ETHERNET: + p = bnepu_init_hdr (p_buf, 3, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET)); + break; + + case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY: + p = bnepu_init_hdr (p_buf, 9, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY)); + + memcpy (p, p_src_addr, BD_ADDR_LEN); + p += BD_ADDR_LEN; + break; + + case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY: + p = bnepu_init_hdr (p_buf, 9, (UINT8)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY)); + + memcpy (p, p_dest_addr, BD_ADDR_LEN); + p += BD_ADDR_LEN; + break; + } + + UINT16_TO_BE_STREAM (p, protocol); +} + + +/******************************************************************************* +** +** Function bnepu_init_hdr +** +** Description This function initializes the BNEP header +** +** Returns pointer to header in buffer +** +*******************************************************************************/ +static UINT8 *bnepu_init_hdr (BT_HDR *p_buf, UINT16 hdr_len, UINT8 pkt_type) +{ + UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* See if we need to make space in the buffer */ + if (p_buf->offset < (hdr_len + L2CAP_MIN_OFFSET)) + { + UINT16 xx, diff = BNEP_MINIMUM_OFFSET - p_buf->offset; + p = p + p_buf->len - 1; + for (xx = 0; xx < p_buf->len; xx++, p--) + p[diff] = *p; + + p_buf->offset = BNEP_MINIMUM_OFFSET; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + } + + p_buf->len += hdr_len; + p_buf->offset -= hdr_len; + p -= hdr_len; + + *p++ = pkt_type; + + return (p); +} + + +/******************************************************************************* +** +** Function bnep_process_setup_conn_req +** +** Description This function processes a peer's setup connection request +** message. The destination UUID is verified and response sent +** Connection open indication will be given to PAN profile +** +** Returns void +** +*******************************************************************************/ +void bnep_process_setup_conn_req (tBNEP_CONN *p_bcb, UINT8 *p_setup, UINT8 len) +{ + BNEP_TRACE_EVENT1 ("BNEP - bnep_process_setup_conn_req for CID: 0x%x", p_bcb->l2cap_cid); + + if (p_bcb->con_state != BNEP_STATE_CONN_SETUP && + p_bcb->con_state != BNEP_STATE_SEC_CHECKING && + p_bcb->con_state != BNEP_STATE_CONNECTED) + { + BNEP_TRACE_ERROR1 ("BNEP - setup request in bad state %d", p_bcb->con_state); + bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); + return; + } + + /* Check if we already initiated security check or if waiting for user responce */ + if (p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD) + { + BNEP_TRACE_EVENT0 ("BNEP - Duplicate Setup message received while doing security check"); + return; + } + + /* Check if peer is the originator */ + if (p_bcb->con_state != BNEP_STATE_CONNECTED && + (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) && + (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) + { + BNEP_TRACE_ERROR1 ("BNEP - setup request when we are originator", p_bcb->con_state); + bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); + return; + } + + if (p_bcb->con_state == BNEP_STATE_CONNECTED) + { + memcpy ((UINT8 *)&(p_bcb->prv_src_uuid), (UINT8 *)&(p_bcb->src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->prv_dst_uuid), (UINT8 *)&(p_bcb->dst_uuid), sizeof (tBT_UUID)); + } + + p_bcb->dst_uuid.len = p_bcb->src_uuid.len = len; + + if (p_bcb->dst_uuid.len == 2) + { + /* because peer initiated connection keep src uuid as dst uuid */ + BE_STREAM_TO_UINT16 (p_bcb->src_uuid.uu.uuid16, p_setup); + BE_STREAM_TO_UINT16 (p_bcb->dst_uuid.uu.uuid16, p_setup); + + /* If nothing has changed don't bother the profile */ + if (p_bcb->con_state == BNEP_STATE_CONNECTED && + p_bcb->src_uuid.uu.uuid16 == p_bcb->prv_src_uuid.uu.uuid16 && + p_bcb->dst_uuid.uu.uuid16 == p_bcb->prv_dst_uuid.uu.uuid16) + { + bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_OK); + return; + } + } +#if (defined (BNEP_SUPPORTS_ALL_UUID_LENGTHS) && BNEP_SUPPORTS_ALL_UUID_LENGTHS == TRUE) + else if (p_bcb->dst_uuid.len == 4) + { + BE_STREAM_TO_UINT32 (p_bcb->src_uuid.uu.uuid32, p_setup); + BE_STREAM_TO_UINT32 (p_bcb->dst_uuid.uu.uuid32, p_setup); + } + else if (p_bcb->dst_uuid.len == 16) + { + memcpy (p_bcb->src_uuid.uu.uuid128, p_setup, p_bcb->src_uuid.len); + p_setup += p_bcb->src_uuid.len; + memcpy (p_bcb->dst_uuid.uu.uuid128, p_setup, p_bcb->dst_uuid.len); + p_setup += p_bcb->dst_uuid.len; + } +#endif + else + { + BNEP_TRACE_ERROR1 ("BNEP - Bad UID len %d in ConnReq", p_bcb->dst_uuid.len); + bnep_send_conn_responce (p_bcb, BNEP_SETUP_INVALID_UUID_SIZE); + return; + } + + p_bcb->con_state = BNEP_STATE_SEC_CHECKING; + p_bcb->con_flags |= BNEP_FLAGS_SETUP_RCVD; + + BNEP_TRACE_EVENT1 ("BNEP initiating security check for incoming call for uuid 0x%x", p_bcb->src_uuid.uu.uuid16); +#if (!defined (BNEP_DO_AUTH_FOR_ROLE_SWITCH) || BNEP_DO_AUTH_FOR_ROLE_SWITCH == FALSE) + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + bnep_sec_check_complete (p_bcb->rem_bda, p_bcb, BTM_SUCCESS); + else +#endif + btm_sec_mx_access_request (p_bcb->rem_bda, BT_PSM_BNEP, FALSE, + BTM_SEC_PROTO_BNEP, bnep_get_uuid32(&(p_bcb->src_uuid)), + &bnep_sec_check_complete, p_bcb); + + return; +} + + +/******************************************************************************* +** +** Function bnep_process_setup_conn_responce +** +** Description This function processes a peer's setup connection response +** message. The response code is verified and +** Connection open indication will be given to PAN profile +** +** Returns void +** +*******************************************************************************/ +void bnep_process_setup_conn_responce (tBNEP_CONN *p_bcb, UINT8 *p_setup) +{ + tBNEP_RESULT resp; + UINT16 resp_code; + + BNEP_TRACE_DEBUG0 ("BNEP received setup responce"); + /* The state should be either SETUP or CONNECTED */ + if (p_bcb->con_state != BNEP_STATE_CONN_SETUP) + { + /* Should we disconnect ? */ + BNEP_TRACE_ERROR1 ("BNEP - setup response in bad state %d", p_bcb->con_state); + return; + } + + /* Check if we are the originator */ + if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) + { + BNEP_TRACE_ERROR1 ("BNEP - setup response when we are not originator", p_bcb->con_state); + return; + } + + BE_STREAM_TO_UINT16 (resp_code, p_setup); + + switch (resp_code) + { + case BNEP_SETUP_INVALID_SRC_UUID: + resp = BNEP_CONN_FAILED_SRC_UUID; + break; + + case BNEP_SETUP_INVALID_DEST_UUID: + resp = BNEP_CONN_FAILED_DST_UUID; + break; + + case BNEP_SETUP_INVALID_UUID_SIZE: + resp = BNEP_CONN_FAILED_UUID_SIZE; + break; + + case BNEP_SETUP_CONN_NOT_ALLOWED: + default: + resp = BNEP_CONN_FAILED; + break; + } + + /* Check the responce code */ + if (resp_code != BNEP_SETUP_CONN_OK) + { + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + { + BNEP_TRACE_EVENT1 ("BNEP - role change response is %d", resp_code); + + /* Restore the earlier BNEP status */ + p_bcb->con_state = BNEP_STATE_CONNECTED; + p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); + memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID)); + + /* Ensure timer is stopped */ + btu_stop_timer (&p_bcb->conn_tle); + p_bcb->re_transmits = 0; + + /* Tell the user if he has a callback */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, TRUE); + + return; + } + else + { + BNEP_TRACE_ERROR1 ("BNEP - setup response %d is not OK", resp_code); + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + /* Tell the user if he has a callback */ + if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, resp, FALSE); + + bnepu_release_bcb (p_bcb); + return; + } + } + + /* Received successful responce */ + bnep_connected (p_bcb); +} + + +/******************************************************************************* +** +** Function bnep_process_control_packet +** +** Description This function processes a peer's setup connection request +** message. The destination UUID is verified and response sent +** Connection open indication will be given to PAN profile +** +** Returns void +** +*******************************************************************************/ +UINT8 *bnep_process_control_packet (tBNEP_CONN *p_bcb, UINT8 *p, UINT16 *rem_len, BOOLEAN is_ext) +{ + UINT8 control_type; + BOOLEAN bad_pkt = FALSE; + UINT16 len, ext_len = 0; + + if (is_ext) + { + ext_len = *p++; + *rem_len = *rem_len - 1; + } + + control_type = *p++; + *rem_len = *rem_len - 1; + + BNEP_TRACE_EVENT3 ("BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d", *rem_len, is_ext, control_type); + + switch (control_type) + { + case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD: + BNEP_TRACE_ERROR1 ("BNEP Received Cmd not understood for ctl pkt type: %d", *p); + p++; + *rem_len = *rem_len - 1; + break; + + case BNEP_SETUP_CONNECTION_REQUEST_MSG: + len = *p++; + if (*rem_len < ((2 * len) + 1)) + { + bad_pkt = TRUE; + BNEP_TRACE_ERROR0 ("BNEP Received Setup message with bad length"); + break; + } + if (!is_ext) + bnep_process_setup_conn_req (p_bcb, p, (UINT8)len); + p += (2 * len); + *rem_len = *rem_len - (2 * len) - 1; + break; + + case BNEP_SETUP_CONNECTION_RESPONSE_MSG: + if (!is_ext) + bnep_process_setup_conn_responce (p_bcb, p); + p += 2; + *rem_len = *rem_len - 2; + break; + + case BNEP_FILTER_NET_TYPE_SET_MSG: + BE_STREAM_TO_UINT16 (len, p); + if (*rem_len < (len + 2)) + { + bad_pkt = TRUE; + BNEP_TRACE_ERROR0 ("BNEP Received Filter set message with bad length"); + break; + } + bnepu_process_peer_filter_set (p_bcb, p, len); + p += len; + *rem_len = *rem_len - len - 2; + break; + + case BNEP_FILTER_NET_TYPE_RESPONSE_MSG: + bnepu_process_peer_filter_rsp (p_bcb, p); + p += 2; + *rem_len = *rem_len - 2; + break; + + case BNEP_FILTER_MULTI_ADDR_SET_MSG: + BE_STREAM_TO_UINT16 (len, p); + if (*rem_len < (len + 2)) + { + bad_pkt = TRUE; + BNEP_TRACE_ERROR0 ("BNEP Received Multicast Filter Set message with bad length"); + break; + } + bnepu_process_peer_multicast_filter_set (p_bcb, p, len); + p += len; + *rem_len = *rem_len - len - 2; + break; + + case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG: + bnepu_process_multicast_filter_rsp (p_bcb, p); + p += 2; + *rem_len = *rem_len - 2; + break; + + default : + BNEP_TRACE_ERROR1 ("BNEP - bad ctl pkt type: %d", control_type); + bnep_send_command_not_understood (p_bcb, control_type); + if (is_ext) + { + p += (ext_len - 1); + *rem_len -= (ext_len - 1); + } + break; + } + + if (bad_pkt) + { + BNEP_TRACE_ERROR1 ("BNEP - bad ctl pkt length: %d", *rem_len); + *rem_len = 0; + return NULL; + } + + return p; +} + + +/******************************************************************************* +** +** Function bnepu_process_peer_filter_set +** +** Description This function processes a peer's filter control +** 'set' message. The filters are stored in the BCB, +** and an appropriate filter response message sent. +** +** Returns void +** +*******************************************************************************/ +void bnepu_process_peer_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + UINT16 num_filters = 0; + UINT16 xx, resp_code = BNEP_FILTER_CRL_OK; + UINT16 start, end; + UINT8 *p_temp_filters; + + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + { + BNEP_TRACE_DEBUG0 ("BNEP received filter set from peer when there is no connection"); + return; + } + + BNEP_TRACE_DEBUG0 ("BNEP received filter set from peer"); + /* Check for length not a multiple of 4 */ + if (len & 3) + { + BNEP_TRACE_EVENT1 ("BNEP - bad filter len: %d", len); + bnepu_send_peer_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE); + return; + } + + if (len) + num_filters = (UINT16) (len >> 2); + + /* Validate filter values */ + if (num_filters <= BNEP_MAX_PROT_FILTERS) + { + p_temp_filters = p_filters; + for (xx = 0; xx < num_filters; xx++) + { + BE_STREAM_TO_UINT16 (start, p_temp_filters); + BE_STREAM_TO_UINT16 (end, p_temp_filters); + + if (start > end) + { + resp_code = BNEP_FILTER_CRL_BAD_RANGE; + break; + } + } + } + else + resp_code = BNEP_FILTER_CRL_MAX_REACHED; + + if (resp_code != BNEP_FILTER_CRL_OK) + { + bnepu_send_peer_filter_rsp (p_bcb, resp_code); + return; + } + + if (bnep_cb.p_filter_ind_cb) + (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, TRUE, 0, len, p_filters); + + p_bcb->rcvd_num_filters = num_filters; + for (xx = 0; xx < num_filters; xx++) + { + BE_STREAM_TO_UINT16 (start, p_filters); + BE_STREAM_TO_UINT16 (end, p_filters); + + p_bcb->rcvd_prot_filter_start[xx] = start; + p_bcb->rcvd_prot_filter_end[xx] = end; + } + + bnepu_send_peer_filter_rsp (p_bcb, resp_code); +#else + bnepu_send_peer_filter_rsp (p_bcb, BNEP_FILTER_CRL_UNSUPPORTED); +#endif +} + + +/******************************************************************************* +** +** Function bnepu_process_peer_filter_rsp +** +** Description This function processes a peer's filter control +** 'response' message. +** +** Returns void +** +*******************************************************************************/ +void bnepu_process_peer_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + UINT16 resp_code; + tBNEP_RESULT result; + + BNEP_TRACE_DEBUG0 ("BNEP received filter responce"); + /* The state should be CONNECTED */ + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + { + BNEP_TRACE_ERROR1 ("BNEP - filter response in bad state %d", p_bcb->con_state); + return; + } + + /* Check if we are the originator */ + if (!(p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND)) + { + BNEP_TRACE_ERROR0 ("BNEP - filter response when not expecting"); + return; + } + + /* Ensure timer is stopped */ + btu_stop_timer (&p_bcb->conn_tle); + p_bcb->con_flags &= ~BNEP_FLAGS_FILTER_RESP_PEND; + p_bcb->re_transmits = 0; + + BE_STREAM_TO_UINT16 (resp_code, p_data); + + result = BNEP_SUCCESS; + if (resp_code != BNEP_FILTER_CRL_OK) + result = BNEP_SET_FILTER_FAIL; + + if (bnep_cb.p_filter_ind_cb) + (*bnep_cb.p_filter_ind_cb) (p_bcb->handle, FALSE, result, 0, NULL); + + return; +#endif +} + + + +/******************************************************************************* +** +** Function bnepu_process_multicast_filter_rsp +** +** Description This function processes multicast filter control +** 'response' message. +** +** Returns void +** +*******************************************************************************/ +void bnepu_process_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT8 *p_data) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + UINT16 resp_code; + tBNEP_RESULT result; + + BNEP_TRACE_DEBUG0 ("BNEP received multicast filter responce"); + /* The state should be CONNECTED */ + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + { + BNEP_TRACE_ERROR1 ("BNEP - multicast filter response in bad state %d", p_bcb->con_state); + return; + } + + /* Check if we are the originator */ + if (!(p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND)) + { + BNEP_TRACE_ERROR0 ("BNEP - multicast filter response when not expecting"); + return; + } + + /* Ensure timer is stopped */ + btu_stop_timer (&p_bcb->conn_tle); + p_bcb->con_flags &= ~BNEP_FLAGS_MULTI_RESP_PEND; + p_bcb->re_transmits = 0; + + BE_STREAM_TO_UINT16 (resp_code, p_data); + + result = BNEP_SUCCESS; + if (resp_code != BNEP_FILTER_CRL_OK) + result = BNEP_SET_FILTER_FAIL; + + if (bnep_cb.p_mfilter_ind_cb) + (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, FALSE, result, 0, NULL); + + return; +#endif +} + + + +/******************************************************************************* +** +** Function bnepu_process_peer_multicast_filter_set +** +** Description This function processes a peer's filter control +** 'set' message. The filters are stored in the BCB, +** and an appropriate filter response message sent. +** +** Returns void +** +*******************************************************************************/ +void bnepu_process_peer_multicast_filter_set (tBNEP_CONN *p_bcb, UINT8 *p_filters, UINT16 len) +{ +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + UINT16 resp_code = BNEP_FILTER_CRL_OK; + UINT16 num_filters, xx; + UINT8 *p_temp_filters, null_bda[BD_ADDR_LEN] = {0,0,0,0,0,0}; + + if ((p_bcb->con_state != BNEP_STATE_CONNECTED) && + (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) + { + BNEP_TRACE_DEBUG0 ("BNEP received multicast filter set from peer when there is no connection"); + return; + } + + if (len % 12) + { + BNEP_TRACE_EVENT1 ("BNEP - bad filter len: %d", len); + bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE); + return; + } + + if (len > (BNEP_MAX_MULTI_FILTERS * 2 * BD_ADDR_LEN)) + { + BNEP_TRACE_EVENT0 ("BNEP - Too many filters"); + bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_MAX_REACHED); + return; + } + + num_filters = 0; + if (len) + num_filters = (UINT16) (len / 12); + + /* Validate filter values */ + if (num_filters <= BNEP_MAX_MULTI_FILTERS) + { + p_temp_filters = p_filters; + for (xx = 0; xx < num_filters; xx++) + { + if (memcmp (p_temp_filters, p_temp_filters + BD_ADDR_LEN, BD_ADDR_LEN) > 0) + { + bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_BAD_RANGE); + return; + } + + p_temp_filters += (BD_ADDR_LEN * 2); + } + } + + p_bcb->rcvd_mcast_filters = num_filters; + for (xx = 0; xx < num_filters; xx++) + { + memcpy (p_bcb->rcvd_mcast_filter_start[xx], p_filters, BD_ADDR_LEN); + memcpy (p_bcb->rcvd_mcast_filter_end[xx], p_filters + BD_ADDR_LEN, BD_ADDR_LEN); + p_filters += (BD_ADDR_LEN * 2); + + /* Check if any of the ranges have all zeros as both starting and ending addresses */ + if ((memcmp (null_bda, p_bcb->rcvd_mcast_filter_start[xx], BD_ADDR_LEN) == 0) && + (memcmp (null_bda, p_bcb->rcvd_mcast_filter_end[xx], BD_ADDR_LEN) == 0)) + { + p_bcb->rcvd_mcast_filters = 0xFFFF; + break; + } + } + + BNEP_TRACE_EVENT1 ("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters); + bnepu_send_peer_multicast_filter_rsp (p_bcb, resp_code); + + if (bnep_cb.p_mfilter_ind_cb) + (*bnep_cb.p_mfilter_ind_cb) (p_bcb->handle, TRUE, 0, len, p_filters); +#else + bnepu_send_peer_multicast_filter_rsp (p_bcb, BNEP_FILTER_CRL_UNSUPPORTED); +#endif +} + + +/******************************************************************************* +** +** Function bnepu_send_peer_multicast_filter_rsp +** +** Description This function sends a filter response to a peer +** +** Returns void +** +*******************************************************************************/ +void bnepu_send_peer_multicast_filter_rsp (tBNEP_CONN *p_bcb, UINT16 response_code) +{ + BT_HDR *p_buf; + UINT8 *p; + + BNEP_TRACE_DEBUG1 ("BNEP sending multicast filter response %d", response_code); + if ((p_buf = (BT_HDR *)GKI_getpoolbuf (BNEP_POOL_ID)) == NULL) + { + BNEP_TRACE_ERROR0 ("BNEP - no buffer filter rsp"); + return; + } + + p_buf->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; + + /* Put in BNEP frame type - filter control */ + UINT8_TO_BE_STREAM (p, BNEP_FRAME_CONTROL); + + /* Put in filter message type - set filters */ + UINT8_TO_BE_STREAM (p, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG); + + UINT16_TO_BE_STREAM (p, response_code); + + p_buf->len = 4; + + bnepu_check_send_packet (p_bcb, p_buf); +} + + + +/******************************************************************************* +** +** Function bnep_sec_check_complete +** +** Description This function is registered with BTM and will be called +** after completing the security procedures +** +** Returns void +** +*******************************************************************************/ +void bnep_sec_check_complete (BD_ADDR bd_addr, void *p_ref_data, UINT8 result) +{ + tBNEP_CONN *p_bcb = (tBNEP_CONN *)p_ref_data; + UINT16 resp_code = BNEP_SETUP_CONN_OK; + BOOLEAN is_role_change; + + BNEP_TRACE_EVENT1 ("BNEP security callback returned result %d", result); + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + is_role_change = TRUE; + else + is_role_change = FALSE; + + /* check if the port is still waiting for security to complete */ + if (p_bcb->con_state != BNEP_STATE_SEC_CHECKING) + { + BNEP_TRACE_ERROR1 ("BNEP Connection in wrong state %d when security is completed", p_bcb->con_state); + return; + } + + /* if it is outgoing call and result is FAILURE return security fail error */ + if (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) + { + if (result != BTM_SUCCESS) + { + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + { + /* Tell the user that role change is failed because of security */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change); + + p_bcb->con_state = BNEP_STATE_CONNECTED; + memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID)); + return; + } + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + /* Tell the user if he has a callback */ + if (bnep_cb.p_conn_state_cb) + (*bnep_cb.p_conn_state_cb) (p_bcb->handle, p_bcb->rem_bda, BNEP_SECURITY_FAIL, is_role_change); + + bnepu_release_bcb (p_bcb); + return; + } + + /* Transition to the next appropriate state, waiting for connection confirm. */ + p_bcb->con_state = BNEP_STATE_CONN_SETUP; + + bnep_send_conn_req (p_bcb); + btu_start_timer (&p_bcb->conn_tle, BTU_TTYPE_BNEP, BNEP_CONN_TIMEOUT); + return; + } + + /* it is an incoming call respond appropriately */ + if (result != BTM_SUCCESS) + { + bnep_send_conn_responce (p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED); + if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) + { + /* Role change is failed because of security. Revert back to connected state */ + p_bcb->con_state = BNEP_STATE_CONNECTED; + p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD); + memcpy ((UINT8 *)&(p_bcb->src_uuid), (UINT8 *)&(p_bcb->prv_src_uuid), sizeof (tBT_UUID)); + memcpy ((UINT8 *)&(p_bcb->dst_uuid), (UINT8 *)&(p_bcb->prv_dst_uuid), sizeof (tBT_UUID)); + return; + } + + L2CA_DisconnectReq (p_bcb->l2cap_cid); + + bnepu_release_bcb (p_bcb); + return; + } + + if (bnep_cb.p_conn_ind_cb) + { + p_bcb->con_state = BNEP_STATE_CONN_SETUP; + (*bnep_cb.p_conn_ind_cb) (p_bcb->handle, p_bcb->rem_bda, &p_bcb->dst_uuid, &p_bcb->src_uuid, is_role_change); + } + else + { + /* Profile didn't register connection indication call back */ + bnep_send_conn_responce (p_bcb, resp_code); + bnep_connected (p_bcb); + } + + return; +} + + +/******************************************************************************* +** +** Function bnep_is_packet_allowed +** +** Description This function verifies whether the protocol passes through +** the protocol filters set by the peer +** +** Returns BNEP_SUCCESS - if the protocol is allowed +** BNEP_IGNORE_CMD - if the protocol is filtered out +** +*******************************************************************************/ +tBNEP_RESULT bnep_is_packet_allowed (tBNEP_CONN *p_bcb, + BD_ADDR p_dest_addr, + UINT16 protocol, + BOOLEAN fw_ext_present, + UINT8 *p_data) +{ +#if (defined (BNEP_SUPPORTS_PROT_FILTERS) && BNEP_SUPPORTS_PROT_FILTERS == TRUE) + if (p_bcb->rcvd_num_filters) + { + UINT16 i, proto; + + /* Findout the actual protocol to check for the filtering */ + proto = protocol; + if (proto == BNEP_802_1_P_PROTOCOL) + { + if (fw_ext_present) + { + UINT8 len, ext; + /* parse the extension headers and findout actual protocol */ + do { + + ext = *p_data++; + len = *p_data++; + p_data += len; + + } while (ext & 0x80); + } + p_data += 2; + BE_STREAM_TO_UINT16 (proto, p_data); + } + + for (i=0; i<p_bcb->rcvd_num_filters; i++) + { + if ((p_bcb->rcvd_prot_filter_start[i] <= proto) && + (proto <= p_bcb->rcvd_prot_filter_end[i])) + break; + } + + if (i == p_bcb->rcvd_num_filters) + { + BNEP_TRACE_DEBUG1 ("Ignoring protocol 0x%x in BNEP data write", proto); + return BNEP_IGNORE_CMD; + } + } +#endif + +#if (defined (BNEP_SUPPORTS_MULTI_FILTERS) && BNEP_SUPPORTS_MULTI_FILTERS == TRUE) + /* Ckeck for multicast address filtering */ + if ((p_dest_addr[0] & 0x01) && + p_bcb->rcvd_mcast_filters) + { + UINT16 i; + + /* Check if every multicast should be filtered */ + if (p_bcb->rcvd_mcast_filters != 0xFFFF) + { + /* Check if the address is mentioned in the filter range */ + for (i = 0; i < p_bcb->rcvd_mcast_filters; i++) + { + if ((memcmp (p_bcb->rcvd_mcast_filter_start[i], p_dest_addr, BD_ADDR_LEN) <= 0) && + (memcmp (p_bcb->rcvd_mcast_filter_end[i], p_dest_addr, BD_ADDR_LEN) >= 0)) + break; + } + } + + /* + ** If every multicast should be filtered or the address is not in the filter range + ** drop the packet + */ + if ((p_bcb->rcvd_mcast_filters == 0xFFFF) || (i == p_bcb->rcvd_mcast_filters)) + { + BNEP_TRACE_DEBUG6 ("Ignoring multicast address %x.%x.%x.%x.%x.%x in BNEP data write", + p_dest_addr[0], p_dest_addr[1], p_dest_addr[2], + p_dest_addr[3], p_dest_addr[4], p_dest_addr[5]); + return BNEP_IGNORE_CMD; + } + } +#endif + + return BNEP_SUCCESS; +} + + + + + +/******************************************************************************* +** +** Function bnep_get_uuid32 +** +** Description This function returns the 32 bit equivalent of the given UUID +** +** Returns UINT32 - 32 bit equivalent of the UUID +** +*******************************************************************************/ +UINT32 bnep_get_uuid32 (tBT_UUID *src_uuid) +{ + UINT32 result; + + if (src_uuid->len == 2) + return ((UINT32)src_uuid->uu.uuid16); + else if (src_uuid->len == 4) + return (src_uuid->uu.uuid32 & 0x0000FFFF); + else + { + result = src_uuid->uu.uuid128[2]; + result = (result << 8) | (src_uuid->uu.uuid128[3]); + return result; + } +} + + + + +/******************************************************************************* +** +** Function bnep_dump_status +** +** Description This function dumps the bnep control block and connection +** blocks information +** +** Returns none +** +*******************************************************************************/ +void bnep_dump_status (void) +{ +#if (defined (BNEP_SUPPORTS_DEBUG_DUMP) && BNEP_SUPPORTS_DEBUG_DUMP == TRUE) + UINT16 i; + char buff[200]; + tBNEP_CONN *p_bcb; + + BNEP_TRACE_DEBUG6 ("BNEP my BD Addr %x.%x.%x.%x.%x.%x", + bnep_cb.my_bda[0], bnep_cb.my_bda[1], bnep_cb.my_bda[2], + bnep_cb.my_bda[3], bnep_cb.my_bda[4], bnep_cb.my_bda[5]); + BNEP_TRACE_DEBUG3 ("profile registered %d, trace %d, got_my_bd_addr %d", + bnep_cb.profile_registered, bnep_cb.trace_level, bnep_cb.got_my_bd_addr); + + for (i = 0, p_bcb = bnep_cb.bcb; i < BNEP_MAX_CONNECTIONS; i++, p_bcb++) + { + sprintf (buff, "%d state %d, flags 0x%x, cid %d, pfilts %d, mfilts %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x", + i, p_bcb->con_state, p_bcb->con_flags, p_bcb->l2cap_cid, + p_bcb->rcvd_num_filters, p_bcb->rcvd_mcast_filters, + p_bcb->src_uuid.uu.uuid16, p_bcb->dst_uuid.uu.uuid16, + p_bcb->rem_bda[0], p_bcb->rem_bda[1], p_bcb->rem_bda[2], + p_bcb->rem_bda[3], p_bcb->rem_bda[4], p_bcb->rem_bda[5]); + + BNEP_TRACE_DEBUG0 (buff); + } +#endif +} + + |