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