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