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