| /****************************************************************************** |
| * |
| * Copyright (C) 1999-2012 Broadcom Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * This file contains functions that handle inquiries. These include |
| * setting discoverable mode, controlling the mode of the Baseband, and |
| * maintaining a small database of inquiry responses, with API for people |
| * to browse it. |
| * |
| ******************************************************************************/ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stddef.h> |
| |
| #include "bt_types.h" |
| #include "gki.h" |
| #include "hcimsgs.h" |
| #include "btu.h" |
| #include "btm_api.h" |
| #include "btm_int.h" |
| #include "hcidefs.h" |
| |
| #define BTM_INQ_REPLY_TIMEOUT 3 /* 3 second timeout waiting for responses */ |
| |
| /* TRUE to enable DEBUG traces for btm_inq */ |
| #ifndef BTM_INQ_DEBUG |
| #define BTM_INQ_DEBUG FALSE |
| #endif |
| /********************************************************************************/ |
| /* L O C A L D A T A D E F I N I T I O N S */ |
| /********************************************************************************/ |
| static const LAP general_inq_lap = {0x9e,0x8b,0x33}; |
| static const LAP limited_inq_lap = {0x9e,0x8b,0x00}; |
| |
| #if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE )) |
| #ifndef BTM_EIR_UUID_LKUP_TBL |
| const UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] = |
| { |
| UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER, |
| /* UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */ |
| /* UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */ |
| UUID_SERVCLASS_SERIAL_PORT, |
| UUID_SERVCLASS_LAN_ACCESS_USING_PPP, |
| UUID_SERVCLASS_DIALUP_NETWORKING, |
| UUID_SERVCLASS_IRMC_SYNC, |
| UUID_SERVCLASS_OBEX_OBJECT_PUSH, |
| UUID_SERVCLASS_OBEX_FILE_TRANSFER, |
| UUID_SERVCLASS_IRMC_SYNC_COMMAND, |
| UUID_SERVCLASS_HEADSET, |
| UUID_SERVCLASS_CORDLESS_TELEPHONY, |
| UUID_SERVCLASS_AUDIO_SOURCE, |
| UUID_SERVCLASS_AUDIO_SINK, |
| UUID_SERVCLASS_AV_REM_CTRL_TARGET, |
| /* UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */ |
| UUID_SERVCLASS_AV_REMOTE_CONTROL, |
| /* UUID_SERVCLASS_VIDEO_CONFERENCING, */ |
| UUID_SERVCLASS_INTERCOM, |
| UUID_SERVCLASS_FAX, |
| UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, |
| /* UUID_SERVCLASS_WAP, */ |
| /* UUID_SERVCLASS_WAP_CLIENT, */ |
| UUID_SERVCLASS_PANU, |
| UUID_SERVCLASS_NAP, |
| UUID_SERVCLASS_GN, |
| UUID_SERVCLASS_DIRECT_PRINTING, |
| /* UUID_SERVCLASS_REFERENCE_PRINTING, */ |
| UUID_SERVCLASS_IMAGING, |
| UUID_SERVCLASS_IMAGING_RESPONDER, |
| UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE, |
| UUID_SERVCLASS_IMAGING_REF_OBJECTS, |
| UUID_SERVCLASS_HF_HANDSFREE, |
| UUID_SERVCLASS_AG_HANDSFREE, |
| UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE, |
| /* UUID_SERVCLASS_REFLECTED_UI, */ |
| UUID_SERVCLASS_BASIC_PRINTING, |
| UUID_SERVCLASS_PRINTING_STATUS, |
| UUID_SERVCLASS_HUMAN_INTERFACE, |
| UUID_SERVCLASS_CABLE_REPLACEMENT, |
| UUID_SERVCLASS_HCRP_PRINT, |
| UUID_SERVCLASS_HCRP_SCAN, |
| /* UUID_SERVCLASS_COMMON_ISDN_ACCESS, */ |
| /* UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */ |
| /* UUID_SERVCLASS_UDI_MT, */ |
| /* UUID_SERVCLASS_UDI_TA, */ |
| /* UUID_SERVCLASS_VCP, */ |
| UUID_SERVCLASS_SAP, |
| UUID_SERVCLASS_PBAP_PCE, |
| UUID_SERVCLASS_PBAP_PSE, |
| UUID_SERVCLASS_PHONE_ACCESS, |
| UUID_SERVCLASS_HEADSET_HS, |
| UUID_SERVCLASS_PNP_INFORMATION, |
| /* UUID_SERVCLASS_GENERIC_NETWORKING, */ |
| /* UUID_SERVCLASS_GENERIC_FILETRANSFER, */ |
| /* UUID_SERVCLASS_GENERIC_AUDIO, */ |
| /* UUID_SERVCLASS_GENERIC_TELEPHONY, */ |
| /* UUID_SERVCLASS_UPNP_SERVICE, */ |
| /* UUID_SERVCLASS_UPNP_IP_SERVICE, */ |
| /* UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */ |
| /* UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */ |
| /* UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */ |
| UUID_SERVCLASS_VIDEO_SOURCE, |
| UUID_SERVCLASS_VIDEO_SINK, |
| /* UUID_SERVCLASS_VIDEO_DISTRIBUTION */ |
| UUID_SERVCLASS_MESSAGE_ACCESS, |
| UUID_SERVCLASS_MESSAGE_NOTIFICATION, |
| UUID_SERVCLASS_HDP_SOURCE, |
| UUID_SERVCLASS_HDP_SINK |
| }; |
| #else |
| /* |
| If customized UUID look-up table needs to be used, |
| the followings should be defined in bdroid_buildcfg.h. |
| BTM_EIR_UUID_LKUP_TBL = <customized UUID list> |
| BTM_EIR_MAX_SERVICES = <number of UUID in list> |
| */ |
| #if (BTM_EIR_MAX_SERVICES == 0) |
| const UINT16 BTM_EIR_UUID_LKUP_TBL[]; |
| #else |
| extern UINT16 BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES]; |
| #endif |
| #endif |
| #endif /* BTM_EIR_UUID_LKUP_TBL*/ |
| |
| /********************************************************************************/ |
| /* 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 btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq); |
| static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, tBTM_INQ_FILT_COND *p_filt_cond); |
| static void btm_clr_inq_result_flt (void); |
| |
| #if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE)) |
| static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 ); |
| #endif |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| static void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results ); |
| static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size, |
| UINT8 *p_num_uuid, UINT8 *p_uuid_list_type ); |
| static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size ); |
| #endif |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetDiscoverability |
| ** |
| ** Description This function is called to set the device into or out of |
| ** discoverable mode. Discoverable mode means inquiry |
| ** scans are enabled. If a value of '0' is entered for window or |
| ** interval, the default values are used. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_BUSY if a setting of the filter is already in progress |
| ** BTM_NO_RESOURCES if couldn't get a memory pool buffer |
| ** BTM_ILLEGAL_VALUE if a bad parameter was detected |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 interval) |
| { |
| UINT8 scan_mode = 0; |
| UINT16 service_class; |
| UINT8 *p_cod; |
| UINT8 major, minor; |
| DEV_CLASS cod; |
| LAP temp_lap[2]; |
| BOOLEAN is_limited; |
| BOOLEAN cod_limited; |
| |
| BTM_TRACE_API0 ("BTM_SetDiscoverability"); |
| #if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE) |
| if (btm_ble_set_discoverability((UINT16)(inq_mode)) |
| == BTM_SUCCESS) |
| { |
| btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK); |
| btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_CONNECTABLE_MASK); |
| } |
| inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK; |
| #endif |
| |
| /*** Check mode parameter ***/ |
| if (inq_mode > BTM_MAX_DISCOVERABLE) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* Make sure the controller is active */ |
| if (btm_cb.devcb.state < BTM_DEV_STATE_READY) |
| return (BTM_DEV_RESET); |
| |
| /* If the window and/or interval is '0', set to default values */ |
| if (!window) |
| window = BTM_DEFAULT_DISC_WINDOW; |
| |
| if (!interval) |
| interval = BTM_DEFAULT_DISC_INTERVAL; |
| |
| BTM_TRACE_API3 ("BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window 0x%04x, interval 0x%04x", |
| inq_mode, window, interval); |
| |
| /*** Check for valid window and interval parameters ***/ |
| /*** Only check window and duration if mode is connectable ***/ |
| if (inq_mode != BTM_NON_DISCOVERABLE) |
| { |
| /* window must be less than or equal to interval */ |
| if (window < HCI_MIN_INQUIRYSCAN_WINDOW || |
| window > HCI_MAX_INQUIRYSCAN_WINDOW || |
| interval < HCI_MIN_INQUIRYSCAN_INTERVAL || |
| interval > HCI_MAX_INQUIRYSCAN_INTERVAL || |
| window > interval) |
| { |
| return (BTM_ILLEGAL_VALUE); |
| } |
| } |
| |
| /* Set the IAC if needed */ |
| if (inq_mode != BTM_NON_DISCOVERABLE) |
| { |
| if (inq_mode & BTM_LIMITED_DISCOVERABLE) |
| { |
| /* Use the GIAC and LIAC codes for limited discoverable mode */ |
| memcpy (temp_lap[0], limited_inq_lap, LAP_LEN); |
| memcpy (temp_lap[1], general_inq_lap, LAP_LEN); |
| |
| if (!btsnd_hcic_write_cur_iac_lap (2, (LAP * const) temp_lap)) |
| return (BTM_NO_RESOURCES); /* Cannot continue */ |
| } |
| else |
| { |
| if (!btsnd_hcic_write_cur_iac_lap (1, (LAP * const) &general_inq_lap)) |
| return (BTM_NO_RESOURCES); /* Cannot continue */ |
| } |
| |
| scan_mode |= HCI_INQUIRY_SCAN_ENABLED; |
| } |
| |
| /* Send down the inquiry scan window and period if changed */ |
| if ((window != btm_cb.btm_inq_vars.inq_scan_window) || |
| (interval != btm_cb.btm_inq_vars.inq_scan_period)) |
| { |
| if (btsnd_hcic_write_inqscan_cfg (interval, window)) |
| { |
| btm_cb.btm_inq_vars.inq_scan_window = window; |
| btm_cb.btm_inq_vars.inq_scan_period = interval; |
| } |
| else |
| return (BTM_NO_RESOURCES); |
| } |
| |
| if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK) |
| scan_mode |= HCI_PAGE_SCAN_ENABLED; |
| |
| if (btsnd_hcic_write_scan_enable (scan_mode)) |
| { |
| btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK); |
| btm_cb.btm_inq_vars.discoverable_mode |= inq_mode; |
| } |
| else |
| return (BTM_NO_RESOURCES); |
| |
| /* Change the service class bit if mode has changed */ |
| p_cod = BTM_ReadDeviceClass(); |
| BTM_COD_SERVICE_CLASS(service_class, p_cod); |
| is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? TRUE : FALSE; |
| cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? TRUE : FALSE; |
| if (is_limited ^ cod_limited) |
| { |
| BTM_COD_MINOR_CLASS(minor, p_cod ); |
| BTM_COD_MAJOR_CLASS(major, p_cod ); |
| if (is_limited) |
| service_class |= BTM_COD_SERVICE_LMTD_DISCOVER; |
| else |
| service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER; |
| |
| FIELDS_TO_COD(cod, minor, major, service_class); |
| (void) BTM_SetDeviceClass (cod); |
| } |
| |
| return (BTM_SUCCESS); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetInquiryScanType |
| ** |
| ** Description This function is called to set the iquiry scan-type to |
| ** standard or interlaced. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_MODE_UNSUPPORTED if not a 1.2 device |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetInquiryScanType (UINT16 scan_type) |
| { |
| |
| BTM_TRACE_API0 ("BTM_SetInquiryScanType"); |
| if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* whatever app wants if device is not 1.2 scan type should be STANDARD */ |
| if (!HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(btm_cb.devcb.local_features)) |
| return (BTM_MODE_UNSUPPORTED); |
| |
| /* Check for scan type if configuration has been changed */ |
| if (scan_type != btm_cb.btm_inq_vars.inq_scan_type) |
| { |
| if (BTM_IsDeviceUp()) |
| { |
| if (btsnd_hcic_write_inqscan_type ((UINT8)scan_type)) |
| btm_cb.btm_inq_vars.inq_scan_type = scan_type; |
| else |
| return (BTM_NO_RESOURCES); |
| } |
| else return (BTM_WRONG_MODE); |
| } |
| return (BTM_SUCCESS); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetPageScanType |
| ** |
| ** Description This function is called to set the page scan-type to |
| ** standard or interlaced. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_MODE_UNSUPPORTED if not a 1.2 device |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetPageScanType (UINT16 scan_type) |
| { |
| BTM_TRACE_API0 ("BTM_SetPageScanType"); |
| if (scan_type != BTM_SCAN_TYPE_STANDARD && scan_type != BTM_SCAN_TYPE_INTERLACED) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* whatever app wants if device is not 1.2 scan type should be STANDARD */ |
| if (!HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(btm_cb.devcb.local_features)) |
| return (BTM_MODE_UNSUPPORTED); |
| |
| /* Check for scan type if configuration has been changed */ |
| if (scan_type != btm_cb.btm_inq_vars.page_scan_type) |
| { |
| if (BTM_IsDeviceUp()) |
| { |
| if (btsnd_hcic_write_pagescan_type ((UINT8)scan_type)) |
| btm_cb.btm_inq_vars.page_scan_type = scan_type; |
| else |
| return (BTM_NO_RESOURCES); |
| } |
| else return (BTM_WRONG_MODE); |
| } |
| return (BTM_SUCCESS); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetInquiryMode |
| ** |
| ** Description This function is called to set standard or with RSSI |
| ** mode of the inquiry for local device. |
| ** |
| ** Output Params: mode - standard, with RSSI, extended |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_NO_RESOURCES if couldn't get a memory pool buffer |
| ** BTM_ILLEGAL_VALUE if a bad parameter was detected |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetInquiryMode (UINT8 mode) |
| { |
| BTM_TRACE_API0 ("BTM_SetInquiryMode"); |
| if (mode == BTM_INQ_RESULT_STANDARD) |
| { |
| /* mandatory mode */ |
| } |
| else if (mode == BTM_INQ_RESULT_WITH_RSSI) |
| { |
| if (!HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features)) |
| return (BTM_MODE_UNSUPPORTED); |
| } |
| #if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE )) |
| else if (mode == BTM_INQ_RESULT_EXTENDED) |
| { |
| if (!HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features)) |
| return (BTM_MODE_UNSUPPORTED); |
| } |
| #endif |
| else |
| return (BTM_ILLEGAL_VALUE); |
| |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| if (!btsnd_hcic_write_inquiry_mode (mode)) |
| return (BTM_NO_RESOURCES); |
| |
| return (BTM_SUCCESS); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ReadDiscoverability |
| ** |
| ** Description This function is called to read the current discoverability |
| ** mode of the device. |
| ** |
| ** Output Params: p_window - current inquiry scan duration |
| ** p_interval - current inquiry scan interval |
| ** |
| ** Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or |
| ** BTM_GENERAL_DISCOVERABLE |
| ** |
| *******************************************************************************/ |
| UINT16 BTM_ReadDiscoverability (UINT16 *p_window, UINT16 *p_interval) |
| { |
| BTM_TRACE_API0 ("BTM_ReadDiscoverability"); |
| if (p_window) |
| *p_window = btm_cb.btm_inq_vars.inq_scan_window; |
| |
| if (p_interval) |
| *p_interval = btm_cb.btm_inq_vars.inq_scan_period; |
| |
| return (btm_cb.btm_inq_vars.discoverable_mode); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetPeriodicInquiryMode |
| ** |
| ** Description This function is called to set the device periodic inquiry mode. |
| ** If the duration is zero, the periodic inquiry mode is cancelled. |
| ** |
| ** Note: We currently do not allow concurrent inquiry and periodic inquiry. |
| ** |
| ** Parameters: p_inqparms - pointer to the inquiry information |
| ** mode - GENERAL or LIMITED inquiry |
| ** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) |
| ** max_resps - maximum amount of devices to search for before ending the inquiry |
| ** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or |
| ** BTM_FILTER_COND_BD_ADDR |
| ** filter_cond - value for the filter (based on filter_cond_type) |
| ** |
| ** max_delay - maximum amount of time between successive inquiries |
| ** min_delay - minimum amount of time between successive inquiries |
| ** p_results_cb - callback returning pointer to results (tBTM_INQ_RESULTS) |
| ** |
| ** Returns BTM_CMD_STARTED if successfully started |
| ** BTM_ILLEGAL_VALUE if a bad parameter is detected |
| ** BTM_NO_RESOURCES if could not allocate a message buffer |
| ** BTM_SUCCESS - if cancelling the periodic inquiry |
| ** BTM_BUSY - if an inquiry is already active |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetPeriodicInquiryMode (tBTM_INQ_PARMS *p_inqparms, UINT16 max_delay, |
| UINT16 min_delay, tBTM_INQ_RESULTS_CB *p_results_cb) |
| { |
| tBTM_STATUS status; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| BTM_TRACE_API6 ("BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: %d, max: %d", |
| p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps, |
| p_inqparms->filter_cond_type, min_delay, max_delay); |
| |
| /*** Make sure the device is ready ***/ |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| /* Only one active inquiry is allowed in this implementation. |
| Also do not allow an inquiry if the inquiry filter is being updated */ |
| if (p_inq->inq_active || p_inq->inqfilt_active) |
| return (BTM_BUSY); |
| |
| /* If illegal parameters return FALSE */ |
| if (p_inqparms->mode != BTM_GENERAL_INQUIRY && |
| p_inqparms->mode != BTM_LIMITED_INQUIRY) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* Verify the parameters for this command */ |
| if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN || |
| p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH || |
| min_delay <= p_inqparms->duration || |
| min_delay < BTM_PER_INQ_MIN_MIN_PERIOD || |
| min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || |
| max_delay <= min_delay || |
| max_delay < BTM_PER_INQ_MIN_MAX_PERIOD || |
| max_delay > BTM_PER_INQ_MAX_MAX_PERIOD) |
| { |
| return (BTM_ILLEGAL_VALUE); |
| } |
| |
| /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */ |
| p_inq->inqparms = *p_inqparms; |
| p_inq->per_min_delay = min_delay; |
| p_inq->per_max_delay = max_delay; |
| p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */ |
| p_inq->p_inq_results_cb = p_results_cb; |
| |
| p_inq->inq_active = (UINT8)((p_inqparms->mode == BTM_LIMITED_INQUIRY) ? |
| (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE) : |
| (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE)); |
| |
| #if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE) |
| BTM_TRACE_WARNING0("BTM: Bypassing event filtering..."); |
| |
| p_inq->state = BTM_INQ_ACTIVE_STATE; |
| p_inq->inqfilt_active = FALSE; |
| btm_initiate_inquiry (p_inq); |
| status = BTM_CMD_STARTED; |
| #else |
| /* If a filter is specified, then save it for later and clear the current filter. |
| The setting of the filter is done upon completion of clearing of the previous |
| filter. |
| */ |
| if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER) |
| { |
| p_inq->state = BTM_INQ_CLR_FILT_STATE; |
| p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER; |
| } |
| else /* The filter is not being used so simply clear it; the inquiry can start after this operation */ |
| p_inq->state = BTM_INQ_SET_FILT_STATE; |
| |
| /* Before beginning the inquiry the current filter must be cleared, so initiate the command */ |
| if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED) |
| { |
| /* If set filter command is not succesful reset the state */ |
| p_inq->p_inq_results_cb = NULL; |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| |
| } |
| |
| #endif |
| return (status); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_CancelPeriodicInquiry |
| ** |
| ** Description This function cancels a periodic inquiry |
| ** |
| ** Returns |
| ** BTM_NO_RESOURCES if could not allocate a message buffer |
| ** BTM_SUCCESS - if cancelling the periodic inquiry |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_CancelPeriodicInquiry(void) |
| { |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tBTM_STATUS status = BTM_SUCCESS; |
| BTM_TRACE_API0 ("BTM_CancelPeriodicInquiry called"); |
| |
| /*** Make sure the device is ready ***/ |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| /* Only cancel if one is active */ |
| if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) |
| { |
| btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE; |
| btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; |
| |
| if (!btsnd_hcic_exit_per_inq ()) |
| status = BTM_NO_RESOURCES; |
| |
| /* If the event filter is in progress, mark it so that the processing of the return |
| event will be ignored */ |
| if(p_inq->inqfilt_active) |
| p_inq->pending_filt_complete_event++; |
| |
| p_inq->inqfilt_active = FALSE; |
| p_inq->inq_counter++; |
| } |
| |
| return (status); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetConnectability |
| ** |
| ** Description This function is called to set the device into or out of |
| ** connectable mode. Discoverable mode means page scans enabled. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_ILLEGAL_VALUE if a bad parameter is detected |
| ** BTM_NO_RESOURCES if could not allocate a message buffer |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 interval) |
| { |
| UINT8 scan_mode = 0; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| BTM_TRACE_API0 ("BTM_SetConnectability"); |
| |
| #if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE) |
| if (btm_ble_set_connectability(page_mode) == BTM_SUCCESS) |
| { |
| p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK); |
| p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK); |
| } |
| page_mode &= ~BTM_BLE_CONNECTABLE_MASK; |
| |
| #endif |
| |
| /*** Check mode parameter ***/ |
| if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* Make sure the controller is active */ |
| if (btm_cb.devcb.state < BTM_DEV_STATE_READY) |
| return (BTM_DEV_RESET); |
| |
| /* If the window and/or interval is '0', set to default values */ |
| if (!window) |
| window = BTM_DEFAULT_CONN_WINDOW; |
| |
| if (!interval) |
| interval = BTM_DEFAULT_CONN_INTERVAL; |
| |
| BTM_TRACE_API3 ("BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, interval 0x%04x", |
| page_mode, window, interval); |
| |
| /*** Check for valid window and interval parameters ***/ |
| /*** Only check window and duration if mode is connectable ***/ |
| if (page_mode == BTM_CONNECTABLE) |
| { |
| /* window must be less than or equal to interval */ |
| if (window < HCI_MIN_PAGESCAN_WINDOW || |
| window > HCI_MAX_PAGESCAN_WINDOW || |
| interval < HCI_MIN_PAGESCAN_INTERVAL || |
| interval > HCI_MAX_PAGESCAN_INTERVAL || |
| window > interval) |
| { |
| return (BTM_ILLEGAL_VALUE); |
| } |
| |
| scan_mode |= HCI_PAGE_SCAN_ENABLED; |
| } |
| |
| if ((window != p_inq->page_scan_window) || |
| (interval != p_inq->page_scan_period)) |
| { |
| p_inq->page_scan_window = window; |
| p_inq->page_scan_period = interval; |
| if (!btsnd_hcic_write_pagescan_cfg (interval, window)) |
| return (BTM_NO_RESOURCES); |
| } |
| |
| /* Keep the inquiry scan as previouosly set */ |
| if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK) |
| scan_mode |= HCI_INQUIRY_SCAN_ENABLED; |
| |
| if (btsnd_hcic_write_scan_enable (scan_mode)) |
| { |
| p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK); |
| p_inq->connectable_mode |= page_mode; |
| |
| return (BTM_SUCCESS); |
| } |
| |
| return (BTM_NO_RESOURCES); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ReadConnectability |
| ** |
| ** Description This function is called to read the current discoverability |
| ** mode of the device. |
| ** Output Params p_window - current page scan duration |
| ** p_interval - current time between page scans |
| ** |
| ** Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE |
| ** |
| *******************************************************************************/ |
| UINT16 BTM_ReadConnectability (UINT16 *p_window, UINT16 *p_interval) |
| { |
| BTM_TRACE_API0 ("BTM_ReadConnectability"); |
| if (p_window) |
| *p_window = btm_cb.btm_inq_vars.page_scan_window; |
| |
| if (p_interval) |
| *p_interval = btm_cb.btm_inq_vars.page_scan_period; |
| |
| return (btm_cb.btm_inq_vars.connectable_mode); |
| } |
| |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_IsInquiryActive |
| ** |
| ** Description This function returns a bit mask of the current inquiry state |
| ** |
| ** Returns BTM_INQUIRY_INACTIVE if inactive (0) |
| ** BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active |
| ** BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active |
| ** BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active |
| ** |
| *******************************************************************************/ |
| UINT16 BTM_IsInquiryActive (void) |
| { |
| BTM_TRACE_API0 ("BTM_IsInquiryActive"); |
| |
| return(btm_cb.btm_inq_vars.inq_active); |
| } |
| |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_CancelInquiry |
| ** |
| ** Description This function cancels an inquiry if active |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** BTM_NO_RESOURCES if could not allocate a message buffer |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_CancelInquiry(void) |
| { |
| tBTM_STATUS status = BTM_SUCCESS; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| BTM_TRACE_API0 ("BTM_CancelInquiry called"); |
| |
| /*** Make sure the device is ready ***/ |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| /* Only cancel if not in periodic mode, otherwise the caller should call BTM_CancelPeriodicMode */ |
| if (p_inq->inq_active && |
| (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) |
| { |
| p_inq->inq_active = BTM_INQUIRY_INACTIVE; |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; /* Do not notify caller anymore */ |
| p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; /* Do not notify caller anymore */ |
| |
| /* If the event filter is in progress, mark it so that the processing of the return |
| event will be ignored */ |
| if (p_inq->inqfilt_active) |
| { |
| p_inq->inqfilt_active = FALSE; |
| p_inq->pending_filt_complete_event++; |
| } |
| /* Initiate the cancel inquiry */ |
| else |
| { |
| if (!btsnd_hcic_inq_cancel()) |
| status = BTM_NO_RESOURCES; |
| #if BLE_INCLUDED == TRUE |
| if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) |
| btm_ble_stop_scan(); |
| #endif |
| } |
| |
| #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) |
| /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event |
| * and then send the BUSY_LEVEL event |
| * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); |
| */ |
| #endif |
| |
| p_inq->inq_counter++; |
| btm_clr_inq_result_flt(); |
| } |
| |
| return (status); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_StartInquiry |
| ** |
| ** Description This function is called to start an inquiry. |
| ** |
| ** Parameters: p_inqparms - pointer to the inquiry information |
| ** mode - GENERAL or LIMITED inquiry |
| ** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) |
| ** max_resps - maximum amount of devices to search for before ending the inquiry |
| ** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or |
| ** BTM_FILTER_COND_BD_ADDR |
| ** filter_cond - value for the filter (based on filter_cond_type) |
| ** |
| ** p_results_cb - Pointer to the callback routine which gets called |
| ** upon receipt of an inquiry result. If this field is |
| ** NULL, the application is not notified. |
| ** |
| ** p_cmpl_cb - Pointer to the callback routine which gets called |
| ** upon completion. If this field is NULL, the |
| ** application is not notified when completed. |
| ** Returns tBTM_STATUS |
| ** BTM_CMD_STARTED if successfully initiated |
| ** BTM_BUSY if already in progress |
| ** BTM_ILLEGAL_VALUE if parameter(s) are out of range |
| ** BTM_NO_RESOURCES if could not allocate resources to start the command |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_StartInquiry (tBTM_INQ_PARMS *p_inqparms, tBTM_INQ_RESULTS_CB *p_results_cb, |
| tBTM_CMPL_CB *p_cmpl_cb) |
| { |
| tBTM_STATUS status; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| BTM_TRACE_API4 ("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d", |
| p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps, |
| p_inqparms->filter_cond_type); |
| |
| /* Only one active inquiry is allowed in this implementation. |
| Also do not allow an inquiry if the inquiry filter is being updated */ |
| if (p_inq->inq_active || p_inq->inqfilt_active) |
| return (BTM_BUSY); |
| |
| /*** Make sure the device is ready ***/ |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_GENERAL_INQUIRY && |
| (p_inqparms->mode & BTM_BR_INQUIRY_MASK)!= BTM_LIMITED_INQUIRY) |
| return (BTM_ILLEGAL_VALUE); |
| |
| /* Save the inquiry parameters to be used upon the completion of setting/clearing the inquiry filter */ |
| p_inq->inqparms = *p_inqparms; |
| #if (BLE_INCLUDED == TRUE) |
| p_inq->inqparms.mode = (UINT8)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) | (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| #else |
| p_inq->inqparms.mode = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| #endif |
| |
| /* Initialize the inquiry variables */ |
| p_inq->state = BTM_INQ_ACTIVE_STATE; |
| p_inq->p_inq_cmpl_cb = p_cmpl_cb; |
| p_inq->p_inq_results_cb = p_results_cb; |
| p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */ |
| p_inq->inq_active = (UINT8)(1 << (p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| |
| BTM_TRACE_DEBUG1("BTM_StartInquiry: p_inq->inq_active = 0x%02x", p_inq->inq_active); |
| |
| /* start LE inquiry here if requested */ |
| #if BLE_INCLUDED == TRUE |
| if (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) |
| { |
| /* BLE for now does not support filter condition for inquiry */ |
| if (btm_ble_start_inquiry((UINT8)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), |
| p_inq->inqparms.duration) != BTM_SUCCESS) |
| { |
| BTM_TRACE_ERROR0("Err Starting LE Inquiry."); |
| p_inq->inqparms.mode &= ~ BTM_BLE_INQUIRY_MASK; |
| } |
| |
| p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK; |
| |
| BTM_TRACE_DEBUG1("BTM_StartInquiry: mode = %02x", p_inqparms->mode); |
| } |
| #endif /* end of BLE_INCLUDED */ |
| |
| #if (defined(BTM_BYPASS_EVENT_FILTERING) && BTM_BYPASS_EVENT_FILTERING == TRUE) |
| BTM_TRACE_WARNING0("BTM: Bypassing event filtering..."); |
| p_inq->inqfilt_active = FALSE; |
| btm_initiate_inquiry (p_inq); |
| status = BTM_CMD_STARTED; |
| #else |
| /* If a filter is specified, then save it for later and clear the current filter. |
| The setting of the filter is done upon completion of clearing of the previous |
| filter. |
| */ |
| switch (p_inqparms->filter_cond_type) |
| { |
| case BTM_CLR_INQUIRY_FILTER: |
| p_inq->state = BTM_INQ_SET_FILT_STATE; |
| break; |
| |
| case BTM_FILTER_COND_DEVICE_CLASS: |
| case BTM_FILTER_COND_BD_ADDR: |
| /* The filter is not being used so simply clear it; |
| the inquiry can start after this operation */ |
| p_inq->state = BTM_INQ_CLR_FILT_STATE; |
| p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER; |
| /* =============>>>> adding LE filtering here ????? */ |
| break; |
| |
| default: |
| return (BTM_ILLEGAL_VALUE); |
| } |
| |
| /* Before beginning the inquiry the current filter must be cleared, so initiate the command */ |
| if ((status = btm_set_inq_event_filter (p_inqparms->filter_cond_type, &p_inqparms->filter_cond)) != BTM_CMD_STARTED) |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| #endif |
| return (status); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ReadRemoteDeviceName |
| ** |
| ** Description This function initiates a remote device HCI command to the |
| ** controller and calls the callback when the process has completed. |
| ** |
| ** Input Params: remote_bda - device address of name to retrieve |
| ** p_cb - callback function called when BTM_CMD_STARTED |
| ** is returned. |
| ** A pointer to tBTM_REMOTE_DEV_NAME is passed to the |
| ** callback. |
| ** |
| ** Returns |
| ** BTM_CMD_STARTED is returned if the request was successfully sent |
| ** to HCI. |
| ** BTM_BUSY if already in progress |
| ** BTM_UNKNOWN_ADDR if device address is bad |
| ** BTM_NO_RESOURCES if could not allocate resources to start the command |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_ReadRemoteDeviceName (BD_ADDR remote_bda, tBTM_CMPL_CB *p_cb) |
| { |
| tBTM_INQ_INFO *p_cur = NULL; |
| tINQ_DB_ENT *p_i; |
| |
| #if BLE_INCLUDED == TRUE |
| tBT_DEVICE_TYPE dev_type; |
| tBLE_ADDR_TYPE addr_type; |
| #endif |
| |
| BTM_TRACE_API6 ("BTM_ReadRemoteDeviceName: bd addr [%02x%02x%02x%02x%02x%02x]", |
| remote_bda[0], remote_bda[1], remote_bda[2], |
| remote_bda[3], remote_bda[4], remote_bda[5]); |
| |
| /* Use the remote device's clock offset if it is in the local inquiry database */ |
| if ((p_i = btm_inq_db_find (remote_bda)) != NULL) |
| { |
| p_cur = &p_i->inq_info; |
| |
| #if (BTM_INQ_GET_REMOTE_NAME == TRUE) |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| #endif |
| } |
| BTM_TRACE_API0 ("no device found in inquiry db"); |
| |
| #if (BLE_INCLUDED == TRUE) |
| BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type); |
| if (dev_type == BT_DEVICE_TYPE_BLE) |
| { |
| return btm_ble_read_remote_name(remote_bda, p_cur, p_cb); |
| } |
| else |
| #endif |
| |
| return (btm_initiate_rem_name (remote_bda, p_cur, BTM_RMT_NAME_EXT, |
| BTM_EXT_RMT_NAME_TIMEOUT, p_cb)); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_CancelRemoteDeviceName |
| ** |
| ** Description This function initiates the cancel request for the specified |
| ** remote device. |
| ** |
| ** Input Params: None |
| ** |
| ** Returns |
| ** BTM_CMD_STARTED is returned if the request was successfully sent |
| ** to HCI. |
| ** BTM_NO_RESOURCES if could not allocate resources to start the command |
| ** BTM_WRONG_MODE if there is not an active remote name request. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_CancelRemoteDeviceName (void) |
| { |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| #if BLE_INCLUDED == TRUE |
| tBT_DEVICE_TYPE dev_type; |
| tBLE_ADDR_TYPE addr_type; |
| #endif |
| |
| BTM_TRACE_API0 ("BTM_CancelRemoteDeviceName()"); |
| |
| /* Make sure there is not already one in progress */ |
| if (p_inq->remname_active) |
| { |
| #if BLE_INCLUDED == TRUE |
| BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type); |
| if (dev_type == BT_DEVICE_TYPE_BLE) |
| { |
| if (btm_ble_cancel_remote_name(p_inq->remname_bda)) |
| return (BTM_CMD_STARTED); |
| else |
| return (BTM_UNKNOWN_ADDR); |
| } |
| else |
| #endif |
| if (btsnd_hcic_rmt_name_req_cancel (p_inq->remname_bda)) |
| return (BTM_CMD_STARTED); |
| else |
| return (BTM_NO_RESOURCES); |
| } |
| else |
| return (BTM_WRONG_MODE); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InqFirstResult |
| ** |
| ** Description This function looks through the inquiry database for the first |
| ** used entrysince the LAST inquiry. This is used in conjunction |
| ** with BTM_InqNext by applications as a way to walk through the |
| ** inquiry results database. |
| ** |
| ** Returns pointer to first in-use entry, or NULL if DB is empty |
| ** |
| *******************************************************************************/ |
| tBTM_INQ_INFO *BTM_InqFirstResult (void) |
| { |
| UINT16 xx; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1; |
| |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if (p_ent->in_use && p_ent->inq_count == cur_inq_count) |
| return (&p_ent->inq_info); |
| } |
| |
| /* If here, no used entry found */ |
| return ((tBTM_INQ_INFO *)NULL); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InqNextResult |
| ** |
| ** Description This function looks through the inquiry database for the next |
| ** used entrysince the LAST inquiry. If the input parameter is NULL, |
| ** the first entry is returned. |
| ** |
| ** Returns pointer to next in-use entry, or NULL if no more found. |
| ** |
| *******************************************************************************/ |
| tBTM_INQ_INFO *BTM_InqNextResult (tBTM_INQ_INFO *p_cur) |
| { |
| tINQ_DB_ENT *p_ent; |
| UINT16 inx; |
| UINT32 cur_inq_count = btm_cb.btm_inq_vars.inq_counter - 1; |
| |
| if (p_cur) |
| { |
| p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info)); |
| inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1); |
| |
| for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++) |
| { |
| if (p_ent->in_use && p_ent->inq_count == cur_inq_count) |
| return (&p_ent->inq_info); |
| } |
| |
| /* If here, more entries found */ |
| return ((tBTM_INQ_INFO *)NULL); |
| } |
| else |
| return (BTM_InqDbFirst()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InqDbRead |
| ** |
| ** Description This function looks through the inquiry database for a match |
| ** based on Bluetooth Device Address. This is the application's |
| ** interface to get the inquiry details of a specific BD address. |
| ** |
| ** Returns pointer to entry, or NULL if not found |
| ** |
| *******************************************************************************/ |
| tBTM_INQ_INFO *BTM_InqDbRead (BD_ADDR p_bda) |
| { |
| UINT16 xx; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| |
| BTM_TRACE_API6 ("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]", |
| p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]); |
| |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) |
| return (&p_ent->inq_info); |
| } |
| |
| /* If here, not found */ |
| return ((tBTM_INQ_INFO *)NULL); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InqDbFirst |
| ** |
| ** Description This function looks through the inquiry database for the first |
| ** used entry, and returns that. This is used in conjunction with |
| ** BTM_InqDbNext by applications as a way to walk through the |
| ** inquiry database. |
| ** |
| ** Returns pointer to first in-use entry, or NULL if DB is empty |
| ** |
| *******************************************************************************/ |
| tBTM_INQ_INFO *BTM_InqDbFirst (void) |
| { |
| UINT16 xx; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if (p_ent->in_use) |
| return (&p_ent->inq_info); |
| } |
| |
| /* If here, no used entry found */ |
| return ((tBTM_INQ_INFO *)NULL); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InqDbNext |
| ** |
| ** Description This function looks through the inquiry database for the next |
| ** used entry, and returns that. If the input parameter is NULL, |
| ** the first entry is returned. |
| ** |
| ** Returns pointer to next in-use entry, or NULL if no more found. |
| ** |
| *******************************************************************************/ |
| tBTM_INQ_INFO *BTM_InqDbNext (tBTM_INQ_INFO *p_cur) |
| { |
| tINQ_DB_ENT *p_ent; |
| UINT16 inx; |
| |
| if (p_cur) |
| { |
| p_ent = (tINQ_DB_ENT *) ((UINT8 *)p_cur - offsetof (tINQ_DB_ENT, inq_info)); |
| inx = (UINT16)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1); |
| |
| for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE; inx++, p_ent++) |
| { |
| if (p_ent->in_use) |
| return (&p_ent->inq_info); |
| } |
| |
| /* If here, more entries found */ |
| return ((tBTM_INQ_INFO *)NULL); |
| } |
| else |
| return (BTM_InqDbFirst()); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ClearInqDb |
| ** |
| ** Description This function is called to clear out a device or all devices |
| ** from the inquiry database. |
| ** |
| ** Parameter p_bda - (input) BD_ADDR -> Address of device to clear |
| ** (NULL clears all entries) |
| ** |
| ** Returns BTM_BUSY if an inquiry, get remote name, or event filter |
| ** is active, otherwise BTM_SUCCESS |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_ClearInqDb (BD_ADDR p_bda) |
| { |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| /* If an inquiry or remote name is in progress return busy */ |
| if (p_inq->inq_active != BTM_INQUIRY_INACTIVE || |
| p_inq->inqfilt_active) |
| return (BTM_BUSY); |
| |
| btm_clr_inq_db(p_bda); |
| |
| return (BTM_SUCCESS); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ReadNumInqDbEntries |
| ** |
| ** Returns This function returns the number of entries in the inquiry database. |
| ** |
| *******************************************************************************/ |
| UINT8 BTM_ReadNumInqDbEntries (void) |
| { |
| UINT8 num_entries; |
| UINT8 num_results; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| |
| for (num_entries = 0, num_results = 0; num_entries < BTM_INQ_DB_SIZE; num_entries++, p_ent++) |
| { |
| if (p_ent->in_use) |
| num_results++; |
| } |
| |
| return (num_results); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_InquiryRegisterForChanges |
| ** |
| ** Returns This function is called to register a callback for when the |
| ** inquiry database changes, i.e. new entry or entry deleted. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_InquiryRegisterForChanges (tBTM_INQ_DB_CHANGE_CB *p_cb) |
| { |
| if (!p_cb) |
| btm_cb.btm_inq_vars.p_inq_change_cb = NULL; |
| else if (btm_cb.btm_inq_vars.p_inq_change_cb) |
| return (BTM_BUSY); |
| else |
| btm_cb.btm_inq_vars.p_inq_change_cb = p_cb; |
| |
| return (BTM_SUCCESS); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_SetInquiryFilterCallback |
| ** |
| ** Description Host can register to be asked whenever an inquiry result |
| ** is received. If host does not like the device no name |
| ** request is issued for the device |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void BTM_SetInquiryFilterCallback (tBTM_FILTER_CB *p_callback) |
| { |
| btm_cb.p_inq_filter_cb = p_callback; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_ReadInquiryRspTxPower |
| ** |
| ** Description This command will read the inquiry Transmit Power level used |
| ** to transmit the FHS and EIR data packets. |
| ** This can be used directly in the Tx Power Level EIR data type. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_ReadInquiryRspTxPower (tBTM_CMPL_CB *p_cb) |
| { |
| if (btm_cb.devcb.p_txpwer_cmpl_cb) |
| return (BTM_BUSY); |
| |
| btu_start_timer (&btm_cb.devcb.txpwer_timer, BTU_TTYPE_BTM_ACL, BTM_INQ_REPLY_TIMEOUT ); |
| |
| |
| btm_cb.devcb.p_txpwer_cmpl_cb = p_cb; |
| |
| if (!btsnd_hcic_read_inq_tx_power ()) |
| { |
| btm_cb.devcb.p_txpwer_cmpl_cb = NULL; |
| btu_stop_timer (&btm_cb.devcb.txpwer_timer); |
| return (BTM_NO_RESOURCES); |
| } |
| else |
| return (BTM_CMD_STARTED); |
| } |
| /******************************************************************************* |
| ** |
| ** Function BTM_WriteInquiryTxPower |
| ** |
| ** Description This command is used to write the inquiry transmit power level |
| ** used to transmit the inquiry (ID) data packets. The Controller |
| ** should use the supported TX power level closest to the Tx_Power |
| ** parameter. |
| ** |
| ** Returns BTM_SUCCESS if successful |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_WriteInquiryTxPower (INT8 tx_power) |
| { |
| tBTM_STATUS status = BTM_SUCCESS; |
| |
| if (tx_power < BTM_MIN_INQ_TX_POWER || tx_power > BTM_MAX_INQ_TX_POWER) |
| { |
| status = BTM_ILLEGAL_VALUE; |
| } |
| else if (!btsnd_hcic_write_inq_tx_power(tx_power)) |
| status = BTM_NO_RESOURCES; |
| |
| return status; |
| } |
| /********************************************************************************* |
| ********************************************************************************** |
| ** ** |
| ** BTM Internal Inquiry Functions ** |
| ** ** |
| ********************************************************************************** |
| *********************************************************************************/ |
| /******************************************************************************* |
| ** |
| ** Function btm_inq_db_reset |
| ** |
| ** Description This function is called at at reset to clear the inquiry |
| ** database & pending callback. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_inq_db_reset (void) |
| { |
| tBTM_REMOTE_DEV_NAME rem_name; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| UINT8 num_responses; |
| UINT8 temp_inq_active; |
| tBTM_STATUS status; |
| |
| btu_stop_timer (&p_inq->inq_timer_ent); |
| |
| /* If an inquiry or periodic inquiry is active, reset the mode to inactive */ |
| if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) |
| { |
| temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE |
| callback is called */ |
| p_inq->inq_active = BTM_INQUIRY_INACTIVE; |
| |
| /* If not a periodic inquiry, the complete callback must be called to notify caller */ |
| if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE || |
| temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE) |
| { |
| if (p_inq->p_inq_cmpl_cb) |
| { |
| num_responses = 0; |
| (*p_inq->p_inq_cmpl_cb)(&num_responses); |
| } |
| } |
| } |
| |
| /* Cancel a remote name request if active, and notify the caller (if waiting) */ |
| if (p_inq->remname_active ) |
| { |
| btu_stop_timer (&p_inq->rmt_name_timer_ent); |
| p_inq->remname_active = FALSE; |
| memset(p_inq->remname_bda, 0, BD_ADDR_LEN); |
| |
| if (p_inq->p_remname_cmpl_cb) |
| { |
| rem_name.status = BTM_DEV_RESET; |
| |
| (*p_inq->p_remname_cmpl_cb)(&rem_name); |
| p_inq->p_remname_cmpl_cb = NULL; |
| } |
| } |
| |
| /* Cancel an inquiry filter request if active, and notify the caller (if waiting) */ |
| if (p_inq->inqfilt_active) |
| { |
| p_inq->inqfilt_active = FALSE; |
| |
| if (p_inq->p_inqfilter_cmpl_cb) |
| { |
| status = BTM_DEV_RESET; |
| (*p_inq->p_inqfilter_cmpl_cb)(&status); |
| } |
| } |
| |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| p_inq->pending_filt_complete_event = 0; |
| p_inq->p_inq_results_cb = NULL; |
| btm_clr_inq_db(NULL); /* Clear out all the entries in the database */ |
| btm_clr_inq_result_flt(); |
| |
| p_inq->discoverable_mode = BTM_NON_DISCOVERABLE; |
| p_inq->connectable_mode = BTM_NON_CONNECTABLE; |
| p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD; |
| p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD; |
| |
| #if BLE_INCLUDED == TRUE |
| p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE; |
| p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE; |
| #endif |
| return; |
| } |
| |
| |
| /********************************************************************************* |
| ** |
| ** Function btm_inq_db_init |
| ** |
| ** Description This function is called at startup to initialize the inquiry |
| ** database. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_inq_db_init (void) |
| { |
| #if 0 /* cleared in btm_init; put back in if called from anywhere else! */ |
| memset (&btm_cb.btm_inq_vars, 0, sizeof (tBTM_INQUIRY_VAR_ST)); |
| #endif |
| btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY; |
| } |
| |
| /********************************************************************************* |
| ** |
| ** Function btm_inq_stop_on_ssp |
| ** |
| ** Description This function is called on incoming SSP |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_inq_stop_on_ssp(void) |
| { |
| UINT8 normal_active = (BTM_GENERAL_INQUIRY_ACTIVE|BTM_LIMITED_INQUIRY_ACTIVE); |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG4 ("btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| if (btm_cb.btm_inq_vars.no_inc_ssp) |
| { |
| if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE) |
| { |
| if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) |
| { |
| BTM_CancelPeriodicInquiry(); |
| } |
| else if (btm_cb.btm_inq_vars.inq_active & normal_active) |
| { |
| /* can not call BTM_CancelInquiry() here. We need to report inquiry complete evt */ |
| btsnd_hcic_inq_cancel(); |
| } |
| } |
| /* do not allow inquiry to start */ |
| btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE; |
| } |
| } |
| |
| /********************************************************************************* |
| ** |
| ** Function btm_inq_clear_ssp |
| ** |
| ** Description This function is called when pairing_state becomes idle |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_inq_clear_ssp(void) |
| { |
| btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE; |
| } |
| |
| /********************************************************************************* |
| ** |
| ** Function btm_clr_inq_db |
| ** |
| ** Description This function is called to clear out a device or all devices |
| ** from the inquiry database. |
| ** |
| ** Parameter p_bda - (input) BD_ADDR -> Address of device to clear |
| ** (NULL clears all entries) |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_clr_inq_db (BD_ADDR p_bda) |
| { |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tINQ_DB_ENT *p_ent = p_inq->inq_db; |
| UINT16 xx; |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG2 ("btm_clr_inq_db: inq_active:0x%x state:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); |
| #endif |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if (p_ent->in_use) |
| { |
| /* If this is the specified BD_ADDR or clearing all devices */ |
| if (p_bda == NULL || |
| (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) |
| { |
| p_ent->in_use = FALSE; |
| #if (BTM_INQ_GET_REMOTE_NAME == TRUE) |
| p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| #endif |
| |
| if (btm_cb.btm_inq_vars.p_inq_change_cb) |
| (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_ent->inq_info, FALSE); |
| } |
| } |
| } |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG2 ("inq_active:0x%x state:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state); |
| #endif |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_clr_inq_result_flt |
| ** |
| ** Description This function looks through the bdaddr database for a match |
| ** based on Bluetooth Device Address |
| ** |
| ** Returns TRUE if found, else FALSE (new entry) |
| ** |
| *******************************************************************************/ |
| static void btm_clr_inq_result_flt (void) |
| { |
| #if BTM_USE_INQ_RESULTS_FILTER == TRUE |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| if (p_inq->p_bd_db) |
| { |
| GKI_freebuf(p_inq->p_bd_db); |
| p_inq->p_bd_db = NULL; |
| } |
| p_inq->num_bd_entries = 0; |
| p_inq->max_bd_entries = 0; |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_inq_find_bdaddr |
| ** |
| ** Description This function looks through the bdaddr database for a match |
| ** based on Bluetooth Device Address |
| ** |
| ** Returns TRUE if found, else FALSE (new entry) |
| ** |
| *******************************************************************************/ |
| BOOLEAN btm_inq_find_bdaddr (BD_ADDR p_bda) |
| { |
| #if BTM_USE_INQ_RESULTS_FILTER == TRUE |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tINQ_BDADDR *p_db = &p_inq->p_bd_db[0]; |
| UINT16 xx; |
| |
| /* Don't bother searching, database doesn't exist or periodic mode */ |
| if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db) |
| return (FALSE); |
| |
| for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++) |
| { |
| if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN) |
| && p_db->inq_count == p_inq->inq_counter) |
| return (TRUE); |
| } |
| |
| if (xx < p_inq->max_bd_entries) |
| { |
| p_db->inq_count = p_inq->inq_counter; |
| memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN); |
| p_inq->num_bd_entries++; |
| } |
| |
| #endif |
| /* If here, New Entry */ |
| return (FALSE); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_inq_db_find |
| ** |
| ** Description This function looks through the inquiry database for a match |
| ** based on Bluetooth Device Address |
| ** |
| ** Returns pointer to entry, or NULL if not found |
| ** |
| *******************************************************************************/ |
| tINQ_DB_ENT *btm_inq_db_find (BD_ADDR p_bda) |
| { |
| UINT16 xx; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if ((p_ent->in_use) && (!memcmp (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN))) |
| return (p_ent); |
| } |
| |
| /* If here, not found */ |
| return (NULL); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_inq_db_new |
| ** |
| ** Description This function looks through the inquiry database for an unused |
| ** entry. If no entry is free, it allocates the oldest entry. |
| ** |
| ** Returns pointer to entry |
| ** |
| *******************************************************************************/ |
| tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda) |
| { |
| UINT16 xx; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| tINQ_DB_ENT *p_old = btm_cb.btm_inq_vars.inq_db; |
| UINT32 ot = 0xFFFFFFFF; |
| |
| for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) |
| { |
| if (!p_ent->in_use) |
| { |
| memset (p_ent, 0, sizeof (tINQ_DB_ENT)); |
| memcpy (p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN); |
| p_ent->in_use = TRUE; |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| p_ent->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| #endif |
| |
| return (p_ent); |
| } |
| |
| if (p_ent->time_of_resp < ot) |
| { |
| p_old = p_ent; |
| ot = p_ent->time_of_resp; |
| } |
| } |
| |
| /* If here, no free entry found. Return the oldest. */ |
| |
| /* Before deleting the oldest, if anyone is registered for change */ |
| /* notifications, then tell him we are deleting an entry. */ |
| if (btm_cb.btm_inq_vars.p_inq_change_cb) |
| (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_old->inq_info, FALSE); |
| |
| memset (p_old, 0, sizeof (tINQ_DB_ENT)); |
| memcpy (p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN); |
| p_old->in_use = TRUE; |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| p_old->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| #endif |
| |
| return (p_old); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_set_inq_event_filter |
| ** |
| ** Description This function is called to set the inquiry event filter. |
| ** It is called by either internally, or by the external API function |
| ** (BTM_SetInqEventFilter). It is used internally as part of the |
| ** inquiry processing. |
| ** |
| ** Input Params: |
| ** filter_cond_type - this is the type of inquiry filter to apply: |
| ** BTM_FILTER_COND_DEVICE_CLASS, |
| ** BTM_FILTER_COND_BD_ADDR, or |
| ** BTM_CLR_INQUIRY_FILTER |
| ** |
| ** p_filt_cond - this is either a BD_ADDR or DEV_CLASS depending on the |
| ** filter_cond_type (See section 4.7.3 of Core Spec 1.0b). |
| ** |
| ** Returns BTM_CMD_STARTED if successfully initiated |
| ** BTM_NO_RESOURCES if couldn't get a memory pool buffer |
| ** BTM_ILLEGAL_VALUE if a bad parameter was detected |
| ** |
| *******************************************************************************/ |
| static tBTM_STATUS btm_set_inq_event_filter (UINT8 filter_cond_type, |
| tBTM_INQ_FILT_COND *p_filt_cond) |
| { |
| UINT8 condition_length = DEV_CLASS_LEN * 2; |
| UINT8 condition_buf[DEV_CLASS_LEN * 2]; |
| UINT8 *p_cond = condition_buf; /* points to the condition to pass to HCI */ |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG1 ("btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]", |
| filter_cond_type); |
| BTM_TRACE_DEBUG6 (" condition [%02x%02x%02x %02x%02x%02x]", |
| p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1], p_filt_cond->bdaddr_cond[2], |
| p_filt_cond->bdaddr_cond[3], p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]); |
| #endif |
| |
| /* Load the correct filter condition to pass to the lower layer */ |
| switch (filter_cond_type) |
| { |
| case BTM_FILTER_COND_DEVICE_CLASS: |
| /* copy the device class and device class fields into contiguous memory to send to HCI */ |
| memcpy (condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN); |
| memcpy (&condition_buf[DEV_CLASS_LEN], |
| p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN); |
| |
| /* condition length should already be set as the default */ |
| break; |
| |
| case BTM_FILTER_COND_BD_ADDR: |
| p_cond = p_filt_cond->bdaddr_cond; |
| |
| /* condition length should already be set as the default */ |
| break; |
| |
| case BTM_CLR_INQUIRY_FILTER: |
| condition_length = 0; |
| break; |
| |
| default: |
| return (BTM_ILLEGAL_VALUE); /* Bad parameter was passed in */ |
| } |
| |
| btm_cb.btm_inq_vars.inqfilt_active = TRUE; |
| |
| /* Filter the inquiry results for the specified condition type and value */ |
| if (btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type, |
| p_cond, condition_length)) |
| |
| return (BTM_CMD_STARTED); |
| else |
| return (BTM_NO_RESOURCES); |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_event_filter_complete |
| ** |
| ** Description This function is called when a set event filter has completed. |
| ** Note: This routine currently only handles inquiry filters. |
| ** Connection filters are ignored for now. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_event_filter_complete (UINT8 *p) |
| { |
| UINT8 hci_status; |
| tBTM_STATUS status; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tBTM_CMPL_CB *p_cb = p_inq->p_inqfilter_cmpl_cb; |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG3 ("btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| /* If the filter complete event is from an old or cancelled request, ignore it */ |
| if(p_inq->pending_filt_complete_event) |
| { |
| p_inq->pending_filt_complete_event--; |
| return; |
| } |
| |
| /* Only process the inquiry filter; Ignore the connection filter until it |
| is used by the upper layers */ |
| if (p_inq->inqfilt_active == TRUE ) |
| { |
| /* Extract the returned status from the buffer */ |
| STREAM_TO_UINT8 (hci_status, p); |
| if (hci_status != HCI_SUCCESS) |
| { |
| /* If standalone operation, return the error status; if embedded in the inquiry, continue the inquiry */ |
| BTM_TRACE_WARNING1 ("BTM Warning: Set Event Filter Failed (HCI returned 0x%x)", hci_status); |
| status = BTM_ERR_PROCESSING; |
| } |
| else |
| status = BTM_SUCCESS; |
| |
| /* If the set filter was initiated externally (via BTM_SetInqEventFilter), call the |
| callback function to notify the initiator that it has completed */ |
| if (p_inq->state == BTM_INQ_INACTIVE_STATE) |
| { |
| p_inq->inqfilt_active = FALSE; |
| if (p_cb) |
| (*p_cb) (&status); |
| } |
| else /* An inquiry is active (the set filter command was internally generated), |
| process the next state of the process (Set a new filter or start the inquiry). */ |
| { |
| if(status != BTM_SUCCESS) |
| { |
| /* Process the inquiry complete (Error Status) */ |
| btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK)); |
| |
| /* btm_process_inq_complete() does not restore the following settings on periodic inquiry */ |
| p_inq->inqfilt_active = FALSE; |
| p_inq->inq_active = BTM_INQUIRY_INACTIVE; |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| |
| return; |
| } |
| |
| /* Check to see if a new filter needs to be set up */ |
| if (p_inq->state == BTM_INQ_CLR_FILT_STATE) |
| { |
| if ((status = btm_set_inq_event_filter (p_inq->inqparms.filter_cond_type, &p_inq->inqparms.filter_cond)) == BTM_CMD_STARTED) |
| { |
| p_inq->state = BTM_INQ_SET_FILT_STATE; |
| } |
| else /* Error setting the filter: Call the initiator's callback function to indicate a failure */ |
| { |
| p_inq->inqfilt_active = FALSE; |
| |
| /* Process the inquiry complete (Error Status) */ |
| btm_process_inq_complete (BTM_ERR_PROCESSING, (UINT8)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK)); |
| } |
| } |
| else /* Initiate the Inquiry or Periodic Inquiry */ |
| { |
| p_inq->state = BTM_INQ_ACTIVE_STATE; |
| p_inq->inqfilt_active = FALSE; |
| btm_initiate_inquiry (p_inq); |
| } |
| } |
| } |
| } |
| |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_initiate_inquiry |
| ** |
| ** Description This function is called to start an inquiry or periodic inquiry |
| ** upon completion of the setting and/or clearing of the inquiry filter. |
| ** |
| ** Inputs: p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry information |
| ** mode - GENERAL or LIMITED inquiry |
| ** duration - length in 1.28 sec intervals (If '0', the inquiry is CANCELLED) |
| ** max_resps - maximum amount of devices to search for before ending the inquiry |
| ** filter_cond_type - BTM_CLR_INQUIRY_FILTER, BTM_FILTER_COND_DEVICE_CLASS, or |
| ** BTM_FILTER_COND_BD_ADDR |
| ** filter_cond - value for the filter (based on filter_cond_type) |
| ** |
| ** Returns If an error occurs the initiator's callback is called with the error status. |
| ** |
| *******************************************************************************/ |
| static void btm_initiate_inquiry (tBTM_INQUIRY_VAR_ST *p_inq) |
| { |
| const LAP *lap; |
| tBTM_INQ_PARMS *p_inqparms = &p_inq->inqparms; |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG3 ("btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) |
| btm_acl_update_busy_level (BTM_BLI_INQ_EVT); |
| #endif |
| |
| if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE) |
| { |
| btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| return; |
| } |
| |
| /* Make sure the number of responses doesn't overflow the database configuration */ |
| p_inqparms->max_resps = (UINT8)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE) ? p_inqparms->max_resps : BTM_INQ_DB_SIZE); |
| |
| lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap : &general_inq_lap; |
| |
| if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) |
| { |
| if (!btsnd_hcic_per_inq_mode (p_inq->per_max_delay, |
| p_inq->per_min_delay, |
| *lap, p_inqparms->duration, |
| p_inqparms->max_resps)) |
| btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| } |
| else |
| { |
| #if BTM_USE_INQ_RESULTS_FILTER == TRUE |
| btm_clr_inq_result_flt(); |
| |
| /* Allocate memory to hold bd_addrs responding */ |
| if ((p_inq->p_bd_db = (tINQ_BDADDR *)GKI_getbuf(GKI_MAX_BUF_SIZE)) != NULL) |
| { |
| p_inq->max_bd_entries = (UINT16)(GKI_MAX_BUF_SIZE / sizeof(tINQ_BDADDR)); |
| memset(p_inq->p_bd_db, 0, GKI_MAX_BUF_SIZE); |
| /* BTM_TRACE_DEBUG1("btm_initiate_inquiry: memory allocated for %d bdaddrs", |
| p_inq->max_bd_entries); */ |
| } |
| |
| if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0)) |
| #else |
| if (!btsnd_hcic_inquiry(*lap, p_inqparms->duration, p_inqparms->max_resps)) |
| #endif /* BTM_USE_INQ_RESULTS_FILTER */ |
| btm_process_inq_complete (BTM_NO_RESOURCES, (UINT8)(p_inqparms->mode & BTM_BR_INQUIRY_MASK)); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_process_inq_results |
| ** |
| ** Description This function is called when inquiry results are received from |
| ** the device. It updates the inquiry database. If the inquiry |
| ** database is full, the oldest entry is discarded. |
| ** |
| ** Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD |
| ** BTM_INQ_RESULT_WITH_RSSI |
| ** BTM_INQ_RESULT_EXTENDED |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) |
| { |
| UINT8 num_resp, xx; |
| BD_ADDR bda; |
| tINQ_DB_ENT *p_i; |
| tBTM_INQ_RESULTS *p_cur; |
| BOOLEAN is_new = TRUE; |
| BOOLEAN update = FALSE; |
| INT8 i_rssi; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb; |
| UINT8 page_scan_rep_mode = 0; |
| UINT8 page_scan_per_mode = 0; |
| UINT8 page_scan_mode = 0; |
| UINT8 rssi = 0; |
| DEV_CLASS dc; |
| UINT16 clock_offset; |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| UINT8 *p_eir_data = NULL; |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| UINT8 remote_name_len; |
| #endif |
| #endif |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG3 ("btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| /* Only process the results if the inquiry is still active */ |
| if (!p_inq->inq_active) |
| return; |
| |
| STREAM_TO_UINT8 (num_resp, p); |
| |
| for (xx = 0; xx < num_resp; xx++) |
| { |
| update = FALSE; |
| /* Extract inquiry results */ |
| STREAM_TO_BDADDR (bda, p); |
| STREAM_TO_UINT8 (page_scan_rep_mode, p); |
| STREAM_TO_UINT8 (page_scan_per_mode, p); |
| |
| if (inq_res_mode == BTM_INQ_RESULT_STANDARD) |
| { |
| STREAM_TO_UINT8(page_scan_mode, p); |
| } |
| |
| STREAM_TO_DEVCLASS (dc, p); |
| STREAM_TO_UINT16 (clock_offset, p); |
| if (inq_res_mode != BTM_INQ_RESULT_STANDARD) |
| { |
| STREAM_TO_UINT8(rssi, p); |
| } |
| |
| p_i = btm_inq_db_find (bda); |
| |
| #if BTM_USE_INQ_RESULTS_FILTER == TRUE |
| /* Only process the num_resp is smaller than max_resps. |
| If results are queued to BTU task while canceling inquiry, |
| or when more than one result is in this response, > max_resp |
| responses could be processed which can confuse some apps |
| */ |
| if (p_inq->inqparms.max_resps && |
| p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps |
| #if BLE_INCLUDED == TRUE |
| /* new device response */ |
| && ( p_i == NULL || |
| /* exisiting device with BR/EDR info */ |
| (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) |
| ) |
| #endif |
| |
| ) |
| { |
| /* BTM_TRACE_WARNING0("INQ RES: Extra Response Received...ignoring"); */ |
| return; |
| } |
| #endif |
| |
| /* Check if this address has already been processed for this inquiry */ |
| if (btm_inq_find_bdaddr(bda)) |
| { |
| /* BTM_TRACE_DEBUG6("BDA seen before [%02x%02x %02x%02x %02x%02x]", |
| bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/ |
| /* By default suppose no update needed */ |
| i_rssi = (INT8)rssi; |
| |
| /* If this new RSSI is higher than the last one */ |
| if(p_inq->inqparms.report_dup && (rssi != 0) && |
| p_i && (i_rssi > p_i->inq_info.results.rssi || p_i->inq_info.results.rssi == 0 |
| #if BLE_INCLUDED == TRUE |
| /* BR/EDR inquiry information update */ |
| || (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0 |
| #endif |
| )) |
| { |
| p_cur = &p_i->inq_info.results; |
| BTM_TRACE_DEBUG2("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi); |
| p_cur->rssi = i_rssi; |
| update = TRUE; |
| } |
| /* If we received a second Extended Inq Event for an already */ |
| /* discovered device, this is because for the first one EIR was not received */ |
| else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i)) |
| { |
| p_cur = &p_i->inq_info.results; |
| update = TRUE; |
| } |
| /* If no update needed continue with next response (if any) */ |
| else |
| continue; |
| } |
| |
| /* Host can be registered to verify comming BDA or DC */ |
| if (btm_cb.p_inq_filter_cb) |
| { |
| if (!(* btm_cb.p_inq_filter_cb) (bda, dc)) |
| { |
| continue; |
| } |
| } |
| |
| /* If existing entry, use that, else get a new one (possibly reusing the oldest) */ |
| if (p_i == NULL) |
| { |
| p_i = btm_inq_db_new (bda); |
| is_new = TRUE; |
| } |
| |
| /* If an entry for the device already exists, overwrite it ONLY if it is from |
| a previous inquiry. (Ignore it if it is a duplicate response from the same |
| inquiry. |
| */ |
| else if (p_i->inq_count == p_inq->inq_counter |
| #if (BLE_INCLUDED == TRUE ) |
| && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) |
| #endif |
| ) |
| is_new = FALSE; |
| |
| /* keep updating RSSI to have latest value */ |
| if( inq_res_mode != BTM_INQ_RESULT_STANDARD ) |
| p_i->inq_info.results.rssi = (INT8)rssi; |
| else |
| p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI; |
| |
| if (is_new == TRUE) |
| { |
| /* Save the info */ |
| p_cur = &p_i->inq_info.results; |
| p_cur->page_scan_rep_mode = page_scan_rep_mode; |
| p_cur->page_scan_per_mode = page_scan_per_mode; |
| p_cur->page_scan_mode = page_scan_mode; |
| p_cur->dev_class[0] = dc[0]; |
| p_cur->dev_class[1] = dc[1]; |
| p_cur->dev_class[2] = dc[2]; |
| p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID; |
| |
| p_i->time_of_resp = GKI_get_tick_count (); |
| |
| if (p_i->inq_count != p_inq->inq_counter) |
| p_inq->inq_cmpl_info.num_resp++; /* A new response was found */ |
| |
| #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) |
| p_cur->inq_result_type = BTM_INQ_RESULT_BR; |
| if (p_i->inq_count != p_inq->inq_counter) |
| { |
| p_cur->device_type = BT_DEVICE_TYPE_BREDR; |
| p_i->scan_rsp = FALSE; |
| } |
| else |
| p_cur->device_type |= BT_DEVICE_TYPE_BREDR; |
| #endif |
| p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */ |
| |
| #if BTM_USE_INQ_RESULTS_FILTER == TRUE |
| /* If the number of responses found and not unlimited, issue a cancel inquiry */ |
| if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && |
| p_inq->inqparms.max_resps && |
| p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps |
| #if BLE_INCLUDED == TRUE |
| /* BLE scanning is active and received adv */ |
| && ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) && |
| p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) || |
| (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0) |
| #endif |
| ) |
| { |
| /* BTM_TRACE_DEBUG0("BTMINQ: Found devices, cancelling inquiry..."); */ |
| btsnd_hcic_inq_cancel(); |
| |
| #if BLE_INCLUDED == TRUE |
| if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) |
| btm_ble_stop_scan(); |
| #endif |
| |
| |
| #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) |
| btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); |
| #endif |
| } |
| #endif |
| /* Initialize flag to FALSE. This flag is set/used by application */ |
| p_i->inq_info.appl_knows_rem_name = FALSE; |
| } |
| |
| if (is_new || update) |
| { |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| if( inq_res_mode == BTM_INQ_RESULT_EXTENDED ) |
| { |
| if((p_eir_data = BTM_CheckEirData( p, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, |
| &remote_name_len )) == NULL) |
| { |
| p_eir_data = BTM_CheckEirData( p, BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, |
| &remote_name_len ); |
| } |
| |
| if( p_eir_data ) |
| { |
| if( remote_name_len > BTM_MAX_REM_BD_NAME_LEN ) |
| remote_name_len = BTM_MAX_REM_BD_NAME_LEN; |
| |
| p_i->inq_info.remote_name_len = remote_name_len; |
| memcpy( p_i->inq_info.remote_name, p_eir_data, p_i->inq_info.remote_name_len ); |
| p_i->inq_info.remote_name[p_i->inq_info.remote_name_len] = 0; |
| p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE; |
| } |
| else |
| p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| } |
| else |
| #endif |
| { |
| /* Clear out the device name so that it can be re-read */ |
| p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| } |
| #endif /*(BTM_INQ_GET_REMOTE_NAME==TRUE)*/ |
| |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| if( inq_res_mode == BTM_INQ_RESULT_EXTENDED ) |
| { |
| memset( p_cur->eir_uuid, 0, |
| BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS/8)); |
| /* set bit map of UUID list from received EIR */ |
| btm_set_eir_uuid( p, p_cur ); |
| p_eir_data = p; |
| } |
| else |
| p_eir_data = NULL; |
| #endif |
| |
| /* If a callback is registered, call it with the results */ |
| if (p_inq_results_cb) |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, p_eir_data); |
| #else |
| (p_inq_results_cb)((tBTM_INQ_RESULTS *) p_cur, NULL); |
| #endif |
| |
| /* If anyone is registered for change notifications, then tell him we added an entry. */ |
| if (p_inq->p_inq_change_cb) |
| (*p_inq->p_inq_change_cb) (&p_i->inq_info, TRUE); |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_sort_inq_result |
| ** |
| ** Description This function is called when inquiry complete is received |
| ** from the device to sort inquiry results based on rssi. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_sort_inq_result(void) |
| { |
| UINT8 xx, yy, num_resp; |
| tINQ_DB_ENT *p_tmp = NULL; |
| tINQ_DB_ENT *p_ent = btm_cb.btm_inq_vars.inq_db; |
| tINQ_DB_ENT *p_next = btm_cb.btm_inq_vars.inq_db+1; |
| int size; |
| |
| num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp<BTM_INQ_DB_SIZE)? |
| btm_cb.btm_inq_vars.inq_cmpl_info.num_resp: BTM_INQ_DB_SIZE; |
| |
| if((p_tmp = (tINQ_DB_ENT *)GKI_getbuf(sizeof(tINQ_DB_ENT))) != NULL) |
| { |
| size = sizeof(tINQ_DB_ENT); |
| for(xx = 0; xx < num_resp-1; xx++, p_ent++) |
| { |
| for(yy = xx+1, p_next = p_ent+1; yy < num_resp; yy++, p_next++) |
| { |
| if(p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi) |
| { |
| memcpy (p_tmp, p_next, size); |
| memcpy (p_next, p_ent, size); |
| memcpy (p_ent, p_tmp, size); |
| } |
| } |
| } |
| |
| GKI_freebuf(p_tmp); |
| } |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_process_inq_complete |
| ** |
| ** Description This function is called when inquiry complete is received |
| ** from the device. Call the callback if not in periodic inquiry |
| ** mode AND it is not NULL (The caller wants the event). |
| ** |
| ** The callback pass back the status and the number of responses |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_process_inq_complete (UINT8 status, UINT8 mode) |
| { |
| tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| tBTM_INQ_INFO *p_cur; |
| UINT8 tempstate; |
| #endif |
| |
| p_inq->inqparms.mode &= ~(mode); |
| |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG3 ("btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) |
| btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); |
| #endif |
| /* Ignore any stray or late complete messages if the inquiry is not active */ |
| if (p_inq->inq_active) |
| { |
| p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING); |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| if (p_inq->inq_cmpl_info.status == BTM_SUCCESS) |
| { |
| for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur)) |
| { |
| if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY) |
| { |
| tempstate = p_cur->remote_name_state; |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING; |
| |
| if (btm_initiate_rem_name (p_cur->results.remote_bd_addr, |
| p_cur, BTM_RMT_NAME_INQ, |
| BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED) |
| p_cur->remote_name_state = tempstate; |
| else |
| return; |
| } |
| } |
| } |
| #endif |
| |
| /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */ |
| if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0) |
| { |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| |
| /* Increment so the start of a next inquiry has a new count */ |
| p_inq->inq_counter++; |
| |
| btm_clr_inq_result_flt(); |
| |
| if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) && HCI_LMP_INQ_RSSI_SUPPORTED(btm_cb.devcb.local_features)) |
| { |
| btm_sort_inq_result(); |
| } |
| |
| /* Clear the results callback if set */ |
| p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; |
| p_inq->inq_active = BTM_INQUIRY_INACTIVE; |
| p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; |
| |
| /* If we have a callback registered for inquiry complete, call it */ |
| BTM_TRACE_DEBUG2 ("BTM Inq Compl Callback: status 0x%02x, num results %d", |
| p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp); |
| |
| if (p_inq_cb) |
| (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info); |
| } |
| |
| } |
| #if (BTM_INQ_DEBUG == TRUE) |
| BTM_TRACE_DEBUG3 ("inq_active:0x%x state:%d inqfilt_active:%d", |
| btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active); |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_process_cancel_complete |
| ** |
| ** Description This function is called when inquiry cancel complete is received |
| ** from the device.This function will also call the btm_process_inq_complete |
| ** This function is needed to differentiate a cancel_cmpl_evt from the |
| ** inq_cmpl_evt |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_process_cancel_complete(UINT8 status, UINT8 mode) |
| { |
| #if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) |
| btm_acl_update_busy_level (BTM_BLI_INQ_CANCEL_EVT); |
| #endif |
| btm_process_inq_complete(status, mode); |
| } |
| /******************************************************************************* |
| ** |
| ** Function btm_initiate_rem_name |
| ** |
| ** Description This function looks initiates a remote name request. It is called |
| ** either by GAP or by the API call BTM_ReadRemoteDeviceName. |
| ** |
| ** Input Params: p_cur - pointer to an inquiry result structure (NULL if nonexistent) |
| ** p_cb - callback function called when BTM_CMD_STARTED |
| ** is returned. |
| ** A pointer to tBTM_REMOTE_DEV_NAME is passed to the |
| ** callback. |
| ** |
| ** Returns |
| ** BTM_CMD_STARTED is returned if the request was sent to HCI. |
| ** BTM_BUSY if already in progress |
| ** BTM_NO_RESOURCES if could not allocate resources to start the command |
| ** BTM_WRONG_MODE if the device is not up. |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS btm_initiate_rem_name (BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, |
| UINT8 origin, UINT32 timeout, tBTM_CMPL_CB *p_cb) |
| { |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| BOOLEAN cmd_ok; |
| |
| |
| /*** Make sure the device is ready ***/ |
| if (!BTM_IsDeviceUp()) |
| return (BTM_WRONG_MODE); |
| |
| |
| if (origin == BTM_RMT_NAME_SEC) |
| { |
| cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1, |
| HCI_MANDATARY_PAGE_SCAN_MODE, 0); |
| if (cmd_ok) |
| return BTM_CMD_STARTED; |
| else |
| return BTM_NO_RESOURCES; |
| } |
| /* Make sure there are no two remote name requests from external API in progress */ |
| else if (origin == BTM_RMT_NAME_EXT) |
| { |
| if (p_inq->remname_active) |
| { |
| return (BTM_BUSY); |
| } |
| else |
| { |
| /* If there is no remote name request running,call the callback function and start timer */ |
| p_inq->p_remname_cmpl_cb = p_cb; |
| memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN); |
| btu_start_timer (&p_inq->rmt_name_timer_ent, |
| BTU_TTYPE_BTM_RMT_NAME, |
| timeout); |
| |
| /* If the database entry exists for the device, use its clock offset */ |
| if (p_cur) |
| { |
| cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, |
| p_cur->results.page_scan_rep_mode, |
| p_cur->results.page_scan_mode, |
| (UINT16)(p_cur->results.clock_offset | |
| BTM_CLOCK_OFFSET_VALID)); |
| } |
| else /* Otherwise use defaults and mark the clock offset as invalid */ |
| { |
| cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, HCI_PAGE_SCAN_REP_MODE_R1, |
| HCI_MANDATARY_PAGE_SCAN_MODE, 0); |
| } |
| if (cmd_ok) |
| { |
| p_inq->remname_active = TRUE; |
| return BTM_CMD_STARTED; |
| } |
| else |
| return BTM_NO_RESOURCES; |
| } |
| } |
| /* If the inquire feature is on */ |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| |
| else if (origin == BTM_RMT_NAME_INQ) |
| { |
| /* If the database entry exists for the device, use its clock offset */ |
| if (p_cur) |
| { |
| cmd_ok = btsnd_hcic_rmt_name_req (remote_bda, |
| p_cur->results.page_scan_rep_mode, |
| p_cur->results.page_scan_mode, |
| (UINT16)(p_cur->results.clock_offset | |
| BTM_CLOCK_OFFSET_VALID)); |
| } |
| else |
| { |
| cmd_ok = FALSE |
| } |
| |
| if (cmd_ok) |
| return BTM_CMD_STARTED; |
| else |
| return BTM_NO_RESOURCES; |
| } |
| #endif |
| else |
| { |
| |
| return BTM_ILLEGAL_VALUE; |
| |
| |
| } |
| |
| |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_process_remote_name |
| ** |
| ** Description This function is called when a remote name is received from |
| ** the device. If remote names are cached, it updates the inquiry |
| ** database. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_process_remote_name (BD_ADDR bda, BD_NAME bdn, UINT16 evt_len, UINT8 hci_status) |
| { |
| tBTM_REMOTE_DEV_NAME rem_name = {0}; |
| tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; |
| tBTM_CMPL_CB *p_cb = p_inq->p_remname_cmpl_cb; |
| UINT8 *p_n1; |
| |
| UINT16 temp_evt_len; |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| /*** These are only used if part of the Inquiry Process ***/ |
| tBTM_CMPL_CB *p_inq_cb; |
| tINQ_DB_ENT *p_i = NULL; |
| UINT8 *p_n; |
| tBTM_INQ_INFO *p_cur; |
| #endif |
| #if BLE_INCLUDED == TRUE |
| tBT_DEVICE_TYPE dev_type; |
| tBLE_ADDR_TYPE addr_type; |
| #endif |
| |
| |
| if (bda != NULL) |
| { |
| BTM_TRACE_EVENT6("BDA %02x:%02x:%02x:%02x:%02x:%02x",bda[0], bda[1], |
| bda[2], bda[3], |
| bda[4], bda[5]); |
| } |
| |
| BTM_TRACE_EVENT6("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x",p_inq->remname_bda[0], p_inq->remname_bda[1], |
| p_inq->remname_bda[2], p_inq->remname_bda[3], |
| p_inq->remname_bda[4], p_inq->remname_bda[5]); |
| |
| |
| |
| /* If the inquire BDA and remote DBA are the same, then stop the timer and set the active to false */ |
| if ((p_inq->remname_active ==TRUE)&& |
| (((bda != NULL) && |
| (memcmp(bda, p_inq->remname_bda,BD_ADDR_LEN)==0)) || bda == NULL)) |
| |
| { |
| #if BLE_INCLUDED == TRUE |
| BTM_ReadDevInfo(p_inq->remname_bda, &dev_type, &addr_type); |
| if (dev_type == BT_DEVICE_TYPE_BLE) |
| { |
| if (hci_status == HCI_ERR_UNSPECIFIED) |
| btm_ble_cancel_remote_name(p_inq->remname_bda); |
| } |
| #endif |
| btu_stop_timer (&p_inq->rmt_name_timer_ent); |
| p_inq->remname_active = FALSE; |
| /* Clean up and return the status if the command was not successful */ |
| /* Note: If part of the inquiry, the name is not stored, and the */ |
| /* inquiry complete callback is called. */ |
| |
| if ((hci_status == HCI_SUCCESS)) |
| { |
| /* Copy the name from the data stream into the return structure */ |
| /* Note that even if it is not being returned, it is used as a */ |
| /* temporary buffer. */ |
| p_n1 = (UINT8 *)rem_name.remote_bd_name; |
| rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN; |
| rem_name.status = BTM_SUCCESS; |
| temp_evt_len = rem_name.length; |
| |
| while (temp_evt_len > 0) |
| { |
| *p_n1++ = *bdn++; |
| temp_evt_len--; |
| } |
| } |
| |
| |
| /* If processing a stand alone remote name then report the error in the callback */ |
| else |
| { |
| rem_name.status = BTM_BAD_VALUE_RET; |
| rem_name.length = 0; |
| rem_name.remote_bd_name[0] = 0; |
| } |
| /* Reset the remote BAD to zero and call callback if possible */ |
| memset(p_inq->remname_bda, 0, BD_ADDR_LEN); |
| |
| p_inq->p_remname_cmpl_cb = NULL; |
| if (p_cb) |
| (p_cb)((tBTM_REMOTE_DEV_NAME *)&rem_name); |
| } |
| |
| |
| #if (BTM_INQ_GET_REMOTE_NAME==TRUE) |
| /* If existing entry, update the name */ |
| if ((bda != NULL) && ((p_i = btm_inq_db_find (bda)) != NULL) |
| && (hci_status == HCI_SUCCESS)) |
| { |
| p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_DONE; |
| p_n = p_i->inq_info.remote_name; |
| memset(p_n, 0, BTM_MAX_REM_BD_NAME_LEN + 1); |
| p_i->inq_info.remote_name_len = (rem_name.length < BTM_MAX_REM_BD_NAME_LEN) ? |
| rem_name.length : BTM_MAX_REM_BD_NAME_LEN; |
| evt_len = p_i->inq_info.remote_name_len; |
| p_n1 = (UINT8 *)rem_name.remote_bd_name; |
| while (evt_len > 0) |
| { |
| *p_n++ = *p_n1++; |
| evt_len--; |
| } |
| |
| if (btm_cb.btm_inq_vars.p_inq_change_cb) |
| (*btm_cb.btm_inq_vars.p_inq_change_cb) (&p_i->inq_info, TRUE); |
| } |
| else |
| { |
| if (p_i) |
| p_i->inq_info.remote_name_state = BTM_INQ_RMT_NAME_FAILED; |
| else |
| { |
| /* Find the entry which is currently doing name request */ |
| for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur)) |
| { |
| if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_PENDING) |
| { |
| /* Should be only one */ |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED; |
| break; |
| } |
| } |
| } |
| } |
| |
| /* If an inquiry is in progress then update other entries */ |
| if (p_inq->inq_active) |
| { |
| /* Check if there are any more entries inquired but not named */ |
| for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur)) |
| { |
| if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_EMPTY) |
| { |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_PENDING; |
| #if (BLE_INCLUDED == TRUE) |
| BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type); |
| if (dev_type == BT_DEVICE_TYPE_BLE) |
| { |
| if (btm_ble_read_remote_name(remote_bda, p_cur, p_cb) != BTM_CMD_STARTED) |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED; |
| else |
| return; |
| } |
| else |
| #endif |
| { |
| if (btm_initiate_rem_name (p_cur->results.remote_bd_addr, |
| p_cur, BTM_RMT_NAME_INQ, |
| BTM_INQ_RMT_NAME_TIMEOUT, NULL) != BTM_CMD_STARTED) |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_FAILED; |
| else |
| return; |
| } |
| } |
| } |
| |
| /* The inquiry has finished so call the callback for the inquiry */ |
| p_inq_cb = p_inq->p_inq_cmpl_cb; |
| p_inq->state = BTM_INQ_INACTIVE_STATE; |
| p_inq->inq_active = BTM_INQUIRY_INACTIVE; |
| p_inq->p_inq_cmpl_cb = NULL; |
| |
| /* If we have a callback registered for inquiry complete, call it */ |
| if (p_inq_cb) |
| (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info); |
| |
| /* In some cases we can not get name of the device once but will be */ |
| /* able to do it next time. Until we have better solution we will */ |
| /* try to get name every time */ |
| for (p_cur = BTM_InqDbFirst(); p_cur; p_cur = BTM_InqDbNext (p_cur)) |
| { |
| if (p_cur->remote_name_state == BTM_INQ_RMT_NAME_FAILED) |
| p_cur->remote_name_state = BTM_INQ_RMT_NAME_EMPTY; |
| } |
| } |
| #endif /* BTM_INQ_GET_REMOTE_NAME == TRUE */ |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_inq_rmt_name_failed |
| ** |
| ** Description This function is if timeout expires while getting remote |
| ** name. This is done for devices that incorrectly do not |
| ** report operation failure |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_inq_rmt_name_failed (void) |
| { |
| BTM_TRACE_ERROR1 ("btm_inq_rmt_name_failed() remname_active=%d", btm_cb.btm_inq_vars.remname_active); |
| |
| if (btm_cb.btm_inq_vars.remname_active) |
| btm_process_remote_name (btm_cb.btm_inq_vars.remname_bda, NULL, 0, HCI_ERR_UNSPECIFIED); |
| else |
| btm_process_remote_name (NULL, NULL, 0, HCI_ERR_UNSPECIFIED); |
| |
| btm_sec_rmt_name_request_complete (NULL, NULL, HCI_ERR_UNSPECIFIED); |
| } |
| /******************************************************************************* |
| ** |
| ** Function btm_read_linq_tx_power_complete |
| ** |
| ** Description read inquiry tx power level complete callback function. |
| ** |
| ** Returns void |
| ** |
| *******************************************************************************/ |
| void btm_read_linq_tx_power_complete(UINT8 *p) |
| { |
| tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_txpwer_cmpl_cb; |
| tBTM_INQ_TXPWR_RESULTS results; |
| |
| btu_stop_timer (&btm_cb.devcb.txpwer_timer); |
| /* If there was a callback registered for read inq tx power, call it */ |
| btm_cb.devcb.p_txpwer_cmpl_cb = NULL; |
| |
| if (p_cb) |
| { |
| STREAM_TO_UINT8 (results.hci_status, p); |
| |
| if (results.hci_status == HCI_SUCCESS) |
| { |
| results.status = BTM_SUCCESS; |
| |
| STREAM_TO_UINT8 (results.tx_power, p); |
| BTM_TRACE_EVENT2 ("BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x", |
| results.tx_power, results.hci_status); |
| } |
| else |
| results.status = BTM_ERR_PROCESSING; |
| |
| (*p_cb)(&results); |
| } |
| |
| } |
| /******************************************************************************* |
| ** |
| ** Function BTM_WriteEIR |
| ** |
| ** Description This function is called to write EIR data to controller. |
| ** |
| ** Parameters p_buff - allocated HCI command buffer including extended |
| ** inquriry response |
| ** |
| ** Returns BTM_SUCCESS - if successful |
| ** BTM_MODE_UNSUPPORTED - if local device cannot support it |
| ** |
| *******************************************************************************/ |
| tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff ) |
| { |
| #if (BTM_EIR_SERVER_INCLUDED == TRUE) |
| if (HCI_EXT_INQ_RSP_SUPPORTED(btm_cb.devcb.local_features)) |
| { |
| BTM_TRACE_API0("Write Extended Inquiry Response to controller"); |
| btsnd_hcic_write_ext_inquiry_response (p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED); |
| return BTM_SUCCESS; |
| } |
| else |
| { |
| GKI_freebuf(p_buff); |
| return BTM_MODE_UNSUPPORTED; |
| } |
| #else |
| GKI_freebuf(p_buff); |
| return BTM_SUCCESS; |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_CheckEirData |
| ** |
| ** Description This function is called to get EIR data from significant part. |
| ** |
| ** Parameters p_eir - pointer of EIR significant part |
| ** type - finding EIR data type |
| ** p_length - return the length of EIR data not including type |
| ** |
| ** Returns pointer of EIR data |
| ** |
| *******************************************************************************/ |
| UINT8 *BTM_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length ) |
| { |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| UINT8 *p = p_eir; |
| UINT8 length; |
| UINT8 eir_type; |
| BTM_TRACE_API1("BTM_CheckEirData type=0x%02X", type); |
| |
| STREAM_TO_UINT8(length, p); |
| while( length && (p - p_eir <= HCI_EXT_INQ_RESPONSE_LEN)) |
| { |
| STREAM_TO_UINT8(eir_type, p); |
| if( eir_type == type ) |
| { |
| /* length doesn't include itself */ |
| *p_length = length - 1; /* minus the length of type */ |
| return p; |
| } |
| p += length - 1; /* skip the length of data */ |
| STREAM_TO_UINT8(length, p); |
| } |
| |
| *p_length = 0; |
| return NULL; |
| #else |
| return NULL; |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_convert_uuid_to_eir_service |
| ** |
| ** Description This function is called to get the bit position of UUID. |
| ** |
| ** Parameters uuid16 - UUID 16-bit |
| ** |
| ** Returns BTM EIR service ID if found |
| ** BTM_EIR_MAX_SERVICES - if not found |
| ** |
| *******************************************************************************/ |
| #if (( BTM_EIR_CLIENT_INCLUDED == TRUE )||( BTM_EIR_SERVER_INCLUDED == TRUE )) |
| static UINT8 btm_convert_uuid_to_eir_service( UINT16 uuid16 ) |
| { |
| UINT8 xx; |
| |
| for( xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++ ) |
| { |
| if( uuid16 == BTM_EIR_UUID_LKUP_TBL[xx]) |
| { |
| return xx; |
| } |
| } |
| return BTM_EIR_MAX_SERVICES; |
| } |
| #endif |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_HasEirService |
| ** |
| ** Description This function is called to know if UUID in bit map of UUID. |
| ** |
| ** Parameters p_eir_uuid - bit map of UUID list |
| ** uuid16 - UUID 16-bit |
| ** |
| ** Returns TRUE - if found |
| ** FALSE - if not found |
| ** |
| *******************************************************************************/ |
| BOOLEAN BTM_HasEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) |
| { |
| #if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE)) |
| UINT8 service_id; |
| |
| service_id = btm_convert_uuid_to_eir_service(uuid16); |
| if( service_id < BTM_EIR_MAX_SERVICES ) |
| return( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_id )); |
| else |
| return( FALSE ); |
| #else |
| return( FALSE ); |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_HasInquiryEirService |
| ** |
| ** Description This function is called to know if UUID in bit map of UUID list. |
| ** |
| ** Parameters p_results - inquiry results |
| ** uuid16 - UUID 16-bit |
| ** |
| ** Returns BTM_EIR_FOUND - if found |
| ** BTM_EIR_NOT_FOUND - if not found and it is complete list |
| ** BTM_EIR_UNKNOWN - if not found and it is not complete list |
| ** |
| *******************************************************************************/ |
| tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService( tBTM_INQ_RESULTS *p_results, UINT16 uuid16 ) |
| { |
| #if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE)) |
| if( BTM_HasEirService( p_results->eir_uuid, uuid16 )) |
| { |
| return BTM_EIR_FOUND; |
| } |
| else if( p_results->eir_complete_list ) |
| { |
| return BTM_EIR_NOT_FOUND; |
| } |
| else |
| return BTM_EIR_UNKNOWN; |
| #else |
| return BTM_EIR_UNKNOWN; |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_AddEirService |
| ** |
| ** Description This function is called to add a service in bit map of UUID list. |
| ** |
| ** Parameters p_eir_uuid - bit mask of UUID list for EIR |
| ** uuid16 - UUID 16-bit |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void BTM_AddEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) |
| { |
| #if ((BTM_EIR_SERVER_INCLUDED == TRUE)||(BTM_EIR_CLIENT_INCLUDED == TRUE)) |
| UINT8 service_id; |
| |
| service_id = btm_convert_uuid_to_eir_service(uuid16); |
| if( service_id < BTM_EIR_MAX_SERVICES ) |
| BTM_EIR_SET_SERVICE( p_eir_uuid, service_id ); |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_RemoveEirService |
| ** |
| ** Description This function is called to remove a service in bit map of UUID list. |
| ** |
| ** Parameters p_eir_uuid - bit mask of UUID list for EIR |
| ** uuid16 - UUID 16-bit |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void BTM_RemoveEirService( UINT32 *p_eir_uuid, UINT16 uuid16 ) |
| { |
| #if (BTM_EIR_SERVER_INCLUDED == TRUE) |
| UINT8 service_id; |
| |
| service_id = btm_convert_uuid_to_eir_service(uuid16); |
| if( service_id < BTM_EIR_MAX_SERVICES ) |
| BTM_EIR_CLR_SERVICE( p_eir_uuid, service_id ); |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_GetEirSupportedServices |
| ** |
| ** Description This function is called to get UUID list from bit map of UUID list. |
| ** |
| ** Parameters p_eir_uuid - bit mask of UUID list for EIR |
| ** p - reference of current pointer of EIR |
| ** max_num_uuid16 - max number of UUID can be written in EIR |
| ** num_uuid16 - number of UUID have been written in EIR |
| ** |
| ** Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max |
| ** BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise |
| ** |
| *******************************************************************************/ |
| UINT8 BTM_GetEirSupportedServices( UINT32 *p_eir_uuid, UINT8 **p, |
| UINT8 max_num_uuid16, UINT8 *p_num_uuid16) |
| { |
| #if (BTM_EIR_SERVER_INCLUDED == TRUE) |
| UINT8 service_index; |
| |
| *p_num_uuid16 = 0; |
| |
| for(service_index = 0; service_index < BTM_EIR_MAX_SERVICES; service_index++) |
| { |
| if( BTM_EIR_HAS_SERVICE( p_eir_uuid, service_index )) |
| { |
| if( *p_num_uuid16 < max_num_uuid16 ) |
| { |
| UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]); |
| (*p_num_uuid16)++; |
| } |
| /* if max number of UUIDs are stored and found one more */ |
| else |
| { |
| return BTM_EIR_MORE_16BITS_UUID_TYPE; |
| } |
| } |
| } |
| return BTM_EIR_COMPLETE_16BITS_UUID_TYPE; |
| #else |
| return BTM_EIR_COMPLETE_16BITS_UUID_TYPE; |
| #endif |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function BTM_GetEirUuidList |
| ** |
| ** Description This function parses EIR and returns UUID list. |
| ** |
| ** Parameters p_eir - EIR |
| ** uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128 |
| ** p_num_uuid - return number of UUID in found list |
| ** p_uuid_list - return UUID list |
| ** max_num_uuid - maximum number of UUID to be returned |
| ** |
| ** Returns 0 - if not found |
| ** BTM_EIR_COMPLETE_16BITS_UUID_TYPE |
| ** BTM_EIR_MORE_16BITS_UUID_TYPE |
| ** BTM_EIR_COMPLETE_32BITS_UUID_TYPE |
| ** BTM_EIR_MORE_32BITS_UUID_TYPE |
| ** BTM_EIR_COMPLETE_128BITS_UUID_TYPE |
| ** BTM_EIR_MORE_128BITS_UUID_TYPE |
| ** |
| *******************************************************************************/ |
| UINT8 BTM_GetEirUuidList( UINT8 *p_eir, UINT8 uuid_size, UINT8 *p_num_uuid, |
| UINT8 *p_uuid_list, UINT8 max_num_uuid) |
| { |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| UINT8 *p_uuid_data; |
| UINT8 type; |
| UINT8 yy, xx; |
| UINT16 *p_uuid16 = (UINT16 *)p_uuid_list; |
| UINT32 *p_uuid32 = (UINT32 *)p_uuid_list; |
| char buff[LEN_UUID_128 * 2 + 1]; |
| |
| p_uuid_data = btm_eir_get_uuid_list( p_eir, uuid_size, p_num_uuid, &type ); |
| if( p_uuid_data == NULL ) |
| { |
| return 0x00; |
| } |
| |
| if( *p_num_uuid > max_num_uuid ) |
| { |
| BTM_TRACE_WARNING2("BTM_GetEirUuidList number of uuid in EIR = %d, size of uuid list = %d", |
| *p_num_uuid, max_num_uuid ); |
| *p_num_uuid = max_num_uuid; |
| } |
| |
| BTM_TRACE_DEBUG2("BTM_GetEirUuidList type = %02X, number of uuid = %d", type, *p_num_uuid ); |
| |
| if( uuid_size == LEN_UUID_16 ) |
| { |
| for( yy = 0; yy < *p_num_uuid; yy++ ) |
| { |
| STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data); |
| BTM_TRACE_DEBUG1(" 0x%04X", *(p_uuid16 + yy)); |
| } |
| } |
| else if( uuid_size == LEN_UUID_32 ) |
| { |
| for( yy = 0; yy < *p_num_uuid; yy++ ) |
| { |
| STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data); |
| BTM_TRACE_DEBUG1(" 0x%08X", *(p_uuid32 + yy)); |
| } |
| } |
| else if( uuid_size == LEN_UUID_128 ) |
| { |
| for( yy = 0; yy < *p_num_uuid; yy++ ) |
| { |
| STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data); |
| for( xx = 0; xx < LEN_UUID_128; xx++ ) |
| sprintf(buff + xx*2, "%02X", *(p_uuid_list + yy * LEN_UUID_128 + xx)); |
| BTM_TRACE_DEBUG1(" 0x%s", buff); |
| } |
| } |
| |
| return type; |
| #else |
| *p_num_uuid = 0; |
| return 0x00; |
| #endif |
| } |
| |
| |
| #if (BTM_EIR_CLIENT_INCLUDED == TRUE) |
| /******************************************************************************* |
| ** |
| ** Function btm_eir_get_uuid_list |
| ** |
| ** Description This function searches UUID list in EIR. |
| ** |
| ** Parameters p_eir - address of EIR |
| ** uuid_size - size of UUID to find |
| ** p_num_uuid - number of UUIDs found |
| ** p_uuid_list_type - EIR data type |
| ** |
| ** Returns NULL - if UUID list with uuid_size is not found |
| ** beginning of UUID list in EIR - otherwise |
| ** |
| *******************************************************************************/ |
| static UINT8 *btm_eir_get_uuid_list( UINT8 *p_eir, UINT8 uuid_size, |
| UINT8 *p_num_uuid, UINT8 *p_uuid_list_type ) |
| { |
| UINT8 *p_uuid_data; |
| UINT8 complete_type, more_type; |
| UINT8 uuid_len; |
| |
| switch( uuid_size ) |
| { |
| case LEN_UUID_16: |
| complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; |
| more_type = BTM_EIR_MORE_16BITS_UUID_TYPE; |
| break; |
| case LEN_UUID_32: |
| complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; |
| more_type = BTM_EIR_MORE_32BITS_UUID_TYPE; |
| break; |
| case LEN_UUID_128: |
| complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; |
| more_type = BTM_EIR_MORE_128BITS_UUID_TYPE; |
| break; |
| default: |
| *p_num_uuid = 0; |
| return NULL; |
| break; |
| } |
| |
| p_uuid_data = BTM_CheckEirData( p_eir, complete_type, &uuid_len ); |
| if(p_uuid_data == NULL) |
| { |
| p_uuid_data = BTM_CheckEirData( p_eir, more_type, &uuid_len ); |
| *p_uuid_list_type = more_type; |
| } |
| else |
| { |
| *p_uuid_list_type = complete_type; |
| } |
| |
| *p_num_uuid = uuid_len / uuid_size; |
| return p_uuid_data; |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_convert_uuid_to_uuid16 |
| ** |
| ** Description This function converts UUID to UUID 16-bit. |
| ** |
| ** Parameters p_uuid - address of UUID |
| ** uuid_size - size of UUID |
| ** |
| ** Returns 0 - if UUID cannot be converted to UUID 16-bit |
| ** UUID 16-bit - otherwise |
| ** |
| *******************************************************************************/ |
| static UINT16 btm_convert_uuid_to_uuid16( UINT8 *p_uuid, UINT8 uuid_size ) |
| { |
| static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| UINT16 uuid16 = 0; |
| UINT32 uuid32; |
| BOOLEAN is_base_uuid; |
| UINT8 xx; |
| |
| switch (uuid_size) |
| { |
| case LEN_UUID_16: |
| STREAM_TO_UINT16 (uuid16, p_uuid); |
| break; |
| case LEN_UUID_32: |
| STREAM_TO_UINT32 (uuid32, p_uuid); |
| if (uuid32 < 0x10000) |
| uuid16 = (UINT16) uuid32; |
| break; |
| case LEN_UUID_128: |
| /* See if we can compress his UUID down to 16 or 32bit UUIDs */ |
| is_base_uuid = TRUE; |
| for (xx = 0; xx < LEN_UUID_128 - 4; xx++) |
| { |
| if (p_uuid[xx] != base_uuid[xx]) |
| { |
| is_base_uuid = FALSE; |
| break; |
| } |
| } |
| if (is_base_uuid) |
| { |
| if ((p_uuid[LEN_UUID_128 - 1] == 0) && (p_uuid[LEN_UUID_128 - 2] == 0)) |
| { |
| p_uuid += (LEN_UUID_128 - 4); |
| STREAM_TO_UINT16(uuid16, p_uuid); |
| } |
| } |
| break; |
| default: |
| BTM_TRACE_WARNING0("btm_convert_uuid_to_uuid16 invalid uuid size"); |
| break; |
| } |
| |
| return( uuid16); |
| } |
| |
| /******************************************************************************* |
| ** |
| ** Function btm_set_eir_uuid |
| ** |
| ** Description This function is called to store received UUID into inquiry result. |
| ** |
| ** Parameters p_eir - pointer of EIR significant part |
| ** p_results - pointer of inquiry result |
| ** |
| ** Returns None |
| ** |
| *******************************************************************************/ |
| void btm_set_eir_uuid( UINT8 *p_eir, tBTM_INQ_RESULTS *p_results ) |
| { |
| UINT8 *p_uuid_data; |
| UINT8 num_uuid; |
| UINT16 uuid16; |
| UINT8 yy; |
| UINT8 type = BTM_EIR_MORE_16BITS_UUID_TYPE; |
| |
| p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_16, &num_uuid, &type ); |
| |
| if(type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE) |
| { |
| p_results->eir_complete_list = TRUE; |
| } |
| else |
| { |
| p_results->eir_complete_list = FALSE; |
| } |
| |
| BTM_TRACE_API1("btm_set_eir_uuid eir_complete_list=0x%02X", p_results->eir_complete_list); |
| |
| if( p_uuid_data ) |
| { |
| for( yy = 0; yy < num_uuid; yy++ ) |
| { |
| STREAM_TO_UINT16(uuid16, p_uuid_data); |
| BTM_AddEirService( p_results->eir_uuid, uuid16 ); |
| } |
| } |
| |
| p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_32, &num_uuid, &type ); |
| if( p_uuid_data ) |
| { |
| for( yy = 0; yy < num_uuid; yy++ ) |
| { |
| uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_32 ); |
| p_uuid_data += LEN_UUID_32; |
| if( uuid16 ) |
| BTM_AddEirService( p_results->eir_uuid, uuid16 ); |
| } |
| } |
| |
| p_uuid_data = btm_eir_get_uuid_list( p_eir, LEN_UUID_128, &num_uuid, &type ); |
| if( p_uuid_data ) |
| { |
| for( yy = 0; yy < num_uuid; yy++ ) |
| { |
| uuid16 = btm_convert_uuid_to_uuid16( p_uuid_data, LEN_UUID_128 ); |
| p_uuid_data += LEN_UUID_128; |
| if( uuid16 ) |
| BTM_AddEirService( p_results->eir_uuid, uuid16 ); |
| } |
| } |
| |
| BTM_TRACE_DEBUG2("btm_set_eir_uuid eir_uuid=0x%08X %08X", |
| p_results->eir_uuid[1], p_results->eir_uuid[0] ); |
| } |
| #endif |
| |