1/****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#define LOG_TAG "bt_btif_sock_sdp" 20 21#include <stdint.h> 22#include <stdbool.h> 23#include <string.h> 24#include <sys/types.h> 25#include <sys/socket.h> 26#include <errno.h> 27 28#include <hardware/bluetooth.h> 29#include <hardware/bt_sock.h> 30 31#include "btif_common.h" 32#include "btif_util.h" 33#include "btif_sock_util.h" 34#include "bta_api.h" 35#include "bt_target.h" 36#include "gki.h" 37#include "hcimsgs.h" 38#include "sdp_api.h" 39#include "btu.h" 40#include "btm_api.h" 41#include "btm_int.h" 42#include "btif_sock_sdp.h" 43#include "utl.h" 44#include "../bta/pb/bta_pbs_int.h" 45#include "../include/bta_op_api.h" 46#include "bta_jv_api.h" 47 48// This module provides an abstraction on top of the lower-level SDP database 49// code for registration and discovery of various bluetooth sockets. 50// 51// This code also provides for on-demand registration of "pre-registered" 52// services as a backwards compatibility function to third-party applications 53// expecting a bluez stack. 54 55// Realm Character Set -- 0 is ASCII 56#define BTA_PBS_REALM_CHARSET 0 57 58// Specifies whether or not client's user id is required during obex 59// authentication 60#define BTA_PBS_USERID_REQ FALSE 61 62static const tBTA_PBS_CFG bta_pbs_cfg = { 63 BTA_PBS_REALM_CHARSET, // realm_charset: Server only 64 BTA_PBS_USERID_REQ, // userid_req: Server only 65 (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), // supported_features 66 BTA_PBS_REPOSIT_LOCAL, // supported_repositories 67}; 68 69// object format lookup table 70#define OBEX_PUSH_NUM_FORMATS 7 71 72static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = { 73 BTA_OP_VCARD21_FMT, 74 BTA_OP_VCARD30_FMT, 75 BTA_OP_VCAL_FMT, 76 BTA_OP_ICAL_FMT, 77 BTA_OP_VNOTE_FMT, 78 BTA_OP_VMSG_FMT, 79 BTA_OP_OTHER_FMT 80}; 81 82// TODO(jtgans): Figure out if we actually need this define. This is ifndef 83// defined in bt_target.h, but nowhere else, so right now, unless something 84// overrides this before bt_target.h sets it, it will always be bt_target.h's 85// version. 86#ifndef BTUI_OPS_FORMATS 87#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK \ 88 | BTA_OP_VCARD30_MASK \ 89 | BTA_OP_VCAL_MASK \ 90 | BTA_OP_ICAL_MASK \ 91 | BTA_OP_VNOTE_MASK \ 92 | BTA_OP_VMSG_MASK \ 93 | BTA_OP_ANY_MASK) 94#endif 95 96 97 98#define RESERVED_SCN_PBS 19 99#define RESERVED_SCN_OPS 12 100 101#define UUID_MAX_LENGTH 16 102#define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH) 103 104// Adds a protocol list and service name (if provided) to an SDP record given by 105// |sdp_handle|, and marks it as browseable. This is a shortcut for defining a 106// set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If 107// |with_obex| is |TRUE|, then an additional OBEX protocol UUID will be included 108// at the end of the protocol list. 109// 110// Returns TRUE if successful, otherwise FALSE. 111static bool create_base_record(const uint32_t sdp_handle, const char *name, 112 const uint16_t channel, const bool with_obex) { 113 APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d", 114 channel, name, with_obex); 115 116 // Setup the protocol list and add it. 117 tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS]; 118 int num_proto_elements = with_obex ? 3 : 2; 119 120 memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM)); 121 122 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 123 proto_list[0].num_params = 0; 124 proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; 125 proto_list[1].num_params = 1; 126 proto_list[1].params[0] = channel; 127 128 if (with_obex == TRUE) { 129 proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX; 130 proto_list[2].num_params = 0; 131 } 132 133 char *stage = "protocol_list"; 134 if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list)) 135 goto error; 136 137 // Add the name to the SDP record. 138 if (name[0] != '\0') { 139 stage = "service_name"; 140 if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, 141 TEXT_STR_DESC_TYPE, (uint32_t)(strlen(name) + 1), 142 (uint8_t *)name)) 143 goto error; 144 } 145 146 // Mark the service as browseable. 147 uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; 148 stage = "browseable"; 149 if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list)) 150 goto error; 151 152 APPL_TRACE_DEBUG("create_base_record: successfully created base service " 153 "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d", 154 sdp_handle, channel, name, with_obex); 155 return TRUE; 156 157error: 158 APPL_TRACE_ERROR("create_base_record: failed to create base service " 159 "record, stage: %s, scn: %d, name: %s, with_obex: %d", 160 stage, channel, name, with_obex); 161 return FALSE; 162} 163 164// Registers a service with the given |name|, |uuid|, and |channel| in the SDP 165// database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service 166// class sequence. 167static int add_sdp_by_uuid(const char *name, const uint8_t *uuid, 168 const uint16_t channel) { 169 APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name); 170 171 uint32_t handle = SDP_CreateRecord(); 172 if (handle == 0) { 173 APPL_TRACE_ERROR("add_sdp_by_uuid: failed to create sdp record, " 174 "scn: %d, service_name: %s", channel, name); 175 return 0; 176 } 177 178 // Create the base SDP record. 179 char *stage = "create_base_record"; 180 if (!create_base_record(handle, name, channel, FALSE /* with_obex */)) 181 goto error; 182 183 // Convert the |uuid| into a big-endian representation and add it as a 184 // sequence. 185 uint8_t type = UUID_DESC_TYPE; 186 uint8_t type_len = UUID_MAX_LENGTH; 187 uint8_t type_buf[48]; 188 // Store the address of type buf in a pointer on the stack, so we can pass 189 // a double pointer to SDP_AddSequence 190 uint8_t *type_buf_ptr = type_buf; 191 192 // Do the conversion to big-endian -- tmp is only used to iterate through the 193 // UUID array in the macro and serves no other purpose as the conversion 194 // macros are not hygenic. 195 { 196 uint8_t *tmp = type_buf; 197 ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH); 198 } 199 200 stage = "service_class_sequence"; 201 if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST, 202 1, &type, &type_len, &type_buf_ptr)) 203 goto error; 204 205 206 APPL_TRACE_DEBUG("add_sdp_by_uuid: service registered successfully, " 207 "service_name: %s, handle: 0x%08x", name, handle); 208 return handle; 209 210error: 211 SDP_DeleteRecord(handle); 212 APPL_TRACE_ERROR("add_sdp_by_uuid: failed to register service " 213 "stage: %s, service_name: %s", stage, name); 214 return 0; 215} 216 217// Registers a service with the given |name| and |channel| in the SDP 218// database as a PBAP protocol. 219static int add_pbap_sdp(const char *name, const int channel) { 220 APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name); 221 222 uint32_t handle = SDP_CreateRecord(); 223 if (handle == 0) { 224 APPL_TRACE_ERROR("add_pbap_sdp: failed to create sdp record, " 225 "service_name: %s", name); 226 return 0; 227 } 228 229 // Create the base SDP record. 230 char *stage = "create_base_record"; 231 if (!create_base_record(handle, name, channel, TRUE /* with_obex */)) 232 goto error; 233 234 // Add service class 235 uint16_t service = UUID_SERVCLASS_PBAP_PSE; 236 stage = "service_class"; 237 if (!SDP_AddServiceClassIdList(handle, 1, &service)) 238 goto error; 239 240 // Add in the phone access descriptor 241 stage = "profile_descriptor_list"; 242 if (!SDP_AddProfileDescriptorList(handle, 243 UUID_SERVCLASS_PHONE_ACCESS, 244 BTA_PBS_DEFAULT_VERSION)) 245 goto error; 246 247 // Set up our supported repositories 248 stage = "supported_repositories"; 249 if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE, 250 1, (uint8_t*)&bta_pbs_cfg.supported_repositories)) 251 goto error; 252 253 // Notify the system that we've got a new service class UUID. 254 bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE); 255 APPL_TRACE_DEBUG("add_pbap_sdp: service registered successfully, " 256 "service_name: %s, handle: 0x%08x", name, handle); 257 258 return handle; 259 260error: 261 SDP_DeleteRecord(handle); 262 APPL_TRACE_ERROR("add_pbap_sdp: failed to register PBAP service, stage: %s, " 263 "service_name: %s", stage, name); 264 return 0; 265} 266// Registers a service with the given |name| and |channel| as an OBEX Push 267// protocol. 268static int add_ops_sdp(const char *name, const int channel) { 269 APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name); 270 271 uint32_t handle = SDP_CreateRecord(); 272 if (handle == 0) { 273 APPL_TRACE_ERROR("add_ops_sdp: failed to create sdp record, " 274 "service_name: %s", name); 275 return 0; 276 } 277 278 // Create the base SDP record. 279 char *stage = "create_base_record"; 280 if (!create_base_record(handle, name, channel, TRUE /* with_obex */)) 281 goto error; 282 283 // Add service class. 284 stage = "service_class"; 285 uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH; 286 if (!SDP_AddServiceClassIdList(handle, 1, &service)) 287 goto error; 288 289 // Add the OBEX push profile descriptor. 290 stage = "profile_descriptor_list"; 291 if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH, 292 0x0100)) 293 goto error; 294 295 // Add sequence for supported types. 296 uint8_t desc_type[OBEX_PUSH_NUM_FORMATS]; 297 uint8_t type_len[OBEX_PUSH_NUM_FORMATS]; 298 uint8_t *type_value[OBEX_PUSH_NUM_FORMATS]; 299 uint8_t j = 0; 300 301 for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) { 302 if ((BTUI_OPS_FORMATS >> i) & 1) { 303 type_value[j] = (uint8_t*)(&bta_ops_obj_fmt[i]); 304 desc_type[j] = UINT_DESC_TYPE; 305 type_len[j++] = 1; 306 } 307 } 308 309 stage = "supported_types"; 310 if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST, 311 j, desc_type, type_len, type_value)) 312 goto error; 313 314 // Set class of device. 315 tBTA_UTL_COD cod; 316 cod.service = BTM_COD_SERVICE_OBJ_TRANSFER; 317 stage = "class_of_device"; 318 if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS)) 319 goto error; 320 321 // Notify the system that we've got a new service class UUID. 322 bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH); 323 APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, " 324 "service_name: %s, handle 0x%08x)", name, handle); 325 326 return handle; 327 328error: 329 SDP_DeleteRecord(handle); 330 APPL_TRACE_ERROR("add_ops_sdp: failed to register OPS service, " 331 "stage: %s, service_name: %s", stage, name); 332 return 0; 333} 334 335// Registers a service with the given |name| and |channel| as a serial port 336// profile protocol. 337static int add_spp_sdp(const char *name, const int channel) { 338 APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name); 339 340 int handle = SDP_CreateRecord(); 341 if (handle == 0) { 342 APPL_TRACE_ERROR("add_spp_sdp: failed to create sdp record, " 343 "service_name: %s", name); 344 return 0; 345 } 346 347 // Create the base SDP record. 348 char *stage = "create_base_record"; 349 if (!create_base_record(handle, name, channel, FALSE /* with_obex */)) 350 goto error; 351 352 uint16_t service = UUID_SERVCLASS_SERIAL_PORT; 353 stage = "service_class"; 354 if (!SDP_AddServiceClassIdList(handle, 1, &service)) 355 goto error; 356 357 APPL_TRACE_DEBUG("add_spp_sdp: service registered successfully, " 358 "service_name: %s, handle 0x%08x)", name, handle); 359 360 return handle; 361 362error: 363 SDP_DeleteRecord(handle); 364 APPL_TRACE_ERROR("add_spp_sdp: failed to register SPP service, " 365 "stage: %s, service_name: %s", stage, name); 366 return 0; 367} 368 369// Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and 370// |channel|. This function attempts to identify the type of the service based 371// upon its |uuid|, and will override the |channel| with a reserved channel 372// number if the |uuid| matches one of the preregistered bluez SDP records. 373static int add_rfc_sdp_by_uuid(const char *name, const uint8_t *uuid, 374 const int channel) { 375 APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name, 376 channel); 377 378 /* 379 * Bluetooth Socket API relies on having preregistered bluez sdp records for 380 * HSAG, HFAG, OPP & PBAP that are mapped to rc chan 10, 11,12 & 19. Today 381 * HSAG and HFAG is routed to BRCM AG and are not using BT socket API so for 382 * now we will need to support OPP and PBAP to enable 3rd party developer apps 383 * running on BRCM Android. 384 * 385 * To do this we will check the UUID for the requested service and mimic the 386 * SDP records of bluez upon reception. See functions add_opush() and 387 * add_pbap() in sdptool.c for actual records. 388 */ 389 390 int final_channel = get_reserved_rfc_channel(uuid); 391 392 if (final_channel == -1) { 393 final_channel = channel; 394 } 395 396 int handle = 0; 397 398 if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) { 399 handle = add_ops_sdp(name, final_channel); 400 } else if (UUID_MATCHES(UUID_PBAP_PSE,uuid)) { 401 // PBAP Server is always channel 19 402 handle = add_pbap_sdp(name, final_channel); 403 } else if (UUID_MATCHES(UUID_SPP, uuid)) { 404 handle = add_spp_sdp(name, final_channel); 405 } else if (UUID_MATCHES(UUID_MAP_MAS,uuid)) { 406 // Record created by new SDP create record interface 407 handle = 0xff; 408 } else { 409 handle = add_sdp_by_uuid(name, uuid, final_channel); 410 } 411 412 return handle; 413} 414 415bool is_reserved_rfc_channel(const int channel) { 416 switch(channel) { 417 case RESERVED_SCN_PBS: 418 case RESERVED_SCN_OPS: 419 return TRUE; 420 } 421 422 return FALSE; 423} 424 425int get_reserved_rfc_channel(const uint8_t *uuid) { 426 if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) { 427 return RESERVED_SCN_PBS; 428 } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) { 429 return RESERVED_SCN_OPS; 430 } 431 432 return -1; 433} 434 435// Adds an SDP record to the SDP database using the given |name|, |uuid|, and 436// |channel|. Note that if the |uuid| is empty, the |uuid| will be set based 437// upon the |channel| passed in. 438int add_rfc_sdp_rec(const char *name, const uint8_t *uuid, const int channel) { 439 if (is_uuid_empty(uuid)) { 440 switch(channel) { 441 case RESERVED_SCN_PBS: // PBAP Reserved port 442 uuid = UUID_PBAP_PSE; 443 break; 444 445 case RESERVED_SCN_OPS: 446 uuid = UUID_OBEX_OBJECT_PUSH; 447 break; 448 449 default: 450 uuid = UUID_SPP; 451 break; 452 } 453 } 454 455 return add_rfc_sdp_by_uuid(name, uuid, channel); 456} 457 458// Deletes an SDP record with the given |handle|. 459void del_rfc_sdp_rec(int handle) { 460 APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle); 461 462 if ((handle != -1) && (handle != 0)) 463 BTA_JvDeleteRecord(handle); 464} 465