OSDN Git Service

Refactoring btif_sock_sdp.c for clarity
[android-x86/system-bt.git] / btif / src / btif_sock_sdp.c
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 "BTIF_SOCK_SDP"
20
21 #include <hardware/bluetooth.h>
22 #include <hardware/bt_sock.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <errno.h>
26 #include <cutils/log.h>
27
28 #include "btif_common.h"
29 #include "btif_util.h"
30 #include "bd.h"
31 #include "bta_api.h"
32 #include "bt_target.h"
33 #include "gki.h"
34 #include "hcimsgs.h"
35 #include "sdp_api.h"
36 #include "btu.h"
37 #include "btm_api.h"
38 #include "btm_int.h"
39 #include "btif_sock_sdp.h"
40 #include "utl.h"
41 #include "../bta/pb/bta_pbs_int.h"
42 #include "../include/bta_op_api.h"
43 #include "bta_jv_api.h"
44
45 // This module provides an abstraction on top of the lower-level SDP database
46 // code for registration and discovery of various bluetooth sockets.
47 //
48 // This code also provides for on-demand registration of "pre-registered"
49 // services as a backwards compatibility function to third-party applications
50 // expecting a bluez stack.
51
52 // Realm Character Set -- 0 is ASCII
53 #define BTA_PBS_REALM_CHARSET 0
54
55 // Specifies whether or not client's user id is required during obex
56 // authentication
57 #define BTA_PBS_USERID_REQ FALSE
58
59 // TODO(jtgans): Is this really exported to anything anywhere? If so, we should
60 // stuff it into the header, otherwise, WHY IS IT HERE?!
61 extern const tBTA_PBS_CFG bta_pbs_cfg;
62
63 const tBTA_PBS_CFG bta_pbs_cfg = {
64   BTA_PBS_REALM_CHARSET,                          // realm_charset: Server only
65   BTA_PBS_USERID_REQ,                             // userid_req: Server only
66   (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),  // supported_features
67   BTA_PBS_REPOSIT_LOCAL,                          // supported_repositories
68 };
69
70 // object format lookup table
71 #define OBEX_PUSH_NUM_FORMATS 7
72
73 static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
74   BTA_OP_VCARD21_FMT,
75   BTA_OP_VCARD30_FMT,
76   BTA_OP_VCAL_FMT,
77   BTA_OP_ICAL_FMT,
78   BTA_OP_VNOTE_FMT,
79   BTA_OP_VMSG_FMT,
80   BTA_OP_OTHER_FMT
81 };
82
83 // TODO(jtgans): Figure out if we actually need this define. This is ifndef
84 // defined in bt_target.h, but nowhere else, so right now, unless something
85 // overrides this before bt_target.h sets it, it will always be bt_target.h's
86 // version.
87 #ifndef BTUI_OPS_FORMATS
88 #define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK   \
89                           | BTA_OP_VCARD30_MASK \
90                           | BTA_OP_VCAL_MASK    \
91                           | BTA_OP_ICAL_MASK    \
92                           | BTA_OP_VNOTE_MASK   \
93                           | BTA_OP_VMSG_MASK    \
94                           | BTA_OP_ANY_MASK)
95 #endif
96
97 /*
98  * This is horrible design - to reserve channel ID's and use them to magically
99  * link a channel number to a hard coded SDP entry.
100  *
101  * TODO: expose a prober SDP API, to avoid hacks like this, and make it possible
102  * to set useful names for the ServiceName
103  */
104 #define BTA_MAP_MSG_TYPE_EMAIL    0x01
105 #define BTA_MAP_MSG_TYPE_SMS_GSM  0x02
106 #define BTA_MAP_MSG_TYPE_SMS_CDMA 0x04
107 #define BTA_MAP_MSG_TYPE_MMS      0x08
108
109 #define BTA_MAP_MAS_ID_SMSMMS 0
110 #define BTA_MAP_MAS_ID_EMAIL 1
111
112 // MAP 1.1
113 #define BTA_MAP_DEFAULT_VERSION 0x0101
114
115 typedef struct {
116   UINT8 mas_id;                  // the MAS instance id
117   const char *service_name;      // Description of the MAS instance
118   UINT8 supported_message_types; // Server supported message types - SMS/MMS/EMAIL
119 } tBTA_MAP_CFG;
120
121 const tBTA_MAP_CFG bta_map_cfg_sms = {
122   BTA_MAP_MAS_ID_SMSMMS,
123   "MAP SMS",
124   BTA_MAP_MSG_TYPE_SMS_GSM | BTA_MAP_MSG_TYPE_SMS_CDMA
125 };
126
127 #define RESERVED_SCN_PBS 19
128 #define RESERVED_SCN_OPS 12
129
130 #define UUID_MAX_LENGTH 16
131 #define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
132
133 // Adds a protocol list and service name (if provided) to an SDP record given by
134 // |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
135 // set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If
136 // |with_obex| is |TRUE|, then an additional OBEX protocol UUID will be included
137 // at the end of the protocol list.
138 //
139 // Returns TRUE if successful, otherwise FALSE.
140 static BOOLEAN create_base_record(const UINT32 sdp_handle, const char *name,
141                                   const UINT16 channel, const BOOLEAN with_obex) {
142   APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
143                    channel, name, with_obex);
144
145   // Setup the protocol list and add it.
146   tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
147   int num_proto_elements = with_obex ? 3 : 2;
148
149   memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
150
151   proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
152   proto_list[0].num_params = 0;
153   proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
154   proto_list[1].num_params = 1;
155   proto_list[1].params[0] = channel;
156
157   if (with_obex == TRUE) {
158     proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
159     proto_list[2].num_params = 0;
160   }
161
162   char *stage = "protocol_list";
163   if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list))
164     goto error;
165
166   // Add the name to the SDP record.
167   if (name[0] != '\0') {
168     stage = "service_name";
169     if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME,
170                           TEXT_STR_DESC_TYPE, (UINT32)(strlen(name) + 1),
171                           (UINT8 *)name))
172       goto error;
173   }
174
175   // Mark the service as browseable.
176   UINT16 list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
177   stage = "browseable";
178   if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list))
179     goto error;
180
181   APPL_TRACE_DEBUG("create_base_record: successfully created base service "
182                    "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
183                    sdp_handle, channel, name, with_obex);
184   return TRUE;
185
186 error:
187   APPL_TRACE_ERROR("create_base_record: failed to create base service "
188                    "record, stage: %s, scn: %d, name: %s, with_obex: %d",
189                    stage, channel, name, with_obex);
190   return FALSE;
191 }
192
193 // Registers a service with the given |name|, |uuid|, and |channel| in the SDP
194 // database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
195 // class sequence.
196 static int add_sdp_by_uuid(const char *name,  const uint8_t *uuid,
197                            const UINT16 channel) {
198   APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name);
199
200   UINT32 handle = SDP_CreateRecord();
201   if (handle == 0) {
202     APPL_TRACE_ERROR("add_sdp_by_uuid: failed to create sdp record, "
203                      "scn: %d, service_name: %s", channel, name);
204     return 0;
205   }
206
207   // Create the base SDP record.
208   char *stage = "create_base_record";
209   if (!create_base_record(handle, name, channel, FALSE /* with_obex */))
210     goto error;
211
212   // Convert the |uuid| into a big-endian representation and add it as a
213   // sequence.
214   UINT8 type = UUID_DESC_TYPE;
215   UINT8 type_len = UUID_MAX_LENGTH;
216   UINT8 type_buf[48];
217
218   // Do the conversion to big-endian -- tmp is only used to iterate through the
219   // UUID array in the macro and serves no other purpose as the conversion
220   // macros are not hygenic.
221   {
222     UINT8 *tmp = type_buf;
223     ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH);
224   }
225
226   stage = "service_class_sequence";
227   if (!SDP_AddSequence(handle, (UINT16)ATTR_ID_SERVICE_CLASS_ID_LIST,
228                        1, &type, &type_len, (UINT8**)&type_buf))
229     goto error;
230
231
232   APPL_TRACE_DEBUG("add_sdp_by_uuid: service registered successfully, "
233                    "service_name: %s, handle: 0x%08x", name, handle);
234   return handle;
235
236 error:
237   SDP_DeleteRecord(handle);
238   APPL_TRACE_ERROR("add_sdp_by_uuid: failed to register service "
239                    "stage: %s, service_name: %s", stage, name);
240   return 0;
241 }
242
243 // Registers a service with the given |name| and |channel| in the SDP
244 // database as a PBAP protocol.
245 static int add_pbap_sdp(const char *name, const int channel) {
246   APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name);
247
248   UINT32 handle = SDP_CreateRecord();
249   if (handle == 0) {
250     APPL_TRACE_ERROR("add_pbap_sdp: failed to create sdp record, "
251                      "service_name: %s", name);
252     return 0;
253   }
254
255   // Create the base SDP record.
256   char *stage = "create_base_record";
257   if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
258     goto error;
259
260   // Add service class
261   UINT16 service = UUID_SERVCLASS_PBAP_PSE;
262   stage = "service_class";
263   if (!SDP_AddServiceClassIdList(handle, 1, &service))
264     goto error;
265
266   // Add in the phone access descriptor
267   stage = "profile_descriptor_list";
268   if (!SDP_AddProfileDescriptorList(handle,
269                                     UUID_SERVCLASS_PHONE_ACCESS,
270                                     BTA_PBS_DEFAULT_VERSION))
271     goto error;
272
273   // Set up our supported repositories
274   stage = "supported_repositories";
275   if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
276                         1, (UINT8*)&bta_pbs_cfg.supported_repositories))
277     goto error;
278
279   // Notify the system that we've got a new service class UUID.
280   bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE);
281   APPL_TRACE_DEBUG("add_pbap_sdp: service registered successfully, "
282                    "service_name: %s, handle: 0x%08x", name, handle);
283
284   return handle;
285
286 error:
287   SDP_DeleteRecord(handle);
288   APPL_TRACE_ERROR("add_pbap_sdp: failed to register PBAP service, stage: %s, "
289                    "service_name: %s", stage, name);
290   return 0;
291 }
292
293 // Registers a service with the given |name| and |channel| in the SDP database
294 // as a MAP protocol.
295 static int add_maps_sdp(const char *name, const int channel) {
296   APPL_TRACE_DEBUG("add_maps_sdp: scn %d, service_name %s", channel,
297                    name);
298
299   UINT32 handle = SDP_CreateRecord();
300   if (handle == 0) {
301     APPL_TRACE_ERROR("add_maps_sdp: failed to create sdp record, "
302                      "service_name: %s", name);
303     return 0;
304   }
305
306   // Create the base SDP record.
307   char *stage = "create_base_record";
308   if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
309     goto error;
310
311   // add service class
312   UINT16 service = UUID_SERVCLASS_MESSAGE_ACCESS;
313   stage = "service_class";
314   if (!SDP_AddServiceClassIdList(handle, 1, &service))
315     goto error;
316
317   // TODO: To add support for EMAIL set below depending on the scn to either
318   // SMS or Email
319   const tBTA_MAP_CFG *bta_map_cfg = &bta_map_cfg_sms;
320
321   // Add in the Bluetooth Profile Descriptor List
322   stage = "profile_descriptor_list";
323   if (!SDP_AddProfileDescriptorList(handle,
324                                     UUID_SERVCLASS_MAP_PROFILE,
325                                     BTA_MAP_DEFAULT_VERSION))
326     goto error;
327
328   stage = "mas_instance_id";
329   if (!SDP_AddAttribute(handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
330                         (UINT32)1, (UINT8*)(&bta_map_cfg->mas_id)))
331     goto error;
332
333   stage = "support_message_types";
334   if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
335                         (UINT32)1,
336                         (UINT8*)(&bta_map_cfg->supported_message_types)))
337     goto error;
338
339   // Notify the system that we've got a new service class UUID.
340   bta_sys_add_uuid(service);  // UUID_SERVCLASS_MESSAGE_ACCESS
341   APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, "
342                    "service_name: %s, handle 0x%08x)", name, handle);
343
344   return handle;
345
346 error:
347   SDP_DeleteRecord(handle);
348   APPL_TRACE_ERROR("add_maps_sdp: failed to register MAP service, stage: %s, "
349                    "service_name: %s", stage, name);
350   return 0;
351 }
352
353 // Registers a service with the given |name| and |channel| as an OBEX Push
354 // protocol.
355 static int add_ops_sdp(const char *name, const int channel) {
356   APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name);
357
358   UINT32 handle = SDP_CreateRecord();
359   if (handle == 0) {
360     APPL_TRACE_ERROR("add_ops_sdp: failed to create sdp record, "
361                      "service_name: %s", name);
362     return 0;
363   }
364
365   // Create the base SDP record.
366   char *stage = "create_base_record";
367   if (!create_base_record(handle, name, channel, TRUE /* with_obex */))
368     goto error;
369
370   // Add service class.
371   stage = "service_class";
372   UINT16 service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
373   if (!SDP_AddServiceClassIdList(handle, 1, &service))
374     goto error;
375
376   // Add the OBEX push profile descriptor.
377   stage = "profile_descriptor_list";
378   if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
379                                     0x0100))
380     goto error;
381
382   // Add sequence for supported types.
383   UINT8 desc_type[OBEX_PUSH_NUM_FORMATS];
384   UINT8 type_len[OBEX_PUSH_NUM_FORMATS];
385   UINT8 *type_value[OBEX_PUSH_NUM_FORMATS];
386   UINT8 j = 0;
387
388   for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) {
389     if ((BTUI_OPS_FORMATS >> i) & 1) {
390       type_value[j] = (UINT8*)(&bta_ops_obj_fmt[i]);
391       desc_type[j] = UINT_DESC_TYPE;
392       type_len[j++] = 1;
393     }
394   }
395
396   stage = "supported_types";
397   if (!SDP_AddSequence(handle, (UINT16)ATTR_ID_SUPPORTED_FORMATS_LIST,
398                        j, desc_type, type_len, type_value))
399     goto error;
400
401   // Set class of device.
402   tBTA_UTL_COD cod;
403   cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
404   stage = "class_of_device";
405   if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS))
406     goto error;
407
408   // Notify the system that we've got a new service class UUID.
409   bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
410   APPL_TRACE_DEBUG("ad_maps_sdp: service registered successfully, "
411                    "service_name: %s, handle 0x%08x)", name, handle);
412
413   return handle;
414
415 error:
416   SDP_DeleteRecord(handle);
417   APPL_TRACE_ERROR("add_ops_sdp: failed to register OPS service, "
418                    "stage: %s, service_name: %s", stage, name);
419   return 0;
420 }
421
422 // Registers a service with the given |name| and |channel| as a serial port
423 // profile protocol.
424 static int add_spp_sdp(const char *name, const int channel) {
425   APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
426
427   int handle = SDP_CreateRecord();
428   if (handle == 0) {
429     APPL_TRACE_ERROR("add_spp_sdp: failed to create sdp record, "
430                      "service_name: %s", name);
431     return 0;
432   }
433
434   // Create the base SDP record.
435   char *stage = "create_base_record";
436   if (!create_base_record(handle, name, channel, FALSE /* with_obex */))
437     goto error;
438
439   UINT16 service = UUID_SERVCLASS_SERIAL_PORT;
440   stage = "service_class";
441   if (!SDP_AddServiceClassIdList(handle, 1, &service))
442     goto error;
443
444   APPL_TRACE_DEBUG("add_spp_sdp: service registered successfully, "
445                    "service_name: %s, handle 0x%08x)", name, handle);
446
447   return handle;
448
449 error:
450   SDP_DeleteRecord(handle);
451   APPL_TRACE_ERROR("add_spp_sdp: failed to register SPP service, "
452                    "stage: %s, service_name: %s", stage, name);
453   return 0;
454 }
455
456 // Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and
457 // |channel|. This function attempts to identify the type of the service based
458 // upon its |uuid|, and will override the |channel| with a reserved channel
459 // number if the |uuid| matches one of the preregistered bluez SDP records.
460 static int add_rfc_sdp_by_uuid(const char *name, const uint8_t *uuid,
461                                const int channel) {
462   APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name,
463                    channel);
464
465   /*
466    * Bluetooth Socket API relies on having preregistered bluez sdp records for
467    * HSAG, HFAG, OPP & PBAP that are mapped to rc chan 10, 11,12 & 19. Today
468    * HSAG and HFAG is routed to BRCM AG and are not using BT socket API so for
469    * now we will need to support OPP and PBAP to enable 3rd party developer apps
470    * running on BRCM Android.
471    *
472    * To do this we will check the UUID for the requested service and mimic the
473    * SDP records of bluez upon reception.  See functions add_opush() and
474    * add_pbap() in sdptool.c for actual records.
475    */
476
477   int final_channel = get_reserved_rfc_channel(uuid);
478
479   if (final_channel == -1) {
480     final_channel = channel;
481   }
482
483   int handle = 0;
484
485   if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
486     handle = add_ops_sdp(name, final_channel);
487   } else if (UUID_MATCHES(UUID_PBAP_PSE,uuid)) {
488     // PBAP Server is always channel 19
489     handle = add_pbap_sdp(name, final_channel);
490   } else if (UUID_MATCHES(UUID_SPP, uuid)) {
491     handle = add_spp_sdp(name, final_channel);
492   } else if (UUID_MATCHES(UUID_MAPS_MAS,uuid)) {
493     // MAP Server is always channel 19
494     handle = add_maps_sdp(name, final_channel);
495   } else {
496     handle = add_sdp_by_uuid(name, uuid, final_channel);
497   }
498
499   return handle;
500 }
501
502 BOOLEAN is_reserved_rfc_channel(const int channel) {
503   switch(channel) {
504     case RESERVED_SCN_PBS:
505     case RESERVED_SCN_OPS:
506       return TRUE;
507   }
508
509   return FALSE;
510 }
511
512 int get_reserved_rfc_channel(const uint8_t *uuid) {
513   if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
514     return RESERVED_SCN_PBS;
515   } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
516     return RESERVED_SCN_OPS;
517   }
518
519   return -1;
520 }
521
522 // Adds an SDP record to the SDP database using the given |name|, |uuid|, and
523 // |channel|. Note that if the |uuid| is empty, the |uuid| will be set based
524 // upon the |channel| passed in.
525 int add_rfc_sdp_rec(const char *name, const uint8_t *uuid, const int channel) {
526   if (is_uuid_empty(uuid)) {
527     switch(channel) {
528       case RESERVED_SCN_PBS: // PBAP Reserved port
529         uuid = UUID_PBAP_PSE;
530         break;
531
532       case RESERVED_SCN_OPS:
533         uuid = UUID_OBEX_OBJECT_PUSH;
534         break;
535
536       default:
537         uuid = UUID_SPP;
538         break;
539     }
540   }
541
542   return add_rfc_sdp_by_uuid(name, uuid, channel);
543 }
544
545 // Deletes an SDP record with the given |handle|.
546 void del_rfc_sdp_rec(int handle) {
547   APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle);
548
549   if ((handle != -1) && (handle != 0))
550     BTA_JvDeleteRecord(handle);
551 }