diff options
Diffstat (limited to 'btif/src/btif_sock_sdp.c')
-rw-r--r-- | btif/src/btif_sock_sdp.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/btif/src/btif_sock_sdp.c b/btif/src/btif_sock_sdp.c new file mode 100644 index 0000000..cf55e8a --- /dev/null +++ b/btif/src/btif_sock_sdp.c @@ -0,0 +1,443 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/************************************************************************************ + * + * Filename: btif_hf.c + * + * Description: Handsfree Profile Bluetooth Interface + * + * + ***********************************************************************************/ + +#include <hardware/bluetooth.h> +#include <hardware/bt_sock.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#define LOG_TAG "BTIF_SOCK_SDP" +#include "btif_common.h" +#include "btif_util.h" + +#include "bd.h" + +#include "bta_api.h" + + +#include "bt_target.h" +#include "gki.h" +#include "hcimsgs.h" +#include "sdp_api.h" +#include "btu.h" +#include "btm_api.h" +#include "btm_int.h" +#include "btif_sock_sdp.h" +#include "utl.h" +#include "../bta/pb/bta_pbs_int.h" +#include "../include/bta_op_api.h" +#include <cutils/log.h> + +#define RESERVED_SCN_PBS 19 +#define RESERVED_SCN_OPS 12 + +#define UUID_MAX_LENGTH 16 + + +#define IS_UUID(u1,u2) !memcmp(u1,u2,UUID_MAX_LENGTH) + + +#define BTM_NUM_PROTO_ELEMS 2 +static int add_sdp_by_uuid(const char *name, const uint8_t *service_uuid, UINT16 channel) +{ + + UINT32 btm_sdp_handle; + + tSDP_PROTOCOL_ELEM proto_elem_list[BTM_NUM_PROTO_ELEMS]; + + /* register the service */ + if ((btm_sdp_handle = SDP_CreateRecord()) != FALSE) + { + /*** Fill out the protocol element sequence for SDP ***/ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 0; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + proto_elem_list[1].num_params = 1; + + proto_elem_list[1].params[0] = channel; + + if (SDP_AddProtocolList(btm_sdp_handle, BTM_NUM_PROTO_ELEMS, + proto_elem_list)) + { + UINT8 buff[48]; + UINT8 *p, *type_buf[1]; + UINT8 type[1], type_len[1]; + p = type_buf[0] = buff; + type[0] = UUID_DESC_TYPE; + +// UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES); + ARRAY_TO_BE_STREAM (p, service_uuid, 16); + type_len[0] = 16; + if( SDP_AddSequence(btm_sdp_handle, (UINT16) ATTR_ID_SERVICE_CLASS_ID_LIST, + 1, type, type_len, type_buf) ) +// if (SDP_AddServiceClassIdList(btm_sdp_handle, 1, &service_uuid)) + { + if ((SDP_AddAttribute(btm_sdp_handle, ATTR_ID_SERVICE_NAME, + TEXT_STR_DESC_TYPE, (UINT32)(strlen(name)+1), + (UINT8 *)name)) ) + { + UINT16 list[1]; + + /* Make the service browseable */ + list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + if ((SDP_AddUuidSequence (btm_sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, + 1, list)) ) + + return btm_sdp_handle; + } + } + } + } + + return 0; +} + + +/* Realm Character Set */ +#define BTA_PBS_REALM_CHARSET 0 /* ASCII */ + +/* Specifies whether or not client's user id is required during obex authentication */ +#define BTA_PBS_USERID_REQ FALSE +extern const tBTA_PBS_CFG bta_pbs_cfg; +const tBTA_PBS_CFG bta_pbs_cfg = +{ + BTA_PBS_REALM_CHARSET, /* Server only */ + BTA_PBS_USERID_REQ, /* Server only */ + (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), + BTA_PBS_REPOSIT_LOCAL, +}; + +static int add_pbap_sdp(const char* p_service_name, int scn) +{ + + tSDP_PROTOCOL_ELEM protoList [3]; + UINT16 pbs_service = UUID_SERVCLASS_PBAP_PSE; + UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + BOOLEAN status = FALSE; + UINT32 sdp_handle = 0; + tBTA_PBS_CFG *p_bta_pbs_cfg = (tBTA_PBS_CFG *)&bta_pbs_cfg; + + APPL_TRACE_DEBUG2("scn %d, service name %s", scn, p_service_name); + + if ((sdp_handle = SDP_CreateRecord()) == 0) + { + APPL_TRACE_ERROR0("PBS SDP: Unable to register PBS Service"); + return sdp_handle; + } + + /* add service class */ + if (SDP_AddServiceClassIdList(sdp_handle, 1, &pbs_service)) + { + memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) ); + /* add protocol list, including RFCOMM scn */ + protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + protoList[0].num_params = 0; + protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + protoList[1].num_params = 1; + protoList[1].params[0] = scn; + protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX; + protoList[2].num_params = 0; + + if (SDP_AddProtocolList(sdp_handle, 3, protoList)) + { + status = TRUE; /* All mandatory fields were successful */ + + /* optional: if name is not "", add a name entry */ + if (*p_service_name != '\0') + SDP_AddAttribute(sdp_handle, + (UINT16)ATTR_ID_SERVICE_NAME, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name) + 1), + (UINT8 *)p_service_name); + + /* Add in the Bluetooth Profile Descriptor List */ + SDP_AddProfileDescriptorList(sdp_handle, + UUID_SERVCLASS_PHONE_ACCESS, + BTA_PBS_DEFAULT_VERSION); + + } /* end of setting mandatory protocol list */ + } /* end of setting mandatory service class */ + + /* add supported feature and repositories */ + if (status) + { + SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_features); + SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE, + (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_repositories); + + /* Make the service browseable */ + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse); + } + + if (!status) + { + SDP_DeleteRecord(sdp_handle); + sdp_handle = 0; + APPL_TRACE_ERROR0("bta_pbs_sdp_register FAILED"); + } + else + { + bta_sys_add_uuid(pbs_service); /* UUID_SERVCLASS_PBAP_PSE */ + APPL_TRACE_DEBUG1("PBS: SDP Registered (handle 0x%08x)", sdp_handle); + } + + return sdp_handle; +} + + +/* object format lookup table */ +static const tBTA_OP_FMT bta_ops_obj_fmt[] = +{ + BTA_OP_VCARD21_FMT, + BTA_OP_VCARD30_FMT, + BTA_OP_VCAL_FMT, + BTA_OP_ICAL_FMT, + BTA_OP_VNOTE_FMT, + BTA_OP_VMSG_FMT, + BTA_OP_OTHER_FMT +}; + +#define BTA_OPS_NUM_FMTS 7 +#define BTA_OPS_PROTOCOL_COUNT 3 + +#ifndef BTUI_OPS_FORMATS +#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | \ + BTA_OP_VCAL_MASK | BTA_OP_ICAL_MASK | \ + BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | \ + BTA_OP_ANY_MASK ) +#endif + +static int add_ops_sdp(const char *p_service_name,int scn) +{ + + + tSDP_PROTOCOL_ELEM protoList [BTA_OPS_PROTOCOL_COUNT]; + UINT16 servclass = UUID_SERVCLASS_OBEX_OBJECT_PUSH; + int i, j; + tBTA_UTL_COD cod; + UINT8 desc_type[BTA_OPS_NUM_FMTS]; + UINT8 type_len[BTA_OPS_NUM_FMTS]; + UINT8 *type_value[BTA_OPS_NUM_FMTS]; + UINT16 browse; + UINT32 sdp_handle; + tBTA_OP_FMT_MASK formats = BTUI_OPS_FORMATS; + + APPL_TRACE_DEBUG2("scn %d, service name %s", scn, p_service_name); + + sdp_handle = SDP_CreateRecord(); + + /* add service class */ + if (SDP_AddServiceClassIdList(sdp_handle, 1, &servclass)) + { + /* add protocol list, including RFCOMM scn */ + protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + protoList[0].num_params = 0; + protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + protoList[1].num_params = 1; + protoList[1].params[0] = scn; + protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX; + protoList[2].num_params = 0; + + if (SDP_AddProtocolList(sdp_handle, BTA_OPS_PROTOCOL_COUNT, protoList)) + { + SDP_AddAttribute(sdp_handle, + (UINT16)ATTR_ID_SERVICE_NAME, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name) + 1), + (UINT8 *)p_service_name); + + SDP_AddProfileDescriptorList(sdp_handle, + UUID_SERVCLASS_OBEX_OBJECT_PUSH, + 0x0100); + } + } + + /* Make the service browseable */ + browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse); + + /* add sequence for supported types */ + for (i = 0, j = 0; i < BTA_OPS_NUM_FMTS; i++) + { + if ((formats >> i) & 1) + { + type_value[j] = (UINT8 *) &bta_ops_obj_fmt[i]; + desc_type[j] = UINT_DESC_TYPE; + type_len[j++] = 1; + } + } + + SDP_AddSequence(sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST, + (UINT8) j, desc_type, type_len, type_value); + + /* set class of device */ + cod.service = BTM_COD_SERVICE_OBJ_TRANSFER; + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + + bta_sys_add_uuid(servclass); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */ + + return sdp_handle; +} +#define SPP_NUM_PROTO_ELEMS 2 +static int add_spp_sdp(const char *service_name, int scn) +{ + UINT16 serviceclassid = UUID_SERVCLASS_SERIAL_PORT; + tSDP_PROTOCOL_ELEM proto_elem_list[SPP_NUM_PROTO_ELEMS]; + int sdp_handle; + + APPL_TRACE_DEBUG2("scn %d, service name %s", scn, service_name); + + /* register the service */ + if ((sdp_handle = SDP_CreateRecord()) != FALSE) + { + /*** Fill out the protocol element sequence for SDP ***/ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 0; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + proto_elem_list[1].num_params = 1; + + proto_elem_list[1].params[0] = scn; + + if (SDP_AddProtocolList(sdp_handle, SPP_NUM_PROTO_ELEMS, proto_elem_list)) + { + if (SDP_AddServiceClassIdList(sdp_handle, 1, &serviceclassid)) + { + if ((SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, + TEXT_STR_DESC_TYPE, (UINT32)(strlen(service_name)+1), + (UINT8 *)service_name))) + { + UINT16 list[1]; + /* Make the service browseable */ + list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, + 1, list); + } + } + } + } + return sdp_handle; +} + + + +static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid, int scn) +{ + int handle = 0; + + APPL_TRACE_DEBUG2("name:%s, scn:%d", name, scn); + + /* + Bluetooth Socket API relies on having preregistered bluez sdp records for HSAG, HFAG, OPP & PBAP + that are mapped to rc chan 10, 11,12 & 19. Today HSAG and HFAG is routed to BRCM AG and are not + using BT socket API so for now we will need to support OPP and PBAP to enable 3rd party developer + apps running on BRCM Android. + + To do this we will check the UUID for the requested service and mimic the SDP records of bluez + upon reception. See functions add_opush() and add_pbap() in sdptool.c for actual records + */ + + /* special handling for preregistered bluez services (OPP, PBAP) that we need to mimic */ + + int final_scn = get_reserved_rfc_channel(uuid); + if (final_scn == -1) + { + final_scn=scn; + } + if (IS_UUID(UUID_OBEX_OBJECT_PUSH,uuid)) + { + handle = add_ops_sdp(name,final_scn); + } + else if (IS_UUID(UUID_PBAP_PSE,uuid)) + { + handle = add_pbap_sdp(name, final_scn); //PBAP Server is always 19 + } + else if (IS_UUID(UUID_SPP, uuid)) + { + handle = add_spp_sdp(name, final_scn); + } + else + { + handle = add_sdp_by_uuid(name, uuid, final_scn); + } + return handle; +} + +BOOLEAN is_reserved_rfc_channel(int scn) +{ + switch(scn) + { + case RESERVED_SCN_PBS: + case RESERVED_SCN_OPS: + return TRUE; + } + return FALSE; +} + + +int get_reserved_rfc_channel (const uint8_t* uuid) +{ + if (IS_UUID(UUID_PBAP_PSE,uuid)) + { + return RESERVED_SCN_PBS; + } + else if (IS_UUID(UUID_OBEX_OBJECT_PUSH,uuid)) + { + return RESERVED_SCN_OPS; + } + return -1; +} + +int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn) +{ + int sdp_handle = 0; + if(is_uuid_empty(uuid)) + { + switch(scn) + { + case RESERVED_SCN_PBS: // PBAP Reserved port + uuid = UUID_PBAP_PSE; + break; + case RESERVED_SCN_OPS: + uuid = UUID_OBEX_OBJECT_PUSH; + break; + default: + uuid = UUID_SPP; + break; + } + } + sdp_handle = add_rfc_sdp_by_uuid(name, uuid, scn); + return sdp_handle; +} + +void del_rfc_sdp_rec(int handle) +{ + if(handle != -1 && handle != 0) + SDP_DeleteRecord( handle ); +} + |