• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bt_target.h"  // Must be first to define build configuration
22 
23 #include "bta/include/bta_jv_api.h"
24 #include "bta/include/bta_op_api.h"
25 #include "bta/include/utl.h"
26 #include "bta/pb/bta_pbs_int.h"
27 #include "bta/sys/bta_sys.h"
28 #include "btif/include/btif_sock_sdp.h"
29 #include "stack/include/sdp_api.h"
30 #include "stack/include/sdpdefs.h"
31 #include "types/bluetooth/uuid.h"
32 
33 using bluetooth::Uuid;
34 
35 // This module provides an abstraction on top of the lower-level SDP database
36 // code for registration and discovery of various bluetooth sockets.
37 //
38 // This code also provides for on-demand registration of "pre-registered"
39 // services as a backwards compatibility function to third-party applications
40 // expecting a bluez stack.
41 
42 // Realm Character Set -- 0 is ASCII
43 #define BTA_PBS_REALM_CHARSET 0
44 
45 // Specifies whether or not client's user id is required during obex
46 // authentication
47 #define BTA_PBS_USERID_REQ FALSE
48 
49 static const tBTA_PBS_CFG bta_pbs_cfg = {
50     BTA_PBS_REALM_CHARSET,  // realm_charset: Server only
51     BTA_PBS_USERID_REQ,     // userid_req: Server only
52     (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),  // supported_features
53     BTA_PBS_REPOSIT_LOCAL,                          // supported_repositories
54 };
55 
56 // object format lookup table
57 #define OBEX_PUSH_NUM_FORMATS 7
58 
59 static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
60     BTA_OP_VCARD21_FMT, BTA_OP_VCARD30_FMT, BTA_OP_VCAL_FMT, BTA_OP_ICAL_FMT,
61     BTA_OP_VNOTE_FMT,   BTA_OP_VMSG_FMT,    BTA_OP_OTHER_FMT};
62 
63 // TODO(jtgans): Figure out if we actually need this define. This is ifndef
64 // defined in bt_target.h, but nowhere else, so right now, unless something
65 // overrides this before bt_target.h sets it, it will always be bt_target.h's
66 // version.
67 #ifndef BTUI_OPS_FORMATS
68 #define BTUI_OPS_FORMATS                                          \
69   (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | BTA_OP_VCAL_MASK | \
70    BTA_OP_ICAL_MASK | BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | BTA_OP_ANY_MASK)
71 #endif
72 
73 #define RESERVED_SCN_PBS 19
74 #define RESERVED_SCN_OPS 12
75 
76 #define UUID_MAX_LENGTH 16
77 
78 #define SPP_PROFILE_VERSION 0x0102
79 
80 // Adds a protocol list and service name (if provided) to an SDP record given by
81 // |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
82 // set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If
83 // |with_obex| is |true|, then an additional OBEX protocol UUID will be included
84 // at the end of the protocol list.
85 //
86 // 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)87 static bool create_base_record(const uint32_t sdp_handle, const char* name,
88                                const uint16_t channel, const bool with_obex) {
89   APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
90                    channel, name, with_obex);
91 
92   // Setup the protocol list and add it.
93   tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
94   int num_proto_elements = with_obex ? 3 : 2;
95 
96   memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
97 
98   proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
99   proto_list[0].num_params = 0;
100   proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
101   proto_list[1].num_params = 1;
102   proto_list[1].params[0] = channel;
103 
104   if (with_obex) {
105     proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
106     proto_list[2].num_params = 0;
107   }
108 
109   // Mark the service as browseable.
110   uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
111 
112   const char* stage = "protocol_list";
113   if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list))
114     goto error;
115 
116   // Add the name to the SDP record.
117   if (name[0] != '\0') {
118     stage = "service_name";
119     if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
120                           (uint32_t)strlen(name), (uint8_t*)name))
121       goto error;
122   }
123 
124   stage = "browseable";
125   if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list))
126     goto error;
127 
128   APPL_TRACE_DEBUG(
129       "create_base_record: successfully created base service "
130       "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
131       sdp_handle, channel, name, with_obex);
132   return true;
133 
134 error:
135   APPL_TRACE_ERROR(
136       "create_base_record: failed to create base service "
137       "record, stage: %s, scn: %d, name: %s, with_obex: %d",
138       stage, channel, name, with_obex);
139   return false;
140 }
141 
142 // Registers a service with the given |name|, |uuid|, and |channel| in the SDP
143 // database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
144 // class sequence.
add_sdp_by_uuid(const char * name,const Uuid & uuid,const uint16_t channel)145 static int add_sdp_by_uuid(const char* name, const Uuid& uuid,
146                            const uint16_t channel) {
147   APPL_TRACE_DEBUG("%s: uuid: %s, scn: %d, service_name: %s", __func__,
148                    uuid.ToString().c_str(), channel, name);
149 
150   uint32_t handle = SDP_CreateRecord();
151   if (handle == 0) {
152     APPL_TRACE_ERROR(
153         "%s: failed to create sdp record, scn: %d, service_name: %s", __func__,
154         channel, name);
155     return 0;
156   }
157 
158   // Convert the |uuid| into a big-endian representation and add it as a
159   // sequence.
160   uint8_t type = UUID_DESC_TYPE;
161   uint8_t type_len = UUID_MAX_LENGTH;
162   uint8_t type_buf[48];
163   // Store the address of type buf in a pointer on the stack, so we can pass
164   // a double pointer to SDP_AddSequence
165   uint8_t* type_buf_ptr = type_buf;
166   uint8_t* tmp = type_buf;
167 
168   // Create the base SDP record.
169   const char* stage = "create_base_record";
170   if (!create_base_record(handle, name, channel, false /* with_obex */))
171     goto error;
172 
173   // Do the conversion to big-endian -- tmp is only used to iterate through the
174   // UUID array in the macro and serves no other purpose as the conversion
175   // macros are not hygenic.
176 
177   { ARRAY_TO_BE_STREAM(tmp, uuid.To128BitBE().data(), UUID_MAX_LENGTH); }
178 
179   stage = "service_class_sequence";
180   if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST, 1,
181                        &type, &type_len, &type_buf_ptr))
182     goto error;
183 
184   APPL_TRACE_DEBUG(
185       "%s: service registered successfully, service_name: %s, handle: 0x%08x",
186       __func__, name, handle);
187 
188   {
189     // Write the custom 128-bit UUID to EIR
190     tBTA_CUSTOM_UUID curr = {uuid, handle};
191     bta_sys_add_cust_uuid(curr);
192   }
193 
194   return handle;
195 
196 error:
197   SDP_DeleteRecord(handle);
198   APPL_TRACE_ERROR("%s: failed to register service stage: %s, service_name: %s",
199                    __func__, stage, name);
200   return 0;
201 }
202 
203 // Registers a service with the given |name| and |channel| in the SDP
204 // database as a PBAP protocol.
add_pbap_sdp(const char * name,const int channel)205 static int add_pbap_sdp(const char* name, const int channel) {
206   APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name);
207 
208   uint32_t handle = SDP_CreateRecord();
209   if (handle == 0) {
210     APPL_TRACE_ERROR(
211         "add_pbap_sdp: failed to create sdp record, "
212         "service_name: %s",
213         name);
214     return 0;
215   }
216 
217   uint16_t service = UUID_SERVCLASS_PBAP_PSE;
218 
219   // Create the base SDP record.
220   const char* stage = "create_base_record";
221   if (!create_base_record(handle, name, channel, true /* with_obex */))
222     goto error;
223 
224   // Add service class
225   stage = "service_class";
226   if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
227 
228   // Add in the phone access descriptor
229   stage = "profile_descriptor_list";
230   if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_PHONE_ACCESS,
231                                     BTA_PBS_DEFAULT_VERSION))
232     goto error;
233 
234   // Set up our supported repositories
235   stage = "supported_repositories";
236   if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
237                         1, (uint8_t*)&bta_pbs_cfg.supported_repositories))
238     goto error;
239 
240   // Notify the system that we've got a new service class UUID.
241   bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE);
242   APPL_TRACE_DEBUG(
243       "add_pbap_sdp: service registered successfully, "
244       "service_name: %s, handle: 0x%08x",
245       name, handle);
246 
247   return handle;
248 
249 error:
250   SDP_DeleteRecord(handle);
251   APPL_TRACE_ERROR(
252       "add_pbap_sdp: failed to register PBAP service, stage: %s, "
253       "service_name: %s",
254       stage, name);
255   return 0;
256 }
257 // Registers a service with the given |name| and |channel| as an OBEX Push
258 // protocol.
add_ops_sdp(const char * name,const int channel)259 static int add_ops_sdp(const char* name, const int channel) {
260   APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name);
261 
262   uint32_t handle = SDP_CreateRecord();
263   if (handle == 0) {
264     APPL_TRACE_ERROR(
265         "add_ops_sdp: failed to create sdp record, "
266         "service_name: %s",
267         name);
268     return 0;
269   }
270 
271   // Add sequence for supported types.
272   uint8_t desc_type[OBEX_PUSH_NUM_FORMATS];
273   uint8_t type_len[OBEX_PUSH_NUM_FORMATS];
274   uint8_t* type_value[OBEX_PUSH_NUM_FORMATS];
275   uint8_t j = 0;
276 
277   uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
278   tBTA_UTL_COD cod;
279 
280   // Create the base SDP record.
281   const char* stage = "create_base_record";
282   if (!create_base_record(handle, name, channel, true /* with_obex */))
283     goto error;
284 
285   // Add service class.
286   stage = "service_class";
287   if (!SDP_AddServiceClassIdList(handle, 1, &service)) 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   for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) {
296     if ((BTUI_OPS_FORMATS >> i) & 1) {
297       type_value[j] = (uint8_t*)(&bta_ops_obj_fmt[i]);
298       desc_type[j] = UINT_DESC_TYPE;
299       type_len[j++] = 1;
300     }
301   }
302 
303   stage = "supported_types";
304   if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST, j,
305                        desc_type, type_len, type_value))
306     goto error;
307 
308   // Set class of device.
309   cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
310   stage = "class_of_device";
311   if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS)) goto error;
312 
313   // Notify the system that we've got a new service class UUID.
314   bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
315   APPL_TRACE_DEBUG(
316       "ad_maps_sdp: service registered successfully, "
317       "service_name: %s, handle 0x%08x)",
318       name, handle);
319 
320   return handle;
321 
322 error:
323   SDP_DeleteRecord(handle);
324   APPL_TRACE_ERROR(
325       "add_ops_sdp: failed to register OPS service, "
326       "stage: %s, service_name: %s",
327       stage, name);
328   return 0;
329 }
330 
331 // Registers a service with the given |name| and |channel| as a serial port
332 // profile protocol.
add_spp_sdp(const char * name,const int channel)333 static int add_spp_sdp(const char* name, const int channel) {
334   APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
335 
336   int handle = SDP_CreateRecord();
337   if (handle == 0) {
338     APPL_TRACE_ERROR(
339         "add_spp_sdp: failed to create sdp record, "
340         "service_name: %s",
341         name);
342     return 0;
343   }
344 
345   // Create the base SDP record.
346   const char* stage = "create_base_record";
347   uint16_t service = UUID_SERVCLASS_SERIAL_PORT;
348 
349   if (!create_base_record(handle, name, channel, false /* with_obex */))
350     goto error;
351 
352   stage = "service_class";
353   if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
354 
355   stage = "profile_descriptor_list";
356   if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_SERIAL_PORT,
357                                     SPP_PROFILE_VERSION))
358     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 Uuid & uuid,const int channel)380 static int add_rfc_sdp_by_uuid(const char* name, const Uuid& uuid,
381                                const int channel) {
382   APPL_TRACE_DEBUG("%s: uuid: %s, service_name: %s, channel: %d", __func__,
383                    uuid.ToString().c_str(), name, 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 == UUID_OBEX_OBJECT_PUSH) {
406     handle = add_ops_sdp(name, final_channel);
407   } else if (uuid == UUID_PBAP_PSE) {
408     // PBAP Server is always channel 19
409     handle = add_pbap_sdp(name, final_channel);
410   } else if (uuid == UUID_SPP) {
411     handle = add_spp_sdp(name, final_channel);
412   } else if (uuid == UUID_MAP_MAS) {
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 bluetooth::Uuid & uuid)432 int get_reserved_rfc_channel(const bluetooth::Uuid& uuid) {
433   if (uuid == UUID_PBAP_PSE) {
434     return RESERVED_SCN_PBS;
435   } else if (uuid == UUID_OBEX_OBJECT_PUSH) {
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,Uuid uuid,const int channel)445 int add_rfc_sdp_rec(const char* name, Uuid uuid, const int channel) {
446   if (uuid.IsEmpty()) {
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)) {
470     // Remove the custom 128-bit UUID from EIR
471     const tBTA_CUSTOM_UUID curr = {Uuid::kEmpty, (uint32_t)handle};
472     bta_sys_remove_cust_uuid(curr);
473 
474     BTA_JvDeleteRecord(handle);
475   }
476 }
477