diff options
Diffstat (limited to 'stack/btm/btm_inq.c')
-rw-r--r-- | stack/btm/btm_inq.c | 3233 |
1 files changed, 3233 insertions, 0 deletions
diff --git a/stack/btm/btm_inq.c b/stack/btm/btm_inq.c new file mode 100644 index 0000000..f42cdc1 --- /dev/null +++ b/stack/btm/btm_inq.c @@ -0,0 +1,3233 @@ +/***************************************************************************** +** +** Name: btm_inq.c +** +** Description: 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. +** +** NOTE: Only ONE inquiry is allowed to run at a time +** (including periodic inquiries); +** +** +** Copyright (c) 1999-2012, Broadcom Corp., All Rights Reserved. +** Broadcom Bluetooth Core. Proprietary and confidential. +******************************************************************************/ + +#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 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) + 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_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 + |