1 /******************************************************************************
3 * Copyright (C) 2014 Google, Inc.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 #define LOG_TAG "bt_btif_sock_sdp"
24 #include <sys/types.h>
25 #include <sys/socket.h>
28 #include <hardware/bluetooth.h>
29 #include <hardware/bt_sock.h>
31 #include "btif_common.h"
32 #include "btif_util.h"
34 #include "bt_target.h"
41 #include "btif_sock_sdp.h"
43 #include "../bta/pb/bta_pbs_int.h"
44 #include "../include/bta_op_api.h"
45 #include "bta_jv_api.h"
47 // This module provides an abstraction on top of the lower-level SDP database
48 // code for registration and discovery of various bluetooth sockets.
50 // This code also provides for on-demand registration of "pre-registered"
51 // services as a backwards compatibility function to third-party applications
52 // expecting a bluez stack.
54 // Realm Character Set -- 0 is ASCII
55 #define BTA_PBS_REALM_CHARSET 0
57 // Specifies whether or not client's user id is required during obex
59 #define BTA_PBS_USERID_REQ FALSE
61 static const tBTA_PBS_CFG bta_pbs_cfg = {
62 BTA_PBS_REALM_CHARSET, // realm_charset: Server only
63 BTA_PBS_USERID_REQ, // userid_req: Server only
64 (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), // supported_features
65 BTA_PBS_REPOSIT_LOCAL, // supported_repositories
68 // object format lookup table
69 #define OBEX_PUSH_NUM_FORMATS 7
71 static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
81 // TODO(jtgans): Figure out if we actually need this define. This is ifndef
82 // defined in bt_target.h, but nowhere else, so right now, unless something
83 // overrides this before bt_target.h sets it, it will always be bt_target.h's
85 #ifndef BTUI_OPS_FORMATS
86 #define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK \
87 | BTA_OP_VCARD30_MASK \
96 * This is horrible design - to reserve channel ID's and use them to magically
97 * link a channel number to a hard coded SDP entry.
99 * TODO: expose a prober SDP API, to avoid hacks like this, and make it possible
100 * to set useful names for the ServiceName
102 #define BTA_MAP_MSG_TYPE_EMAIL 0x01
103 #define BTA_MAP_MSG_TYPE_SMS_GSM 0x02
104 #define BTA_MAP_MSG_TYPE_SMS_CDMA 0x04
105 #define BTA_MAP_MSG_TYPE_MMS 0x08
107 #define BTA_MAP_MAS_ID_SMSMMS 0
108 #define BTA_MAP_MAS_ID_EMAIL 1
111 #define BTA_MAP_DEFAULT_VERSION 0x0101
114 uint8_t mas_id; // the MAS instance id
115 const char *service_name; // Description of the MAS instance
116 uint8_t supported_message_types; // Server supported message types - SMS/MMS/EMAIL
119 const tBTA_MAP_CFG bta_map_cfg_sms = {
120 BTA_MAP_MAS_ID_SMSMMS,
122 BTA_MAP_MSG_TYPE_SMS_GSM | BTA_MAP_MSG_TYPE_SMS_CDMA
125 #define RESERVED_SCN_PBS 19
126 #define RESERVED_SCN_OPS 12
128 #define UUID_MAX_LENGTH 16
129 #define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
131 // Adds a protocol list and service name (if provided) to an SDP record given by
132 // |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
133 // set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If
134 // |with_obex| is |TRUE|, then an additional OBEX protocol UUID will be included
135 // at the end of the protocol list.
137 // Returns TRUE if successful, otherwise FALSE.
138 static bool create_base_record(const uint32_t sdp_handle, const char *name,
139 const uint16_t channel, const bool with_obex) {
140 APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
141 channel, name, with_obex);
143 // Setup the protocol list and add it.
144 tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
145 int num_proto_elements = with_obex ? 3 : 2;
147 memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
149 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
150 proto_list[0].num_params = 0;
151 proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
152 proto_list[1].num_params = 1;
153 proto_list[1].params[0] = channel;
155 if (with_obex == TRUE) {
156 proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
157 proto_list[2].num_params = 0;
160 char *stage = "protocol_list";
161 if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list))
164 // Add the name to the SDP record.
165 if (name[0] != '\0') {
166 stage = "service_name";
167 if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME,
168 TEXT_STR_DESC_TYPE, (uint32_t)(strlen(name) + 1),
173 // Mark the service as browseable.
174 uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
175 stage = "browseable";
176 if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list))
179 APPL_TRACE_DEBUG("create_base_record: successfully created base service "
180 "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
181 sdp_handle, channel, name, with_obex);
185 APPL_TRACE_ERROR("create_base_record: failed to create base service "
186 "record, stage: %s, scn: %d, name: %s, with_obex: %d",
187 stage, channel, name, with_obex);
191 // Registers a service with the given |name|, |uuid|, and |channel| in the SDP
192 // database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
194 static int add_sdp_by_uuid(const char *name, const uint8_t *uuid,
195 const uint16_t channel) {
196 APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name);
198 uint32_t handle = SDP_CreateRecord();
200 APPL_TRACE_ERROR("add_sdp_by_uuid: failed to create sdp record, "
201 "scn: %d, service_name: %s", channel, name);
205 // Create the base SDP record.
206 char *stage = "create_base_record";
207 if (!create_base_record(handle, name, channel, FALSE /* with_obex */))
210 // Convert the |uuid| into a big-endian representation and add it as a
212 uint8_t type = UUID_DESC_TYPE;
213 uint8_t type_len = UUID_MAX_LENGTH;
214 uint8_t type_buf[48];
215 // Store the address of type buf in a pointer on the stack, so we can pass
216 // a double pointer to SDP_AddSequence
217 uint8_t *type_buf_ptr = type_buf;
219 // Do the conversion to big-endian -- tmp is only used to iterate through the
220 // UUID array in the macro and serves no other purpose as the conversion
221 // macros are not hygenic.
223 uint8_t *tmp = type_buf;
224 ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH);
227 stage = "service_class_sequence";
228 if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST,
229 1, &type, &type_len, &type_buf_ptr))
233 APPL_TRACE_DEBUG("add_sdp_by_uuid: service registered successfully, "
234 "service_name: %s, handle: 0x%08x", name, handle);
238 SDP_DeleteRecord(handle);
239 APPL_TRACE_ERROR("add_sdp_by_uuid: failed to register service "
240 "stage: %s, service_name: %s", stage, name);
244 // Registers a service with the given |name| and |channel| in the SDP
245 // database as a PBAP protocol.
246 static int add_pbap_sdp(const char *name, const int channel) {
247 APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name);
249 uint32_t handle = SDP_CreateRecord();
251 APPL_TRACE_ERROR("add_pbap_sdp: failed to create sdp record, "
252 "service_name: %s", name);
256 // Create the base SDP record.
257 char *stage = "create_base_record";
258 if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
262 uint16_t service = UUID_SERVCLASS_PBAP_PSE;
263 stage = "service_class";
264 if (!SDP_AddServiceClassIdList(handle, 1, &service))
267 // Add in the phone access descriptor
268 stage = "profile_descriptor_list";
269 if (!SDP_AddProfileDescriptorList(handle,
270 UUID_SERVCLASS_PHONE_ACCESS,
271 BTA_PBS_DEFAULT_VERSION))
274 // Set up our supported repositories
275 stage = "supported_repositories";
276 if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
277 1, (uint8_t*)&bta_pbs_cfg.supported_repositories))
280 // Notify the system that we've got a new service class UUID.
281 bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE);
282 APPL_TRACE_DEBUG("add_pbap_sdp: service registered successfully, "
283 "service_name: %s, handle: 0x%08x", name, handle);
288 SDP_DeleteRecord(handle);
289 APPL_TRACE_ERROR("add_pbap_sdp: failed to register PBAP service, stage: %s, "
290 "service_name: %s", stage, name);
294 // Registers a service with the given |name| and |channel| in the SDP database
295 // as a MAP protocol.
296 static int add_maps_sdp(const char *name, const int channel) {
297 APPL_TRACE_DEBUG("add_maps_sdp: scn %d, service_name %s", channel,
300 uint32_t handle = SDP_CreateRecord();
302 APPL_TRACE_ERROR("add_maps_sdp: failed to create sdp record, "
303 "service_name: %s", name);
307 // Create the base SDP record.
308 char *stage = "create_base_record";
309 if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
313 uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
314 stage = "service_class";
315 if (!SDP_AddServiceClassIdList(handle, 1, &service))
318 // TODO: To add support for EMAIL set below depending on the scn to either
320 const tBTA_MAP_CFG *bta_map_cfg = &bta_map_cfg_sms;
322 // Add in the Bluetooth Profile Descriptor List
323 stage = "profile_descriptor_list";
324 if (!SDP_AddProfileDescriptorList(handle,
325 UUID_SERVCLASS_MAP_PROFILE,
326 BTA_MAP_DEFAULT_VERSION))
329 stage = "mas_instance_id";
330 if (!SDP_AddAttribute(handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
331 (uint32_t)1, (uint8_t*)(&bta_map_cfg->mas_id)))
334 stage = "support_message_types";
335 if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
337 (uint8_t*)(&bta_map_cfg->supported_message_types)))
340 // Notify the system that we've got a new service class UUID.
341 bta_sys_add_uuid(service); // UUID_SERVCLASS_MESSAGE_ACCESS
342 APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, "
343 "service_name: %s, handle 0x%08x)", name, handle);
348 SDP_DeleteRecord(handle);
349 APPL_TRACE_ERROR("add_maps_sdp: failed to register MAP service, stage: %s, "
350 "service_name: %s", stage, name);
354 // Registers a service with the given |name| and |channel| as an OBEX Push
356 static int add_ops_sdp(const char *name, const int channel) {
357 APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name);
359 uint32_t handle = SDP_CreateRecord();
361 APPL_TRACE_ERROR("add_ops_sdp: failed to create sdp record, "
362 "service_name: %s", name);
366 // Create the base SDP record.
367 char *stage = "create_base_record";
368 if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
371 // Add service class.
372 stage = "service_class";
373 uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
374 if (!SDP_AddServiceClassIdList(handle, 1, &service))
377 // Add the OBEX push profile descriptor.
378 stage = "profile_descriptor_list";
379 if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
383 // Add sequence for supported types.
384 uint8_t desc_type[OBEX_PUSH_NUM_FORMATS];
385 uint8_t type_len[OBEX_PUSH_NUM_FORMATS];
386 uint8_t *type_value[OBEX_PUSH_NUM_FORMATS];
389 for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) {
390 if ((BTUI_OPS_FORMATS >> i) & 1) {
391 type_value[j] = (uint8_t*)(&bta_ops_obj_fmt[i]);
392 desc_type[j] = UINT_DESC_TYPE;
397 stage = "supported_types";
398 if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST,
399 j, desc_type, type_len, type_value))
402 // Set class of device.
404 cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
405 stage = "class_of_device";
406 if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS))
409 // Notify the system that we've got a new service class UUID.
410 bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
411 APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, "
412 "service_name: %s, handle 0x%08x)", name, handle);
417 SDP_DeleteRecord(handle);
418 APPL_TRACE_ERROR("add_ops_sdp: failed to register OPS service, "
419 "stage: %s, service_name: %s", stage, name);
423 // Registers a service with the given |name| and |channel| as a serial port
425 static int add_spp_sdp(const char *name, const int channel) {
426 APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
428 int handle = SDP_CreateRecord();
430 APPL_TRACE_ERROR("add_spp_sdp: failed to create sdp record, "
431 "service_name: %s", name);
435 // Create the base SDP record.
436 char *stage = "create_base_record";
437 if (!create_base_record(handle, name, channel, FALSE /* with_obex */))
440 uint16_t service = UUID_SERVCLASS_SERIAL_PORT;
441 stage = "service_class";
442 if (!SDP_AddServiceClassIdList(handle, 1, &service))
445 APPL_TRACE_DEBUG("add_spp_sdp: service registered successfully, "
446 "service_name: %s, handle 0x%08x)", name, handle);
451 SDP_DeleteRecord(handle);
452 APPL_TRACE_ERROR("add_spp_sdp: failed to register SPP service, "
453 "stage: %s, service_name: %s", stage, name);
457 // Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and
458 // |channel|. This function attempts to identify the type of the service based
459 // upon its |uuid|, and will override the |channel| with a reserved channel
460 // number if the |uuid| matches one of the preregistered bluez SDP records.
461 static int add_rfc_sdp_by_uuid(const char *name, const uint8_t *uuid,
463 APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name,
467 * Bluetooth Socket API relies on having preregistered bluez sdp records for
468 * HSAG, HFAG, OPP & PBAP that are mapped to rc chan 10, 11,12 & 19. Today
469 * HSAG and HFAG is routed to BRCM AG and are not using BT socket API so for
470 * now we will need to support OPP and PBAP to enable 3rd party developer apps
471 * running on BRCM Android.
473 * To do this we will check the UUID for the requested service and mimic the
474 * SDP records of bluez upon reception. See functions add_opush() and
475 * add_pbap() in sdptool.c for actual records.
478 int final_channel = get_reserved_rfc_channel(uuid);
480 if (final_channel == -1) {
481 final_channel = channel;
486 if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
487 handle = add_ops_sdp(name, final_channel);
488 } else if (UUID_MATCHES(UUID_PBAP_PSE,uuid)) {
489 // PBAP Server is always channel 19
490 handle = add_pbap_sdp(name, final_channel);
491 } else if (UUID_MATCHES(UUID_SPP, uuid)) {
492 handle = add_spp_sdp(name, final_channel);
493 } else if (UUID_MATCHES(UUID_MAPS_MAS,uuid)) {
494 // MAP Server is always channel 19
495 handle = add_maps_sdp(name, final_channel);
497 handle = add_sdp_by_uuid(name, uuid, final_channel);
503 bool is_reserved_rfc_channel(const int channel) {
505 case RESERVED_SCN_PBS:
506 case RESERVED_SCN_OPS:
513 int get_reserved_rfc_channel(const uint8_t *uuid) {
514 if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
515 return RESERVED_SCN_PBS;
516 } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
517 return RESERVED_SCN_OPS;
523 // Adds an SDP record to the SDP database using the given |name|, |uuid|, and
524 // |channel|. Note that if the |uuid| is empty, the |uuid| will be set based
525 // upon the |channel| passed in.
526 int add_rfc_sdp_rec(const char *name, const uint8_t *uuid, const int channel) {
527 if (is_uuid_empty(uuid)) {
529 case RESERVED_SCN_PBS: // PBAP Reserved port
530 uuid = UUID_PBAP_PSE;
533 case RESERVED_SCN_OPS:
534 uuid = UUID_OBEX_OBJECT_PUSH;
543 return add_rfc_sdp_by_uuid(name, uuid, channel);
546 // Deletes an SDP record with the given |handle|.
547 void del_rfc_sdp_rec(int handle) {
548 APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle);
550 if ((handle != -1) && (handle != 0))
551 BTA_JvDeleteRecord(handle);