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
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,
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.
create_base_record(const uint32_t sdp_handle,const char * name,const uint16_t channel,const bool with_obex)111 static 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
157 error:
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.
add_sdp_by_uuid(const char * name,const uint8_t * uuid,const uint16_t channel)167 static 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
210 error:
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.
add_pbap_sdp(const char * name,const int channel)219 static 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
260 error:
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.
add_ops_sdp(const char * name,const int channel)268 static 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
328 error:
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.
add_spp_sdp(const char * name,const int channel)337 static 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
362 error:
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.
add_rfc_sdp_by_uuid(const char * name,const uint8_t * uuid,const int channel)373 static 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
is_reserved_rfc_channel(const int channel)415 bool 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
get_reserved_rfc_channel(const uint8_t * uuid)425 int 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.
add_rfc_sdp_rec(const char * name,const uint8_t * uuid,const int channel)438 int 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|.
del_rfc_sdp_rec(int handle)459 void 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